Gauche:MacOSX:スレッドとシグナルマスク
Gauche:Bugsより移動
スレッドでのエラーが別スレッドのシグナルマスクに影響を与える (0.8.13, MacOSX Tiger)
http://d.hatena.ne.jp/mcabe/20080505 より。Linuxでは再現しないようです。
このコードをひとつのシェルから走らせて:
(use gauche.net)
(use gauche.threads)
(define (echo sock)
(call-with-client-socket sock
(lambda (ip op)
(guard (e (else (format #t "~a\n" (ref e 'message))))
(let loop ((line (read-line ip)))
(format op "~a\n" line)
(unless (equal? line "exit")
(loop (read-line ip))))))))
(define (main args)
(let1 sock (make-server-socket 'inet 5000 :reuse-addr? #t)
(let loop ((csock (socket-accept sock)))
(print (sys-sigmask SIG_SETMASK #f))
(thread-start! (make-thread (lambda _ (echo csock))))
(loop (socket-accept sock)))))
別のシェルからtelnet localhost 5000で接続し、^]q とかで接続を切ることを 何回か繰り返してみてください。サーバの方のシェルにこんな感じで 結果が出るんですが:
$ gosh ~/src/tt.scm #<sys-sigset []> write failed on #<oport (socket output #<socket (connect "127.0.0.1:36908")>) 0x8fd4e00>: Broken pipe #<sys-sigset []> write failed on #<oport (socket output #<socket (connect "127.0.0.1:36909")>) 0x918dd90>: Broken pipe
MacOSXだと2回目以降、sys-sigsetが空でなくフルマスク状態になるようです。 Leopardを使ってる方、試してみて頂けますか。
koguro(2008/05/06 02:05:20 PDT): Leopard(Darwin Kernel Version 9.2.2: Tue Mar 4 21:17:34 PST 2008; root:xnu-1228.4.31~1/RELEASE_I386)でもフルマスク状態になるようです。
#<sys-sigset []> write failed on #<oport (socket output #<socket (connect "127.0.0.1:64055")>) 0x5fc6e0>: Broken pipe #<sys-sigset [HUP|INT|QUIT|ILL|TRAP|ABRT|IOT|BUS|FPE|USR1|SEGV|USR2|PIPE|ALRM|TERM|CHLD|CONT|TSTP|TTIN|TTOU|URG|XCPU|XFSZ|VTALRM|PROF|WINCH|IO]> write failed on #<oport (socket output #<socket (connect "127.0.0.1:64058")>) 0x610c80>: Connection reset by peer
Shiro(2008/05/07 01:45:59 PDT): 試しに、src/vm.cのScm_NewVM()の中コードを 次のように修正して同じテストをやってみて頂けますか > Mac使いの方。 行番号は0.8.13リリース以来変わってるかも。
--- src/vm.c 4 May 2008 18:41:45 -0000 1.278
+++ src/vm.c 7 May 2008 08:43:56 -0000
@@ -160,7 +160,7 @@
v->result = SCM_UNDEFINED;
v->resultException = SCM_UNDEFINED;
v->module = proto ? proto->module : Scm_SchemeModule();
- v->cstack = proto ? proto->cstack : NULL;
+ v->cstack = NULL;
v->curin = proto? proto->curin : SCM_PORT(Scm_Stdin());
v->curout = proto? proto->curout : SCM_PORT(Scm_Stdout());
び(2008/05/07 22:50:34 PDT): 試してみましたが症状は変わりませんでした。
% gosh aaa.scm #<sys-sigset []> write failed on #<oport (socket output #<socket (connect "[::1]:53596")>) 0x4baea0>: Connection reset by peer #<sys-sigset [HUP|INT|QUIT|ILL|TRAP|ABRT|IOT|BUS|FPE|USR1|SEGV|USR2|PIPE|ALRM|TERM|CHLD|CONT|TSTP|TTIN|TTOU|URG|XCPU|XFSZ|VTALRM|PROF|WINCH|IO]> read failed on #<iport (socket input #<socket (connect "[::1]:53597")>) 0x4bab40>: Connection reset by peer zsh: killed gosh aaa.scm % uname -a Darwin condor.local 9.2.2 Darwin Kernel Version 9.2.2: Tue Mar 4 21:17:34 PST 2008; root:xnu-1228.4.31~1/RELEASE_I386 i386
Shiro(2008/05/07 23:45:55 PDT): むー。実機がないと追いづらいなあ。 サーバの方をstraceかけて、シグナルマスク関係だけ抜き出す…ってのはちょっと データが膨大になりそうだしなあ。
enami(2008/05/30 22:06:35 PDT): MacOSX では siglongjmp でプロセス全体のシグナルマスクが変更されるみたいですね。 以下のプログラムを、
#include <pthread.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
void *
f(void *a)
{
sigjmp_buf jb;
sigset_t ss;
sigfillset(&ss);
pthread_sigmask(SIG_SETMASK, &ss, NULL);
if (sigsetjmp(jb, 1) == 0)
siglongjmp(jb, 1);
pthread_sigmask(SIG_SETMASK, NULL, &ss);
printf("th: %x\n", sigismember(&ss, SIGINT));
return (NULL);
}
main()
{
sigset_t s;
pthread_t pt;
pthread_sigmask(SIG_SETMASK, NULL, &s);
printf("main: %x\n", sigismember(&s, SIGINT));
pthread_create(&pt, NULL, f, NULL);
pthread_join(pt, NULL);
pthread_sigmask(SIG_SETMASK, NULL, &s);
printf("main: %x\n", sigismember(&s, SIGINT));
}
MacOSX で実行すると
main: 0 th: 1 main: 1
になってしまいますが、他の例えば NetBSD では
main: 0 th: 1 main: 0
になります。 そのため、user_eval_inner でキャプチャされたシグナルマスクが Scm_VMDefaultExceptionHandler でプロセス全体に設定されているみたいです。
Shiro(2008/05/30 23:45:16 PDT): なるほど。調査ありがとうございます。 しかしこれは悲しい仕様だなあ。siglongjmpは使うなってことかな。 それともスレッド対応版が別に用意されてたりするのかな。
Shiro(2008/06/01 18:16:14 PDT): シグナルマスクの復帰を自前で行うように してみました (vm.c,v 1.280 etc.) MacOSXな方、試してみてください。
び(2008/06/01 18:56:48 PDT): 試してみましたが、上記の問題は再現しなくなりました。これで、Kahuaに入っているwork aroundを捨てられるかな。