web-dev-qa-db-ja.com

シグナルハンドラーへの引数の提供/受け渡し

シグナルハンドラに引数を指定/渡すことはできますか?

/* Signal handling */
struct sigaction act;
act.sa_handler = signal_handler;
/* some more settings */

ハンドラーは次のようになります。

void signal_handler(int signo) {
    /* some code */
}

特別なこと、つまり一時ファイルを削除したい場合、これらのファイルをこのハンドラーの引数として提供できますか?

編集0:答えてくれてありがとう。通常、グローバル変数の使用を回避/抑制します。そして、この場合、巨大なプログラムを持っていると、さまざまな場所で問題が発生する可能性があり、多くのクリーンアップが必要になる場合があります。 APIがこのように設計されたのはなぜですか?

54
hari

独自のデータをパラメーターとしてシグナルハンドラーに渡すことはできません。代わりに、パラメーターをグローバル変数に保存する必要があります。 (そして、シグナルハンドラをインストールした後にchangeこれらのデータが必要になった場合は、本当に注意してください)。

編集0への応答:歴史的理由。信号は非常に古く、非常に低レベルの設計です。基本的には、いくつかのマシンコードへの単一のアドレスをカーネルに与え、そのような場合にこの特定のアドレスにアクセスするように要求します。ここで、「ポータブルアセンブラー」の考え方に戻ります。カーネルは飾り気のないベースラインサービスを提供し、ユーザープロセスがそれ自体に対して合理的に期待できるものは何でも、それ自体を実行する必要があります。

また、グローバル変数に対する通常の引数は、ここでは実際には適用されません。シグナルハンドラーそれ自体はグローバル設定であるため、ユーザー指定パラメーターのいくつかの異なるセットを使用する可能性はありません。 (まあ、実際には完全にグローバルではなく、スレッドのみです。しかし、スレッドAPIにはスレッドローカルストレージのメカニズムが含まれます。これはこの場合に必要なものです)。

52
Henning Makholm

シグナルハンドラの登録は、既にグローバルな状態グローバル変数と同等です。そのため、グローバル変数を使用して引数を渡すことは大きな問題ではありません。しかし、とにかくシグナルハンドラから何かをすることは大きな間違いです(ほとんど間違いなく未定義の動作あなたが専門家でない限り!)。代わりに、シグナルをブロックしてメインプログラムループからポーリングするだけで、これらの問題をすべて回避できます。

16
R..

これは本当に古い質問ですが、私はあなたの問題に答えたであろう素敵なトリックをお見せできると思います。 sigqueueなどを使用する必要はありません。

また、グローバル変数の使用が嫌いなので、私の場合、void ptr(後で必要に応じてキャストできます)を送信するための賢い方法を見つける必要がありました。

実際にこれを行うことができます:

signal(SIGWHATEVER, (void (*)(int))sighandler); // Yes it works ! Even with -Wall -Wextra -Werror using gcc

すると、sighandlerは次のようになります。

int sighandler(const int signal, void *ptr) // Actually void can be replaced with anything you want , MAGIC !

あなたは尋ねるかもしれません:* ptrを取得する方法?

方法は次のとおりです。初期化時

signal(SIGWHATEVER, (void (*)(int))sighandler)
sighandler(FAKE_SIGNAL, your_ptr);

あなたのsighandler funcで

int sighandler(const int signal, void *ptr)
{
  static my_struct saved = NULL;

  if (saved == NULL)
     saved = ptr;
  if (signal == SIGNALWHATEVER)
     // DO YOUR STUFF OR FREE YOUR PTR
   return (0);
}
5
rak007

絶対に。通常のkill()の代わりにsigqueue()を使用して、整数とポインターをシグナルハンドラーに渡すことができます。

http://man7.org/linux/man-pages/man2/sigqueue.2.html

4
David Yeager

ファイルの名前をグローバル変数に保存し、ハンドラーからファイルにアクセスします。シグナルハンドラコールバックには、1つの引数のみが渡されます。問題の原因となった実際のシグナルのID(SIGINT、SIGTSTPなど)

編集0:「ハンドラーへの引数を許可しない堅実な理由が必要です。」 <-割り込みベクトルがあります(基本的に、可能な各信号のルーチンへのジャンプアドレスのセット)。割り込みベクトルに基づいて、割り込みがトリガーされる方法を考えると、特定の関数が呼び出されます。残念ながら、変数に関連付けられたメモリがどこで呼び出されるかは明確ではなく、割り込みによっては実際にメモリが破損する可能性があります。それを回避する方法はありますが、既存のint 0x80アセンブリ命令(一部のシステムはまだ使用しています)を活用できません

1
Foo Bah

クラスのメソッドであるシグナルハンドラを使用できます。その後、そのハンドラーはそのクラスのメンバーデータにアクセスできます。ここでは、C signal()呼び出しの周りでPythonが何をするのか完全にはわかりませんが、データを再スコープする必要がありますか?

私はこれがうまくいくことに驚いたが、うまくいく。これを実行してから、別の端末からプロセスを強制終了します。

import os, signal, time

class someclass:
    def __init__(self):
        self.myvalue = "something initialized not globally defined"
        signal.signal(signal.SIGTERM, self.myHandler)
    def myHandler(self, s, f):
        # WTF u can do this?
        print "HEY I CAUGHT IT, AND CHECK THIS OUT", self.myvalue


print "Making an object"
a = someclass()

while 1:
    print "sleeping.  Kill me now."
    time.sleep(60)
0
drizzo4shizzo