X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/9f8886c72ce02c9c4487a562a24a518c96043664..4f6d400bf0d6324faa343ea121f465017032d72b:/sig.c diff --git a/sig.c b/sig.c index 1bfddbf..555a2a9 100644 --- a/sig.c +++ b/sig.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: sig.c,v 1.1 1999/07/26 23:16:26 mdw Exp $ + * $Id: sig.c,v 1.2 1999/08/19 18:31:04 mdw Exp $ * * Signal handling * @@ -30,6 +30,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: sig.c,v $ + * Revision 1.2 1999/08/19 18:31:04 mdw + * Improve signal handling to prevent signals from being lost. + * * Revision 1.1 1999/07/26 23:16:26 mdw * Signal handling integrated into I/O system. * @@ -63,6 +66,8 @@ typedef struct sigstate { static sel_file sigsel; static int sigfd; static sigstate *sigs; +static sigset_t ss_all, ss_caught; +static unsigned nsig; /*----- Main code ---------------------------------------------------------*/ @@ -72,14 +77,21 @@ static sigstate *sigs; * * Returns: --- * - * Use: Generic signal handler. Just writes a single byte to the - * signal pipe. The byte contains the signal number. + * Use: Generic signal handler. Writes a single byte to the + * signal pipe. The byte contains the signal number. Also + * sets the appropriate bit in @ss_caught@ to indicate which + * signals are pending. */ static void sig_handler(int n) { + int e = errno; unsigned char sch = (unsigned char)n; + sigprocmask(SIG_BLOCK, &ss_all, 0); + sigaddset(&ss_caught, n); write(sigfd, &sch, 1); + /* The system should reset the signal mask here. */ + errno = e; } /* --- @sig_read@ --- * @@ -96,23 +108,37 @@ static void sig_handler(int n) static void sig_read(int fd, unsigned mode, void *p) { sigset_t ss; - unsigned char buf[256]; - int r; - sigemptyset(&ss); - while ((r = read(fd, buf, sizeof(buf))) > 0) { - unsigned char *p, *q; - for (p = buf, q = buf + r; p < q; p++) { + /* --- Read the currently caught signals --- * + * + * Block signals while the mask is being copied. + */ + + { + sigset_t oss; + unsigned char buf[256]; + + sigprocmask(SIG_BLOCK, &ss_all, &oss); + ss = ss_caught; + sigemptyset(&ss_caught); + while (read(fd, buf, sizeof(buf)) > 0) + /* Do nothing */; + sigprocmask(SIG_SETMASK, &oss, 0); + } + + /* --- Process the caught signals --- */ + + { + int i; + for (i = 0; i < nsig; i++) { sig *s; - int n = *p; - if (sigismember(&ss, n)) + if (!sigismember(&ss, i)) continue; - sigaddset(&ss, n); - s = sigs[n].list; + s = sigs[i].list; while (s) { sig *ss = s; s = s->next; - ss->proc(n, ss->p); + ss->proc(i, ss->p); } } } @@ -152,6 +178,7 @@ void sig_add(sig *s, int n, void (*proc)(int /*n*/, void */*p*/), void *p) sa.sa_flags |= SA_RESTART; #endif sigemptyset(&sa.sa_mask); + sigaddset(&ss_all, n); sigaction(n, &sa, &ss->sa); } @@ -186,8 +213,10 @@ void sig_remove(sig *s) /* --- Maybe remove the handler --- */ - if (!ss->list) + if (!ss->list) { sigaction(s->sig, &ss->sa, 0); + sigdelset(&ss_all, s->sig); + } } /* --- @sig_init@ --- * @@ -202,7 +231,6 @@ void sig_remove(sig *s) void sig_init(sel_state *s) { int fd[2]; - unsigned nsig; /* --- Work out how many signals there are --- */ @@ -265,6 +293,8 @@ void sig_init(sel_state *s) sigfd = fd[1]; sel_initfile(s, &sigsel, fd[0], SEL_READ, sig_read, 0); sel_addfile(&sigsel); + sigemptyset(&ss_all); + sigemptyset(&ss_caught); } /*----- That's all, folks -------------------------------------------------*/