Gauche > Archives > 2010/08/27

2010/08/27 02:39:50 UTCenami
#
http://practical-scheme.net/chaton/gauche/a/2010/07/05#entry-4c31afcc-7e461
#
この話ですが、パッチ書いてみました。
2010/08/27 02:40:36 UTCenami
#
diff --git a/src/signal.c b/src/signal.c
index bb87a96..93ac0a1 100644
--- a/src/signal.c
+++ b/src/signal.c
@@ -581,5 +581,5 @@ ScmObj Scm_SetSignalHandler(ScmObj sigs, ScmObj handler, ScmSysSigset *mask)
     struct sigdesc *desc;
     sigset_t sigset;
-    int badproc = FALSE, sigactionfailed = FALSE;
+    int badproc = FALSE, sigactionfailed = FALSE, donthandle = FALSE;
 
     if (SCM_INTP(sigs)) {
@@ -596,11 +596,4 @@ ScmObj Scm_SetSignalHandler(ScmObj sigs, ScmObj handler, ScmSysSigset *mask)
     }
 
-    if (mask == NULL) {
-        /* If no mask is specified, block singals in SIGS. */
-        mask = make_sigset();
-        mask->set = sigset;
-    }
-    
-    (void)SCM_INTERNAL_MUTEX_LOCK(sigHandlers.mutex);
     if (SCM_TRUEP(handler)) {
         act.sa_handler = SIG_DFL;
@@ -610,7 +603,17 @@ ScmObj Scm_SetSignalHandler(ScmObj sigs, ScmObj handler, ScmSysSigset *mask)
                && SCM_PROCEDURE_TAKE_NARG_P(handler, 1)) {
         act.sa_handler = sig_handle;
+    } else if (SCM_NULLP(handler)) {
+        donthandle = TRUE;
     } else {
         badproc = TRUE;
     }
+
+    if (mask == NULL && !donthandle) {
+        /* If no mask is specified, block singals in SIGS. */
+        mask = make_sigset();
+        mask->set = sigset;
+    }
+    
+    (void)SCM_INTERNAL_MUTEX_LOCK(sigHandlers.mutex);
     if (!badproc) {
         sigfillset(&act.sa_mask); /* we should block all the signals */
@@ -619,5 +622,5 @@ ScmObj Scm_SetSignalHandler(ScmObj sigs, ScmObj handler, ScmSysSigset *mask)
             if (!sigismember(&sigset, desc->num)) continue;
             if (!sigismember(&sigHandlers.masterSigset, desc->num)) continue;
-            if (sigaction(desc->num, &act, NULL) != 0) {
+            if (!donthandle && sigaction(desc->num, &act, NULL) != 0) {
                 sigactionfailed = desc->num;
             } else {
@@ -956,5 +959,5 @@ void Scm__InitSignal(void)
     (void)SCM_INTERNAL_MUTEX_INIT(sigHandlers.mutex);
     sigemptyset(&sigHandlers.masterSigset);
-    for (i=0; i<NSIG; i++) sigHand
2010/08/27 02:41:49 UTCenami
#
あれ、切れちゃった?
#
wiliki のほうに貼っときます。
2010/08/27 12:29:27 UTCshiro
#
Cのシグナルハンドラで出来ることは非常に限られているので RT: @garaemon: gaucheとかどうしてるんだろ。ffi越しのcの世界でシグナルが発生したら、それを処理する為にcの世界からschemeの世界にすぐもどるのかな?
#
@garaemon CのハンドラではVMにフラグを立てるだけで、VMループに戻った時にフラグをチェックしてSchemeのハンドラを呼び出しています
#
@garaemon また、大抵のシステムコールはシグナルで中断されるので、システムコールの戻り値がEINTRの時はそこからSchemeのハンドラを呼び出します
#
@garaemon ただし、pthread_cond_waitはシグナルで中断されることが保証されてないので、そこで受けたシグナルは条件が満たされるまで待たされる可能性あり
#
@garaemon あと、Cルーチン内でシステムコールを呼ばずに長時間かかる計算をしている場合などにも、Schemeのハンドラが呼ばれるのが遅れる可能性があります
#
@garaemon あれ、twitterブリッジが止まってたみたい。シグナルについて説明したのでchatonの方見てください。
2010/08/27 12:38:18 UTCgaraemon
#
なるほどー. ありがとうございます > shiroさん
#
そうすると, signalが発生しないととまらないmainLoopみたいなのがあって, それをffi越しに呼ぶと, しかもシグナルハンドラはscheme vmが設定しちゃってたら, けっこうやばい感じでしょうか?
2010/08/27 12:41:06 UTCshiro
#
foreign libraryがGaucheを意識して書かれてるなら適宜SCM_SIGCHECKをループ内に挿入してもらえばいいんですが、既存のライブラリだと無理ですね。
2010/08/27 12:41:24 UTCgaraemon
#
なるほど, なるほど
2010/08/27 12:41:34 UTCshiro
#
foreign functionを呼び出す部分でシグナルハンドラをすげ替えるとかする手はありますが。
2010/08/27 12:43:36 UTCgaraemon
#
gaucheのFFIのためのブリッジを書くところで, 適切にSCM_SIGCHECKを使ったハンドラを定義すべき, というのが落しどころでしょうか?
2010/08/27 12:43:59 UTCshiro
#
あと、Gaucheを組み込みで用いる場合は、「どのシグナルをSchemeで処理するか」を指定できます (Scm_SetMasterSigmask)。なのでシグナル処理はシステムに任せる(Schemeでは処理しない)というのも可。
#
ハンドラ内でSCM_SIGCHECKは呼べません。 > gaucheのFFIのためのブリッジを書くところで, 適切にSCM_SIGCHECKを使ったハンドラを定義すべき, というのが落しどころでしょうか?
#
ハンドラ内で、というのはCのシグナルハンドラ内で、ということ
#
どんな場合でも使えるという手段は多分無いのですが、外部ライブラリの方で何らかの例外/エラー事態を発生させるような手段をCのハンドラで講じて、その例外事態をブリッジで捕まえてSCM_SIGCHECKを呼ぶ、ということになると思います。
2010/08/27 12:49:30 UTCgaraemon
#
なるほどー
2010/08/27 12:49:34 UTCshiro
#
Cのハンドラから(sig)longjmpで抜けるのは安全ではないし、C++の例外をthrowすることもできないので、上記例外事態というのはあくまでその外部ライブラリが例外と認識する何か、ということになります。
2010/08/27 12:52:38 UTCgaraemon
#
そういうときに, signal.cのvoid sig_handle(int)を呼ぶというのは, sig_handleが外から見えないようになっているところを見ると, 意図されていないんでしょうか?
2010/08/27 12:53:42 UTCshiro
#
sig_handleはVMにフラグを立てて戻るだけですから、今回の目的には使えないのでは?
2010/08/27 12:56:27 UTCgaraemon
#
きちんとしたエラーハンドルになるかは微妙ですが, 
void newHandler(int sig)
{
 # call original handler
 c_original_handler(sig);
 # for scheme vm
 sig_handle(sig);
}

int init_c_lib(){
 ...
 signal(SIGINT, newHandler);
}
#
みたいなのを想像してます
#
もちろん, ケースバイケースですが, Cのハンドラも, schemeのハンドラも呼ぶというイメージでしょうか?
2010/08/27 12:58:49 UTCshiro
#
ああなるほど。両方呼びたいというケースがあるのか。
#
そういう目的ならsig_handleを外から見えるようにしとくのはありですね。
#
Cレベルのハンドラはすぐに呼ばれて、SchemeレベルのはGaucheに戻ってから呼ばれると。
2010/08/27 12:59:45 UTCgaraemon
#
はい, そうです
2010/08/27 13:02:10 UTCshiro
#
とりあえずのworkaroundとしては、init_c_lib()で新しいハンドラを設定した時に古いハンドラを得ることができて、それがsig_handleを指している「はず」なので、それを使うということはできるかも。init_c_libが一度しか呼ばれないことは別途保証するとして。
2010/08/27 13:04:28 UTCgaraemon
#
なるほど, sigactionでちょろっと古いのはとってこれるのですね
2010/08/27 13:04:48 UTCshiro
#
signal(2)も古いハンドラを返しますよ。
2010/08/27 13:05:09 UTCgaraemon
#
あ, そうなんですか, 知らなかったです
2010/08/27 15:18:08 UTCkoguro
#
ふと思いついたけど、シェルの機能使わなくても括弧0個にできた。
#
;; coding: iso8859-1
'端call-with-input-string "\x28print 'hi\x29" load-from-port #;云
#
ただし、Shift-JISで保存すること。
2010/08/27 15:33:06 UTCshiro
#
わはは。しかしcoding:をつけとくと次にemacsで開けた時にバレてしまうのでは。
2010/08/27 15:34:13 UTCkoguro
#
みんな vi を使おう。
#
こういった技 utf-8 だと使えないんですよね。まあ、21世紀にもなって、なんでこんなことやってんだろうと思いますが。