Gauche:MTとシグナル

Gauche:MTとシグナル

Gaucheでは、システムのシグナルハンドラはVMにシグナルをキューするだけで、 実際にそのシグナルを処理するのはVMのメインループやシステムコールの 直後など安全な箇所で行っている。Thread毎にVMを持つので、シグナルを処理する のはシグナルを受けたthreadだ。

ところが、これだとpthread_cond_waitで待っている時に受けたシグナルが うまくいかない。システムのシグナルハンドラは呼ばれるけど、それだけで pthread_cond_waitは中断しないからだ。

どうすべえ。


Linuxのpthread_cond_timedwaitはinterruptされると中断してEINTRを返す、 とマニュアルにあるが、POSIX的には「中断されないか、もしくは0を返す spurious wakeupとなる」らしい。

どっちにせよ、pthread_cond_timedwaitもシグナルでの中断には使えないと。


タイムアウトを切らない待ちに関しては、内部でpthread_cond_timedwaitを 使って適当な間隔でシグナルキューをチェックするって方法はあるが、 timedwaitで長時間の待ちが指定された場合はだめだし、そもそも綺麗じゃない。

「シグナルを受けたthreadがその処理をする」というモデルがそもそも 悪いような気がしてきた。


ちょっとsurvey。

Python

シグナルはキューに入り、primordial thread中のsafeな場所で処理されるようだ。

Perl

Thread::Signalをuseしてると、シグナルハンドル専用のスレッドが走る。 何もしなければシステムのハンドラ内でPerlのハンドラを呼ぶらしい。これはunsafe。


メモ。Boehm GCはLinux/pthreadの実装で、SIGPWRとSIGXCPUを GC中のスレッドの同期に使っている。Scheme側でこれらのハンドラを 置き換えないこと。


POSIX threadのモデルをそのまま踏襲するのが良いような気がしてきた。 つまり、ハンドラベクタは全スレッドで共通にして、 各スレッド毎にマスクを持つと。

現実的なプログラムでは、どのスレッドにシグナルが配送されるかわからない という状態ではほとんど役に立たないので、マスクを適切にセットすることに なろう。多分、次の3つのケースがあるんじゃなかろうか。

ところでpthreadではpthread_createを発行したスレッドのマスクが作られたスレッド へと引き継がれる。デフォルトではasynchronous signalはどのスレッドでも 処理され得る。シグナル処理がCのハンドラ内だけで完結するなら、それで問題はない。

しかしGaucheの場合、Cのシグナルハンドラはシグナルを受けたスレッド固有の シグナルキューにシグナルを入れるだけで、そのシグナルはスレッドがシグナルの チェックポイントに到達しないとSchemeレベルで処理されない。condition variable 等で待っているスレッドにシグナルが配送されてしまった場合、そのシグナルは ずーっとキューに置いておかれることになるかもしれない。

make-threadの前後でいちいちマスクをセットすれば良いのだろうが、 それだとせっかくスレッドAPIをSRFI-18に合わせたのに、現実的なプログラムでは ポータビリティが無くなってしまう。

むしろ、Schemeレベルで作られるスレッドはデフォルトで全シグナルをブロックするように したらどうか。これならデフォルトでasynchronous signalはprimordial thread で処理されることになる。SRFI-18コンパチで書いてあるスクリプトも安全に 動かせるだろう。特別なことをしたい場合だけ、スレッドの中で明示的に マスクを変更すれば良い。


というわけで、Gauche 0.6 は上記のモデルで実装してみた。


2002-11-27 gniibe と申します。お世話になります。Gauche 使ってます。 コードは確認していないのですが、正しい判断だと思われます。

勘違いして、スレッド毎にシグナルハンドラということが多いです。これは、 間違いです。 POSIX Thread FAQ

Guile でもまちがってる。言ったのに。

時に、POSIX Thread の実装の LinuxThreads でもスレッド毎のシグナルハンドラは サポートされてなくって(どのスレッドがシグナルを受けるか保証していない)、Ulrich Drepper さんが作っているスレッドライブラリの実装ではそれをできるようにしようとしてるようです。

Shiro (2002/11/27 17:06:01 PST): g新部さんこんにちは。 MTでのシグナルハンドリングに関しては私自身は まだテストコード以上のシリアスなコードを書いていないので、 枯れていないと思われます。

gniibe's little survey in 1998

Shiro (2002/11/28 23:11:13 PST): GuileのDEFER_INTS/ALLOW_INTSはSCM由来だったように 思います。ところで上のメッセージの返信でTelford Tendysが書いている問題:

   Finally, if a piece of C code already makes use of signals for it's own
   purposes then it's difficult to adapt that code to using Guile because
   Guile wants control over all of the signals. This must limit the
   scope of Guile usage somewhat.

ですが、Gaucheではアプリケーションの組み込み言語として使われる場合、 アプリケーション側がGaucheにハンドルして欲しいシグナルを明示的に 指定するようにしています。(Scm_SetMasterSigmask/Scm_GetMasterSigmask in signal.c)

Gaucheにextensionで組み込むライブラリがシグナルを使用していた場合も、 一応ブリッジコードからこれらのAPIを呼ぶことでGauche側でシグナルを 触らないように指定することはできます。モジュラリティは損なわれますが。


Last modified : 2005/03/14 11:38:57 UTC