]> git.pond.sub.org Git - empserver/commitdiff
(empth_init_signals): Don't catch SIGINT and SIGTERM.
authorMarkus Armbruster <armbru@pond.sub.org>
Wed, 7 Jun 2006 21:01:16 +0000 (21:01 +0000)
committerMarkus Armbruster <armbru@pond.sub.org>
Wed, 7 Jun 2006 21:01:16 +0000 (21:01 +0000)
(empth_wait_for_shutdown): New.
(main): Use it to wait for shutdown signal, then shut down.  Closes
#770492.
(empth_exit): Remove the weird special case for main thread.

Implement empth_wait_for_shutdown() for EMPTH_LWP:
[EMPTH_LWP] (lwpInitSigWait, lwpSigWait, lwpSigWakeup): New.
Declaration of lwpSigWait was accidentally committed in the previous
revision of lwp.h.
[EMPTH_LWP] (lwpInitSystem): New parameter waitset, pass it on to
lwpInitSigWait().
[EMPTH_LWP] (lwpReschedule): Call lwpSigWakeup().
[EMPTH_LWP] (empth_init): Declare signals needed by
empth_wait_for_shutdown().
(empth_wait_for_shutdown): Implement on top of lwpSigWait().

Implement empth_wait_for_shutdown() for EMPTH_POSIX:
[EMPTH_POSIX] (empth_init): Block signals, so that
empth_wait_for_shutdown() can use sigwait() safely.
(empth_wait_for_shutdown): Implement on top of sigwait().

Implement empth_wait_for_shutdown() for EMPTH_W32:
(empth_wait_for_shutdown): Implement on top of loc_BlockMainThread().

include/empthread.h
include/lwp.h
src/lib/empthread/lwp.c
src/lib/empthread/ntthread.c
src/lib/empthread/posix.c
src/lib/empthread/pthread.c
src/lib/lwp/lwp.c
src/lib/lwp/lwpint.h
src/lib/lwp/sig.c [new file with mode: 0644]
src/server/main.c

index 4c952b405ea2824735e4d5095bb1e4d7190fc228..172e89a0d9917405b547620fd7ae693eee27b6d3 100644 (file)
@@ -144,6 +144,9 @@ empth_t *empth_self(void);
 
 /*
  * Terminate the current thread.
+ * The current thread should not be the thread that executed main().
+ * If it is, implementations may terminate the process rather than the
+ * thread.
  * Never returns.
  */
 void empth_exit(void);
@@ -184,6 +187,12 @@ void empth_wakeup(empth_t *thread);
  */
 void empth_sleep(time_t until);
 
+/*
+ * Wait for some implementation-defined external shutdown signal.
+ * Return a non-negative number identifying the signal.
+ */
+int empth_wait_for_shutdown(void);
+
 /*
  * Create a semaphore.
  * NAME is its name, it is used for debugging.
index dbb2533154ad4257b85d725ddc181692491a485a..303ee3ceb1006232dc6ae0c941a099ae57cec979 100644 (file)
@@ -24,6 +24,7 @@
 #ifndef LWP_H
 #define LWP_H
 
+#include <signal.h>
 #include "misc.h"
 
 #define LWP_STACKCHECK 0x1
@@ -37,7 +38,7 @@ struct lwpSem;
 
 #define LWP_MAX_PRIO   8
 
-struct lwpProc *lwpInitSystem(int prio, char **ctxp, int flags);
+struct lwpProc *lwpInitSystem(int prio, char **ctxp, int flags, sigset_t *);
 struct lwpProc *lwpCreate(int prio, void (*)(void *), int size,
                          int flags, char *name, char *desc,
                          int argc, char **argv, void *ud);
index 6c5cbe83a6fb4b3dfcc7b7893fc2ef6346b1ef61..077c57728cd406c4934c77114191ece4524390eb 100644 (file)
 
 #include <config.h>
 
+#include <signal.h>
 #include <time.h>
 #include "empthread.h"
 
-/* The thread `created' by lwpInitSystem() */
-static empth_t *empth_main;
-
 /* Flags that were passed to empth_init() */
 static int empth_flags;
 
@@ -46,9 +44,14 @@ static int empth_flags;
 int
 empth_init(void **ctx, int flags)
 {
+    sigset_t set;
+
     empth_flags = flags;
     empth_init_signals();
-    empth_main = lwpInitSystem(PP_MAIN, (char **)ctx, flags);
+    sigemptyset(&set);
+    sigaddset(&set, SIGINT);
+    sigaddset(&set, SIGTERM);
+    lwpInitSystem(PP_MAIN, (char **)ctx, flags, &set);
     return 0;
 }
 
@@ -71,16 +74,6 @@ empth_self(void)
 void
 empth_exit(void)
 {
-    time_t now;
-
-    /* We want to leave the main thread around forever, until it's time
-       for it to die for real (in a shutdown) */
-    if (LwpCurrent == empth_main) {
-       while (1) {
-           time(&now);
-           lwpSleepUntil(now + 60);
-       }
-    }
     lwpExit();
 }
 
@@ -114,6 +107,26 @@ empth_sleep(time_t until)
     lwpSleepUntil(until);
 }
 
+int
+empth_wait_for_shutdown(void)
+{
+    sigset_t set;
+    int sig, err;
+    time_t now;
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGINT);
+    sigaddset(&set, SIGTERM);
+    for (;;) {
+       err = lwpSigWait(&set, &sig);
+       if (CANT_HAPPEN(err)) {
+           time(&now);
+           lwpSleepUntil(now + 60);
+           continue;
+       }
+       return sig;
+    }
+}
 
 empth_sem_t *
 empth_sem_create(char *name, int cnt)
index 1f420fa78853c1c3850463f0c0a0876299d7d56f..3942cbe6d0b8debc5a193b6ef2e8eec111d8a79d 100644 (file)
@@ -276,31 +276,6 @@ loc_Exit_Handler(DWORD fdwCtrlType)
     }
 }
 
-/************************
- * empth_request_shutdown
- *
- * This wakes up the main thread so shutdown can proceed.
- * This is done by signalling hShutdownEvent.
- */
-void
-empth_request_shutdown(void)
-{
-    SetEvent(hShutdownEvent);
-}
-
-/************************
- * loc_BlockMainThread
- *
- * This blocks up the main thread.  loc_WakeupMainThread() is used
- * wakeup the main so shutdown can proceed.
- */
-static void
-loc_BlockMainThread(void)
-{
-    /* Get the MUTEX semaphore, wait the number of MS */
-    WaitForSingleObject(hShutdownEvent, INFINITE);
-}
-
 /************************
  * empth_threadMain
  *
@@ -490,19 +465,12 @@ empth_exit(void)
 {
     empth_t *pThread = TlsGetValue(dwTLSIndex);
 
-    loc_BlockThisThread();
-
     loc_debug("empth_exit");
+    loc_BlockThisThread();
 
-    if (pThread->bMainThread) {
-       loc_BlockMainThread();
-       loc_RunThisThread();
-       shutdwn(0);
-    } else {
-       TlsSetValue(dwTLSIndex, NULL);
-       loc_FreeThreadInfo(pThread);
-       _endthread();
-    }
+    TlsSetValue(dwTLSIndex, NULL);
+    loc_FreeThreadInfo(pThread);
+    _endthread();
 }
 
 /************************
@@ -606,6 +574,27 @@ empth_sleep(time_t until)
     loc_RunThisThread();
 }
 
+/************************
+ * empth_request_shutdown
+ *
+ * This wakes up empth_wait_for_shutdown() so shutdown can proceed.
+ * This is done by signalling hShutdownEvent.
+ */
+void
+empth_request_shutdown(void)
+{
+    SetEvent(hShutdownEvent);
+}
+
+int
+empth_wait_for_shutdown(void)
+{
+    /* Get the MUTEX semaphore, wait the number of MS */
+    WaitForSingleObject(hShutdownEvent, INFINITE);
+
+    loc_RunThisThread();
+    return 0;
+}
 
 /************************
  * empth_sem_create
index 5ec66438a946275df92961cfe7bde6e5f1dcaf03..015080ed3e9be1e6f904b643dc7c0737d96fb0d8 100644 (file)
@@ -46,9 +46,6 @@ empth_init_signals(void)
 
     act.sa_flags = 0;
     sigemptyset(&act.sa_mask);
-    act.sa_handler = shutdwn;
-    sigaction(SIGTERM, &act, NULL);
-    sigaction(SIGINT, &act, NULL);
     act.sa_handler = panic;
     sigaction(SIGBUS, &act, NULL);
     sigaction(SIGSEGV, &act, NULL);
index 045fbb2e8de781f996f52f0d0064304f92a9c493..f3503cf8e9b950859d4cafb13008dc7620ed860e 100644 (file)
@@ -144,12 +144,17 @@ int
 empth_init(void **ctx_ptr, int flags)
 {
     empth_t *ctx;
+    sigset_t set;
     struct sigaction act;
 
     empth_flags = flags;
     udata = ctx_ptr;
 
     empth_init_signals();
+    sigemptyset(&set);
+    sigaddset(&set, SIGINT);
+    sigaddset(&set, SIGTERM);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
     act.sa_flags = 0;
     sigemptyset(&act.sa_mask);
     act.sa_handler = empth_alarm;
@@ -256,20 +261,9 @@ empth_self(void)
 void
 empth_exit(void)
 {
-    empth_t *ctx_ptr;
-
-    pthread_mutex_unlock(&mtx_ctxsw);
     empth_status("empth_exit");
-    ctx_ptr = pthread_getspecific(ctx_key);
-    /* We want to leave the main thread around forever, until it's time
-       for it to die for real (in a shutdown) */
-    if (!strcmp(ctx_ptr->name, "Main")) {
-       while (1) {
-           sleep(60);
-       }
-    }
-
-    free(ctx_ptr);
+    pthread_mutex_unlock(&mtx_ctxsw);
+    free(pthread_getspecific(ctx_key));
     pthread_exit(0);
 }
 
@@ -351,7 +345,6 @@ empth_select(int fd, int flags)
 
 }
 
-
 static void
 empth_alarm(int sig)
 {
@@ -386,6 +379,26 @@ empth_sleep(time_t until)
     empth_restorectx();
 }
 
+int
+empth_wait_for_shutdown(void)
+{
+    sigset_t set;
+    int sig, err;
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGINT);
+    sigaddset(&set, SIGTERM);
+    for (;;) {
+       empth_status("waiting for signals");
+       err = sigwait(&set, &sig);
+       if (CANT_HAPPEN(err)) {
+           sleep(60);
+           continue;
+       }
+       empth_status("got awaited signal %d", sig);
+       return sig;
+    }
+}
 
 empth_sem_t *
 empth_sem_create(char *name, int cnt)
index 0205738a2ccb83c12b0245504afd097bf96a2dff..217246a39d90e14588b795d065eaebf20ce71fad 100644 (file)
@@ -76,6 +76,8 @@ lwpReschedule(void)
        lwpStackCheck(LwpCurrent);
     }
 
+    lwpSigWakeup();
+
     /* destroy dead threads */
     lwpStatus(LwpCurrent, "Cleaning dead queue");
     while (NULL != (nextp = lwpGetFirst(&LwpDeadQ))) {
@@ -285,7 +287,7 @@ lwpSetPriority(int new)
  * initialise the coroutine structures
  */
 struct lwpProc *
-lwpInitSystem(int pri, char **ctxptr, int flags)
+lwpInitSystem(int pri, char **ctxptr, int flags, sigset_t *waitset)
 {
     struct lwpQueue *q;
     int i, *stack, marker;
@@ -313,6 +315,7 @@ lwpInitSystem(int pri, char **ctxptr, int flags)
     for (i = LWP_MAX_PRIO, q = LwpSchedQ; i--; q++)
        q->head = q->tail = 0;
     LwpDeadQ.head = LwpDeadQ.tail = 0;
+    lwpInitSigWait(waitset);
     /* must be lower in priority than us for this to work right */
     sel = lwpCreate(0, lwpSelect, 16384, flags, "EventHandler",
                    "Select (main loop) Event Handler", 0, 0, 0);
index 9e905b5f506b300870a5f1c6ff9c433a54653491..2f1edcd7c240ea80b1a4befcb3701a7e8993c4e6 100644 (file)
@@ -95,7 +95,9 @@ void lwpReschedule(void);
 void lwpEntryPoint(void);
 void lwpInitSelect(struct lwpProc *);
 void lwpSelect(void *);
-void lwpStatus(struct lwpProc *proc, char *format, ...)
+void lwpInitSigWait(sigset_t *);
+void lwpSigWakeup(void);
+void lwpStatus(struct lwpProc *, char *, ...)
     ATTRIBUTE((format (printf, 2, 3)));
 
 #endif
diff --git a/src/lib/lwp/sig.c b/src/lib/lwp/sig.c
new file mode 100644 (file)
index 0000000..9800a97
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *  Empire - A multi-player, client/server Internet based war game.
+ *  Copyright (C) 1994-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *                           Ken Stevens, Steve McClure
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  ---
+ *
+ *  See files README, COPYING and CREDITS in the root of the source
+ *  tree for related information and legal notices.  It is expected
+ *  that future projects/authors will amend these files as needed.
+ *
+ *  ---
+ *
+ *  sig.c: Wait for signals
+ * 
+ *  Known contributors to this file:
+ *     Markus Armbruster, 2006
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <signal.h>
+#include "misc.h"
+#include "lwp.h"
+#include "lwpint.h"
+
+/* Signals awaited by lwpSigWait() */
+static sigset_t *LwpSigAwaited;
+
+/*
+ * Signals from LwpSigAwaited catched so far
+ * Access only with signals blocked!
+ */
+static sigset_t LwpSigCatched;
+
+/* The thread waiting for signals in lwpSigWait() */
+static struct lwpProc *LwpSigWaiter;
+
+/* Where to return the signal number to the thread in lwpSigWait() */
+static int *LwpSigPtr;
+
+static void lwpCatchAwaitedSig(int);
+
+/*
+ * Initialize waiting for signals in SET.
+ */
+void
+lwpInitSigWait(sigset_t *set)
+{
+    struct sigaction act;
+    int i;
+
+    sigemptyset(&LwpSigCatched);
+
+    act.sa_flags = 0;
+    act.sa_mask = *set;
+    sigemptyset(&act.sa_mask);
+    act.sa_handler = lwpCatchAwaitedSig;
+    for (i = 0; i < NSIG; i++) {
+       if (sigismember(set, i))
+           sigaction(i, &act, NULL);
+    }
+}
+
+static void
+lwpCatchAwaitedSig(int sig)
+{
+    sigaddset(&LwpSigCatched, sig);
+}
+
+/*
+ * Test whether a signal from SET has been catched.
+ * If yes, delete that signal from the set of catched signals, and
+ * return its number.
+ * Else return 0.
+ */
+static int
+lwpGetSig(sigset_t *set)
+{
+    sigset_t save;
+    int i;
+
+    sigprocmask(SIG_BLOCK, set, &save);
+    for (i = NSIG - 1; i > 0; i--) {
+       if (sigismember(set, i) && sigismember(&LwpSigCatched, i)) {
+           lwpStatus(LwpCurrent, "Got awaited signal %d", i);
+           sigdelset(&LwpSigCatched, i);
+           break;
+       }
+    }
+    sigprocmask(SIG_SETMASK, &save, NULL);
+    return i;
+}
+
+/*
+ * 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
+ * without waiting.
+ */
+int
+lwpSigWait(sigset_t *set, int *sig)
+{
+    int res;
+
+    if (CANT_HAPPEN(LwpSigWaiter))
+       return EBUSY;
+    res = lwpGetSig(set);
+    if (res <= 0) {
+       lwpStatus(LwpCurrent, "Waiting for signals");
+       LwpSigAwaited = set;
+       LwpSigPtr = sig;
+       LwpSigWaiter = LwpCurrent;
+       lwpReschedule();
+       return 0;
+    }
+    *sig = res;
+    return 0;
+}
+
+/*
+ * Wake up the thread awaiting signals if one arrived.
+ * To be called from lwpReschedule().
+ */
+void
+lwpSigWakeup(void)
+{
+    int res;
+
+    if (!LwpSigWaiter)
+       return;
+    res = lwpGetSig(LwpSigAwaited);
+    if (res > 0) {
+       *LwpSigPtr = res;
+       lwpReady(LwpSigWaiter);
+       LwpSigWaiter = NULL;
+    }
+}
index d0a75241696ab284cee95cb4cedbfddf628800b1..1b5713416b19541ab69573d51d766bba9092d7cc 100644 (file)
@@ -261,7 +261,7 @@ main(int argc, char **argv)
 #endif /* !_WIN32 */
     start_server(flags);
 
-    empth_exit();
+    shutdwn(empth_wait_for_shutdown());
 
     CANT_REACH();
     finish_server();