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を捨てられるかな。