chiark / gitweb /
Infrastructure: Strip away crufty CVS $Id$ tags.
[mLib] / sig.c
diff --git a/sig.c b/sig.c
index 1bfddbf4ccee1b65643a91f254d438d53e2ae4e6..87dbb3334890ef23fe610d97394dfcc7072d04c6 100644 (file)
--- a/sig.c
+++ b/sig.c
@@ -1,13 +1,11 @@
 /* -*-c-*-
- *
- * $Id: sig.c,v 1.1 1999/07/26 23:16:26 mdw Exp $
  *
  * Signal handling
  *
  * (c) 1999 Straylight/Edgeware
  */
 
-/*----- Licensing notice --------------------------------------------------* 
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of the mLib utilities library.
  *
  * it under the terms of the GNU Library General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
- * 
+ *
  * mLib is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Library General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Library General Public
  * License along with mLib; if not, write to the Free
  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  * MA 02111-1307, USA.
  */
 
-/*----- Revision history --------------------------------------------------* 
- *
- * $Log: sig.c,v $
- * Revision 1.1  1999/07/26 23:16:26  mdw
- * Signal handling integrated into I/O system.
- *
- */
-
 /*----- Header files ------------------------------------------------------*/
 
 #include <errno.h>
@@ -63,6 +53,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 +64,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,27 +95,41 @@ 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);
       }
     }
   }
-}  
+}
 
 /* --- @sig_add@ --- *
  *
@@ -152,6 +165,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 +200,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 +218,6 @@ void sig_remove(sig *s)
 void sig_init(sel_state *s)
 {
   int fd[2];
-  unsigned nsig;
 
   /* --- Work out how many signals there are --- */
 
@@ -261,10 +276,12 @@ void sig_init(sel_state *s)
   fdflags(fd[1], O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
 
   /* --- Set everything up for the future --- */
-    
+
   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 -------------------------------------------------*/