From 7183516d915229b0dd9c146e4d67cb9c5cd8da1b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 7 Jun 2006 21:01:16 +0000 Subject: [PATCH] (empth_init_signals): Don't catch SIGINT and SIGTERM. (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 | 9 +++ include/lwp.h | 3 +- src/lib/empthread/lwp.c | 41 ++++++---- src/lib/empthread/ntthread.c | 61 ++++++-------- src/lib/empthread/posix.c | 3 - src/lib/empthread/pthread.c | 41 ++++++---- src/lib/lwp/lwp.c | 5 +- src/lib/lwp/lwpint.h | 4 +- src/lib/lwp/sig.c | 153 +++++++++++++++++++++++++++++++++++ src/server/main.c | 2 +- 10 files changed, 251 insertions(+), 71 deletions(-) create mode 100644 src/lib/lwp/sig.c diff --git a/include/empthread.h b/include/empthread.h index 4c952b405..172e89a0d 100644 --- a/include/empthread.h +++ b/include/empthread.h @@ -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. diff --git a/include/lwp.h b/include/lwp.h index dbb253315..303ee3ceb 100644 --- a/include/lwp.h +++ b/include/lwp.h @@ -24,6 +24,7 @@ #ifndef LWP_H #define LWP_H +#include #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); diff --git a/src/lib/empthread/lwp.c b/src/lib/empthread/lwp.c index 6c5cbe83a..077c57728 100644 --- a/src/lib/empthread/lwp.c +++ b/src/lib/empthread/lwp.c @@ -33,12 +33,10 @@ #include +#include #include #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) diff --git a/src/lib/empthread/ntthread.c b/src/lib/empthread/ntthread.c index 1f420fa78..3942cbe6d 100644 --- a/src/lib/empthread/ntthread.c +++ b/src/lib/empthread/ntthread.c @@ -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 diff --git a/src/lib/empthread/posix.c b/src/lib/empthread/posix.c index 5ec66438a..015080ed3 100644 --- a/src/lib/empthread/posix.c +++ b/src/lib/empthread/posix.c @@ -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); diff --git a/src/lib/empthread/pthread.c b/src/lib/empthread/pthread.c index 045fbb2e8..f3503cf8e 100644 --- a/src/lib/empthread/pthread.c +++ b/src/lib/empthread/pthread.c @@ -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) diff --git a/src/lib/lwp/lwp.c b/src/lib/lwp/lwp.c index 0205738a2..217246a39 100644 --- a/src/lib/lwp/lwp.c +++ b/src/lib/lwp/lwp.c @@ -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); diff --git a/src/lib/lwp/lwpint.h b/src/lib/lwp/lwpint.h index 9e905b5f5..2f1edcd7c 100644 --- a/src/lib/lwp/lwpint.h +++ b/src/lib/lwp/lwpint.h @@ -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 index 000000000..9800a97ba --- /dev/null +++ b/src/lib/lwp/sig.c @@ -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 + +#include +#include +#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; + } +} diff --git a/src/server/main.c b/src/server/main.c index d0a752416..1b5713416 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -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(); -- 2.43.0