Gauche:MacOSX:スレッドとシグナルマスク

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


Last modified : 2012/02/02 11:55:20 UTC