(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().
/*
* 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);
*/
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.
#ifndef LWP_H
#define LWP_H
+#include <signal.h>
#include "misc.h"
#define LWP_STACKCHECK 0x1
#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);
#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;
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;
}
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();
}
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)
}
}
-/************************
- * 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
*
{
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();
}
/************************
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
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);
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;
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);
}
}
-
static void
empth_alarm(int sig)
{
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)
lwpStackCheck(LwpCurrent);
}
+ lwpSigWakeup();
+
/* destroy dead threads */
lwpStatus(LwpCurrent, "Cleaning dead queue");
while (NULL != (nextp = lwpGetFirst(&LwpDeadQ))) {
* 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;
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);
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
--- /dev/null
+/*
+ * 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;
+ }
+}
#endif /* !_WIN32 */
start_server(flags);
- empth_exit();
+ shutdwn(empth_wait_for_shutdown());
CANT_REACH();
finish_server();