]> git.pond.sub.org Git - empserver/blobdiff - src/lib/lwp/sig.c
Update copyright notice
[empserver] / src / lib / lwp / sig.c
index adff8a4d9d9b1d2e6f99c4c5c066a6f2580c513b..d950e3516d0a33c5942ffd64f22c2128eaa34447 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1994-2018, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1994-2021, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                Ken Stevens, Steve McClure, Markus Armbruster
  *
  *  Empire is free software: you can redistribute it and/or modify
  *  sig.c: Wait for signals
  *
  *  Known contributors to this file:
- *     Markus Armbruster, 2006-2007
+ *     Markus Armbruster, 2006-2020
  */
 
 #include <config.h>
 
 #include <errno.h>
 #include <stddef.h>
+#include <stdlib.h>
 #include <signal.h>
 #include "lwp.h"
 #include "lwpint.h"
 
 /*
- * Signals caught so far.
+ * Awaited signal numbers, terminated with 0.
+ */
+static int *LwpAwaitedSig;
+
+/*
+ * Pending awaited signals.
  * Access only with signals blocked!
  */
-static sigset_t LwpSigCaught;
+static volatile int *LwpPendingSig;
 
 /*
- * LwpSigCaught changed since last
+ * Is there anything in LwpPendingSig[]?
  */
-static sig_atomic_t LwpSigCheck;
+static volatile sig_atomic_t LwpSigCheck;
 
 /* The thread waiting for signals in lwpSigWait() */
 static struct lwpProc *LwpSigWaiter;
 
-static void lwpCatchAwaitedSig(int);
+static void lwpHandleAwaitedSig(int);
 
 /*
- * Initialize waiting for signals in @set.
+ * Initialize waiting for signals in @sig[].
+ * @sig[] contains signal numbers, terminated with 0.  It must have
+ * static storage duration.
  */
 void
-lwpInitSigWait(sigset_t *set)
+lwpInitSigWait(int sig[])
 {
     struct sigaction act;
     int i;
 
-    sigemptyset(&LwpSigCaught);
+    LwpAwaitedSig = sig;
 
     act.sa_flags = 0;
-    act.sa_mask = *set;
+    act.sa_handler = lwpHandleAwaitedSig;
     sigemptyset(&act.sa_mask);
-    act.sa_handler = lwpCatchAwaitedSig;
-    for (i = 0; i < NSIG; i++) {
-       if (sigismember(set, i))
-           sigaction(i, &act, NULL);
-    }
+    for (i = 0; sig[i]; i++)
+       sigaddset(&act.sa_mask, sig[i]);
+
+    LwpPendingSig = calloc(i, sizeof(*LwpPendingSig));
+
+    for (i = 0; sig[i]; i++)
+       sigaction(sig[i], &act, NULL);
 }
 
+/*
+ * Signal handler for awaited signals.
+ * Set @LwpPendingSig[] for @sig, and set @LwpSigCheck.
+ * Not reentrant; lwpInitSigWait() guards.
+ */
 static void
-lwpCatchAwaitedSig(int sig)
+lwpHandleAwaitedSig(int sig)
 {
-    sigaddset(&LwpSigCaught, sig);
+    int i;
+
+    for (i = 0; LwpAwaitedSig[i]; i++) {
+       if (sig == LwpAwaitedSig[i])
+           LwpPendingSig[i] = 1;
+    }
     LwpSigCheck = 1;
 }
 
 /*
- * Test whether a signal from @set has been caught.
- * If yes, delete that signal from the set of caught signals, and
+ * Test whether an awaited signal is pending.
+ * If yes, remove that signal from the set of pending signals, and
  * return its number.
  * Else return 0.
  */
 static int
-lwpGetSig(sigset_t *set)
+lwpGetSig(void)
 {
-    sigset_t save;
+    int ret = 0;
+    sigset_t set, save;
     int i;
 
-    sigprocmask(SIG_BLOCK, set, &save);
-    for (i = NSIG - 1; i > 0; i--) {
-       if (sigismember(set, i) && sigismember(&LwpSigCaught, i)) {
-           lwpStatus(LwpCurrent, "Got awaited signal %d", i);
-           sigdelset(&LwpSigCaught, i);
-           break;
+    sigemptyset(&set);
+    for (i = 0; LwpAwaitedSig[i]; i++)
+       sigaddset(&set, LwpAwaitedSig[i]);
+    sigprocmask(SIG_BLOCK, &set, &save);
+
+    for (i = 0; LwpAwaitedSig[i]; i++) {
+       if (LwpPendingSig[i]) {
+           lwpStatus(LwpCurrent, "Got awaited signal %d", LwpPendingSig[i]);
+           ret = LwpAwaitedSig[i];
+           LwpPendingSig[i] = 0;
        }
     }
+
+    for (; LwpAwaitedSig[i] && LwpPendingSig[i]; i++) ;
+    if (!LwpPendingSig[i])
+       LwpSigCheck = 0;
+
     sigprocmask(SIG_SETMASK, &save, NULL);
-    return i;
+    return ret;
 }
 
 /*
- * Wait until a signal from @set arrives.
- * Assign its number to *@sig and return 0.
- * If another thread is already waiting for signals, return EBUSY
+ * Wait until one of the signals passed to lwpInitSigWait() arrives.
+ * Return its signal number.
+ * If another thread is already waiting for signals, return -1
  * without waiting.
  */
 int
-lwpSigWait(sigset_t *set, int *sig)
+lwpSigWait(void)
 {
     int res;
 
-    if (CANT_HAPPEN(LwpSigWaiter))
-       return EBUSY;
+    if (LwpSigWaiter)
+       return -1;
     for (;;) {
-       LwpSigCheck = 0;
-       res = lwpGetSig(set);
+       res = lwpGetSig();
        if (res > 0)
            break;
        lwpStatus(LwpCurrent, "Waiting for signals");
        LwpSigWaiter = LwpCurrent;
        lwpReschedule();
     }
-    *sig = res;
-    return 0;
+    return res;
 }
 
 /*