/* -*-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
*
/*----- 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.
*
static sel_file sigsel;
static int sigfd;
static sigstate *sigs;
+static sigset_t ss_all, ss_caught;
+static unsigned nsig;
/*----- Main code ---------------------------------------------------------*/
*
* 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@ --- *
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);
}
}
}
sa.sa_flags |= SA_RESTART;
#endif
sigemptyset(&sa.sa_mask);
+ sigaddset(&ss_all, n);
sigaction(n, &sa, &ss->sa);
}
/* --- Maybe remove the handler --- */
- if (!ss->list)
+ if (!ss->list) {
sigaction(s->sig, &ss->sa, 0);
+ sigdelset(&ss_all, s->sig);
+ }
}
/* --- @sig_init@ --- *
void sig_init(sel_state *s)
{
int fd[2];
- unsigned nsig;
/* --- Work out how many signals there are --- */
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 -------------------------------------------------*/