chiark / gitweb /
Improve signal handling to prevent signals from being lost.
authormdw <mdw>
Thu, 19 Aug 1999 18:31:04 +0000 (18:31 +0000)
committermdw <mdw>
Thu, 19 Aug 1999 18:31:04 +0000 (18:31 +0000)
sig.c

diff --git a/sig.c b/sig.c
index 1bfddbf..555a2a9 100644 (file)
--- 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 -------------------------------------------------*/