diff -ruN kozos13/extintr.c kozos14/extintr.c --- kozos13/extintr.c Sun Nov 11 23:17:30 2007 +++ kozos14/extintr.c Mon Nov 12 00:16:45 2007 @@ -8,6 +8,7 @@ #include #include "kozos.h" +#include "thread.h" #define BUFFER_SIZE 2048 @@ -35,6 +36,7 @@ fd_set fds; char buf[32]; char *p; + fd_set readfds_save; /* * 子プロセスなので,この中で kz_ システムコールを利用してはいけない. @@ -42,6 +44,7 @@ FD_SET(cnt_fd, &readfds); if (maxfd < cnt_fd) maxfd = cnt_fd; + readfds_save = readfds; while (1) { fds = readfds; @@ -53,8 +56,8 @@ for (p = buf; p < buf + size; p += strlen(p) + 1) { if (!strcmp(p, "exit")) goto end; - fd = atoi(p); - FD_SET(fd, &readfds); + if (!strcmp(p, "refresh")) + readfds = readfds_save; } } } else { @@ -126,7 +129,6 @@ struct timeval tm = {0, 0}; intrbuf *ibp; int fildes[2]; - char buf[32]; pid_t chld_pid = 0; FD_ZERO(&readfds); @@ -157,16 +159,14 @@ kz_send(ibp->id, size, buffer); break; } - /* - * GDBスタブ利用の場合はスタブ側で read() されてしまい - * 上の select() で検知できないので,子プロセスへの - * 割り込み再開通知を別の方法で毎回行う必要があるだろう. - */ - sprintf(buf, "%d", ibp->fd); - write(cnt_fd, buf, strlen(buf) + 1); } } } + /* + * GDBスタブ利用の場合はスタブ側で read() されてしまい上の select() で + * 検知できないので,子プロセスへの割り込み再開通知を毎回行う. + */ + write(cnt_fd, "refresh", 8); } else if (fd) { /* from thread */ setintrbuf(fd, id, (struct sockaddr *)p); /* @@ -180,9 +180,13 @@ } pipe(fildes); if ((chld_pid = fork()) == 0) { /* 子プロセス */ -#if 0 - signal(SIGALRM, SIG_IGN); -#endif + /* + * 子プロセスはシグナル設定を引き継ぐらしいので,シグナル無効にする. + * (man sigaction に以下の記述あり) + * After a fork(2) or vfork(2) all signals, the signal mask, the signal + * stack, and the restart/interrupt flags are inherited by the child. + */ + sigprocmask(SIG_BLOCK, &block, NULL); close(fildes[1]); intr_controller(fildes[0]); } diff -ruN kozos13/thread.c kozos14/thread.c --- kozos13/thread.c Sun Nov 11 23:17:30 2007 +++ kozos14/thread.c Mon Nov 12 00:21:49 2007 @@ -21,14 +21,13 @@ kz_thread threads[THREAD_NUM]; kz_thread *readyque[PRI_NUM]; -static ucontext_t intr_env; static kz_timebuf *timers; static kz_thread *sigcalls[SIG_NUM]; static int debug_sockt = 0; -static sigset_t block; +sigset_t block; +static int on_os_stack = 0; kz_thread *current; -static int current_signo; static void getcurrent() { @@ -54,6 +53,10 @@ static void thread_init(kz_thread *thp, int argc, char *argv[]) { + /* + * なぜかここで UNBLOCK にしないとシグナル受信できないので + * UNBLOCK にする.謎. + */ sigprocmask(SIG_UNBLOCK, &block, NULL); thp->func(argc, argv); @@ -410,19 +413,39 @@ } extintr_proc(signo); dispatch(); + + /* + * スタブでの read() 待ちブロック中に SIGALRM (および SIGHUP)が発生した + * 場合に,以下の setcontext() によるコンテキストスイッチで SIGALRM が + * 消えてしまう(これはスタブでのブロックに比べると発生頻度は低いが,OSの + * 処理中にシグナル発生した場合も同様). + * 対策として,シグナルのブロックを一瞬だけ開けて,SIGALRM が発生した + * 場合には,再度シグナル処理を行う. + * これはOSの割り込み処理の再入になるが,以下の位置に限定して再入が行われる + * ので問題は無い. + */ + on_os_stack = 1; + sigprocmask(SIG_UNBLOCK, &block, NULL); + sigprocmask(SIG_BLOCK, &block, NULL); + on_os_stack = 0; + + /* ここで SIGALRM が発生するとシグナルを取りこぼす...要検討 */ + setcontext(¤t->context.uap); } static void thread_intr(int signo, siginfo_t *info, ucontext_t *uap) { - memcpy(¤t->context.uap, uap, sizeof(ucontext_t)); - current_signo = signo; - setcontext(&intr_env); + if (!on_os_stack) { + memcpy(¤t->context.uap, uap, sizeof(ucontext_t)); + } + thread_intrvec(signo); } static void thread_start(kz_func func, char *name, int pri, int argc, char *argv[]) { struct sigaction sa; + stack_t sigstack; memset(threads, 0, sizeof(threads)); memset(readyque, 0, sizeof(readyque)); @@ -430,20 +453,15 @@ timers = NULL; + sigstack.ss_sp = malloc(SIGSTKSZ); + sigstack.ss_size = SIGSTKSZ; + sigstack.ss_flags = 0; + sigaltstack(&sigstack, NULL); + memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = (void (*)(int, siginfo_t *, void *))thread_intr; - sa.sa_flags |= SA_SIGINFO; -#if 0 + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; sa.sa_mask = block; -#else - /* - * シグナル処理中のシグナル発生を受け付ける. - * これを有効にするとKOZOSの処理中に再入する可能性が発生するため問題有り - * なのだが,スタブ中での read() ブロック中に SIGALRM が発生した場合の - * 暫定対処とする. - */ - sigemptyset(&sa.sa_mask); -#endif sigaction(SIGSYS , &sa, NULL); sigaction(SIGHUP , &sa, NULL); @@ -460,30 +478,11 @@ current = NULL; current = (kz_thread *)thread_run(func, name, pri, argc, argv); - swapcontext(&intr_env, ¤t->context.uap); - { - /* なぜか getcontext() しなおさないと正常動作しない...謎 */ - static int f; - do { - f = 0; - getcontext(&intr_env); - } while (f); - f = 1; - } - - thread_intrvec(current_signo); + setcontext(¤t->context.uap); } void kz_start(kz_func func, char *name, int pri, int argc, char *argv[]) { - /* - * setjmp()/longjmp()はシグナルマスクを保存/復旧するので, - * intr_env の setjmp() 前にシグナルマスクを設定することでシグナル処理中の - * シグナルの発生をマスクし,割り込みハンドラ内でのシグナルを無効とする. - * (でないと割り込みハンドラの実行中に intr_env に longjmp() した後に, - * SIGALRM や SIGHUP の発生をハンドリングしてスレッドのディスパッチが - * 行われてしまい,誤動作する) - */ sigemptyset(&block); sigaddset(&block, SIGSYS); sigaddset(&block, SIGHUP); @@ -492,7 +491,6 @@ sigaddset(&block, SIGSEGV); sigaddset(&block, SIGTRAP); sigaddset(&block, SIGILL); - sigprocmask(SIG_BLOCK, &block, NULL); thread_start(func, name, pri, argc, argv); diff -ruN kozos13/thread.h kozos14/thread.h --- kozos13/thread.h Sun Nov 11 23:17:30 2007 +++ kozos14/thread.h Mon Nov 12 00:07:31 2007 @@ -41,5 +41,6 @@ extern kz_thread threads[THREAD_NUM]; extern kz_thread *current; +extern sigset_t block; #endif