/*
* Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2005, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
* Ken Stevens, Steve McClure
*
* This program is free software; you can redistribute it and/or modify
*
* ---
*
- * See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
- * related information and legal notices. It is expected that any future
- * projects/authors will amend these files as needed.
+ * 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.
*
* ---
*
* Known contributors to this file:
* Doug Hay, 1998
* Steve McClure, 1998
+ * Ron Koenderink, 2004-2005
*/
/*
* WIN32 has a full pre-emptive threading environment. But Empire can
* not handle pre-emptive threading. Thus, we will use the threads,
* but limit the preemption using a Mutex semaphore.
- *
*/
+#include <config.h>
+
+#include <errno.h>
+#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
-#include <signal.h>
-#include <errno.h>
-#include "misc.h"
-#include "empthread.h"
-#include "prototypes.h"
-
-#if defined(_WIN32) && defined(_EMPTH_WIN32)
+#include <time.h>
#define WIN32
#include <winsock2.h>
#undef NS_ALL
#include <windows.h>
#include <process.h>
+#include "misc.h"
+#include "empthread.h"
+#include "prototypes.h"
#define loc_MIN_THREAD_STACK 16384
/************************
* loc_Thread_t
- *
- * The REAL empth_t thread structure.
- * The external world only gets a void pointer to this.
*/
-typedef struct loc_Thread_t {
+struct loc_Thread_t {
/* The thread name, passed in at create time. */
char szName[17];
/* An Event sem that the thread will wait/sleep on. */
HANDLE hThreadEvent;
-} loc_Thread_t;
+};
/************************
* loc_Sem_t
- *
- * The REAL empth_sem_t structure.
- * The external world only gets a void pointer to this.
*/
-typedef struct empth_sem_t {
+struct loc_Sem_t {
char szName[17];
HANDLE hEvent;
/* The count variable */
int count;
-} loc_Sem_t;
+};
-static struct {
- /* This is the thread exclusion/non-premption mutex. */
- /* The running thread has this MUTEX, and all others are */
- /* either blocked on it, or waiting for some OS response. */
- HANDLE hThreadMutex;
+/* This is the thread exclusion/non-premption mutex. */
+/* The running thread has this MUTEX, and all others are */
+/* either blocked on it, or waiting for some OS response. */
+static HANDLE hThreadMutex;
- /* This is the thread startup event sem. */
- /* We use this to lockstep when we are starting up threads. */
- HANDLE hThreadStartEvent;
+/* This is the thread startup event sem. */
+/* We use this to lockstep when we are starting up threads. */
+static HANDLE hThreadStartEvent;
- /* This is an event used to wakeup the main thread */
- /* to start the shutdown sequence. */
- HANDLE hShutdownEvent;
+/* This is an event used to wakeup the main thread */
+/* to start the shutdown sequence. */
+static HANDLE hShutdownEvent;
- /* The Thread Local Storage index. We store the pThread pointer */
- /* for each thread at this index. */
- DWORD dwTLSIndex;
+/* The Thread Local Storage index. We store the pThread pointer */
+/* for each thread at this index. */
+static DWORD dwTLSIndex;
- /* The current running thread. */
- loc_Thread_t *pCurThread;
+/* The current running thread. */
+static empth_t *pCurThread;
- /* Ticks at start */
- unsigned long ulTickAtStart;
+/* Ticks at start */
+static unsigned long ulTickAtStart;
- /* Pointer out to global context. "player". */
- /* From empth_init parameter. */
- void **ppvUserData;
+/* Pointer out to global context. "player". */
+/* From empth_init parameter. */
+static void **ppvUserData;
- /* Global flags. From empth_init parameter. */
- int flags;
-} loc_GVAR;
+/* Global flags. From empth_init parameter. */
+static int global_flags;
/************************
unsigned long ulCurTick;
unsigned long ulRunTick;
unsigned long ulMs, ulSec, ulMin, ulHr;
- loc_Thread_t *pThread =
- (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
+ empth_t *pThread = TlsGetValue(dwTLSIndex);
char buf[1024];
- if ((loc_GVAR.flags & EMPTH_PRINT) != 0) {
+ if ((global_flags & EMPTH_PRINT) != 0) {
/* Ticks are in milliseconds */
ulCurTick = GetTickCount();
- ulRunTick = ulCurTick - loc_GVAR.ulTickAtStart;
+ ulRunTick = ulCurTick - ulTickAtStart;
ulMs = ulRunTick % 1000L;
ulSec = (ulRunTick / 1000L) % 60L;
ulMin = (ulRunTick / (60L * 1000L)) % 60L;
/************************
* loc_FreeThreadInfo
- *
*/
static void
-loc_FreeThreadInfo(loc_Thread_t *pThread)
+loc_FreeThreadInfo(empth_t *pThread)
{
if (pThread) {
if (pThread->hThreadEvent)
* info, and the thread owns the MUTEX sem.
*/
static void
-loc_RunThisThread()
+loc_RunThisThread(void)
{
- loc_Thread_t *pThread =
- (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
+ empth_t *pThread = TlsGetValue(dwTLSIndex);
if (pThread->bKilled) {
if (!pThread->bMainThread) {
- TlsSetValue(loc_GVAR.dwTLSIndex, NULL);
+ TlsSetValue(dwTLSIndex, NULL);
loc_FreeThreadInfo(pThread);
_endthread();
}
}
/* Get the MUTEX semaphore, wait forever. */
- WaitForSingleObject(loc_GVAR.hThreadMutex, INFINITE);
+ WaitForSingleObject(hThreadMutex, INFINITE);
- if (!loc_GVAR.pCurThread) {
+ if (!pCurThread) {
/* Set the globals to this thread. */
- *loc_GVAR.ppvUserData = pThread->pvUserData;
+ *ppvUserData = pThread->pvUserData;
- loc_GVAR.pCurThread = pThread;
+ pCurThread = pThread;
} else {
/* Hmm, a problem, eh? */
logerror("RunThisThread, someone already running.");
* This thread was running. It no longer wants to.
*/
static void
-loc_BlockThisThread()
+loc_BlockThisThread(void)
{
- loc_Thread_t *pThread =
- (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
+ empth_t *pThread = TlsGetValue(dwTLSIndex);
- if (loc_GVAR.pCurThread == pThread) {
+ if (pCurThread == pThread) {
/* Reset the globals back to original */
- loc_GVAR.pCurThread = NULL;
- *loc_GVAR.ppvUserData = NULL;
+ pCurThread = NULL;
+ *ppvUserData = NULL;
/* Release the MUTEX */
- ReleaseMutex(loc_GVAR.hThreadMutex);
+ ReleaseMutex(hThreadMutex);
} else {
/* Hmm, this thread was not the running one. */
logerror("BlockThisThread, not running.");
static BOOL
loc_Exit_Handler(DWORD fdwCtrlType)
{
- switch (fdwCtrlType)
- {
+ switch (fdwCtrlType) {
case CTRL_C_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_BREAK_EVENT:
}
}
-/************************
- * 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(loc_GVAR.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(loc_GVAR.hShutdownEvent, INFINITE);
-}
-
/************************
* empth_threadMain
*
* This is the main line of each thread.
* This is really a static local func....
*/
-void
+static void
empth_threadMain(void *pvData)
{
time_t now;
- loc_Thread_t *pThread = (loc_Thread_t *)pvData;
+ empth_t *pThread = pvData;
/* Out of here... */
if (!pvData)
return;
/* Store pThread on this thread. */
- TlsSetValue(loc_GVAR.dwTLSIndex, pvData);
+ TlsSetValue(dwTLSIndex, pvData);
/* Get the ID of the thread. */
pThread->ulThreadID = GetCurrentThreadId();
/* Signal that the thread has started. */
- SetEvent(loc_GVAR.hThreadStartEvent);
+ SetEvent(hThreadStartEvent);
/* seed the rand() function */
time(&now);
- srand(now ^ (unsigned int)pThread);
+ srand(now ^ (unsigned)pThread);
/* Switch to this thread context */
loc_RunThisThread();
int
empth_init(void **ctx_ptr, int flags)
{
- loc_Thread_t *pThread = NULL;
+ empth_t *pThread = NULL;
- loc_GVAR.ulTickAtStart = GetTickCount();
- loc_GVAR.ppvUserData = ctx_ptr;
- loc_GVAR.flags = flags;
- loc_GVAR.dwTLSIndex = TlsAlloc();
+ ulTickAtStart = GetTickCount();
+ ppvUserData = ctx_ptr;
+ global_flags = flags;
+ dwTLSIndex = TlsAlloc();
/* Create the thread mutex sem. */
/* Initally unowned. */
- loc_GVAR.hThreadMutex = CreateMutex(NULL, FALSE, NULL);
- if (!loc_GVAR.hThreadMutex) {
- logerror("Failed to create mutex %d", GetLastError());
+ hThreadMutex = CreateMutex(NULL, FALSE, NULL);
+ if (!hThreadMutex) {
+ logerror("Failed to create mutex %lu", GetLastError());
return 0;
}
/* Create the thread start event sem. */
/* Automatic state reset. */
- loc_GVAR.hThreadStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!loc_GVAR.hThreadStartEvent) {
- logerror("Failed to create start event %d", GetLastError());
+ hThreadStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!hThreadStartEvent) {
+ logerror("Failed to create start event %lu", GetLastError());
return 0;
}
/* Create the shutdown event for the main thread. */
/* Manual reset */
- loc_GVAR.hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!loc_GVAR.hShutdownEvent) {
- logerror("Failed to create shutdown event %d", GetLastError());
+ hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!hShutdownEvent) {
+ logerror("Failed to create shutdown event %lu", GetLastError());
return 0;
}
SetConsoleCtrlHandler((PHANDLER_ROUTINE)loc_Exit_Handler, TRUE);
pThread->ulThreadID = GetCurrentThreadId();
pThread->bMainThread = TRUE;
- TlsSetValue(loc_GVAR.dwTLSIndex, pThread);
+ TlsSetValue(dwTLSIndex, pThread);
/* Make this the running thread. */
loc_RunThisThread();
empth_create(int prio, void (*entry)(void *), int size, int flags,
char *name, char *desc, void *ud)
{
- loc_Thread_t *pThread = NULL;
+ empth_t *pThread = NULL;
loc_debug("creating new thread %s:%s", name, desc);
pThread = malloc(sizeof(*pThread));
if (!pThread) {
- logerror("not enough memory to create thread: %s (%s)", name,
- desc);
+ logerror("not enough memory to create thread: %s (%s)",
+ name, desc);
return NULL;
}
memset(pThread, 0, sizeof(*pThread));
pThread->ulThreadID = _beginthread(empth_threadMain, size, pThread);
if (pThread->ulThreadID == -1) {
- logerror("can not create thread: %s (%s): %s", name, desc,
- strerror(errno));
+ logerror("can not create thread: %s (%s): %s",
+ name, desc, strerror(errno));
goto bad;
}
loc_debug("new thread id is %ld", pThread->ulThreadID);
+ empth_yield();
return pThread;
bad:
empth_t *
empth_self(void)
{
- loc_Thread_t *pThread =
- (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
+ empth_t *pThread = TlsGetValue(dwTLSIndex);
return pThread;
}
void
empth_exit(void)
{
- loc_Thread_t *pThread =
- (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
-
- loc_BlockThisThread();
+ empth_t *pThread = TlsGetValue(dwTLSIndex);
loc_debug("empth_exit");
+ loc_BlockThisThread();
- if (pThread->bMainThread) {
- loc_BlockMainThread();
- loc_RunThisThread();
- shutdwn(0);
- } else {
- TlsSetValue(loc_GVAR.dwTLSIndex, NULL);
- loc_FreeThreadInfo(pThread);
- _endthread();
- }
+ TlsSetValue(dwTLSIndex, NULL);
+ loc_FreeThreadInfo(pThread);
+ _endthread();
}
/************************
* Kill off the thread.
*/
void
-empth_terminate(empth_t *a)
+empth_terminate(empth_t *pThread)
{
- loc_Thread_t *pThread = (loc_Thread_t *)a;
-
loc_debug("killing thread %s", pThread->szName);
pThread->bKilled = TRUE;
empth_select(int fd, int flags)
{
WSAEVENT hEventObject[2];
- loc_Thread_t *pThread =
- (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
+ empth_t *pThread = TlsGetValue(dwTLSIndex);
loc_debug("%s select on %d",
flags == EMPTH_FD_READ ? "read" : "write", fd);
loc_RunThisThread();
}
-/************************
- * empth_alarm
- */
-void
-empth_alarm(int sig)
-{
- loc_Thread_t *pThread =
- (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
-
- loc_debug("got alarm signal %d", sig);
-
- /* Let it run if it is blocked like... */
- SetEvent(pThread->hThreadEvent);
-}
-
/************************
* empth_wakeup
*
* Wake up the specified thread.
*/
void
-empth_wakeup(empth_t *a)
+empth_wakeup(empth_t *pThread)
{
- loc_Thread_t *pThread = (loc_Thread_t *)a;
-
loc_debug("waking up thread %s", pThread->szName);
/* Let it run if it is blocked... */
loc_RunThisThread();
}
+/************************
+ * empth_request_shutdown
+ *
+ * This wakes up empth_wait_for_signal() so shutdown can proceed.
+ * This is done by signalling hShutdownEvent.
+ */
+void
+empth_request_shutdown(void)
+{
+ SetEvent(hShutdownEvent);
+}
+
+int
+empth_wait_for_signal(void)
+{
+ loc_BlockThisThread();
+
+ /* Get the MUTEX semaphore, wait the number of MS */
+ WaitForSingleObject(hShutdownEvent, INFINITE);
+
+ loc_RunThisThread();
+ return 0;
+}
/************************
* empth_sem_create
empth_sem_t *
empth_sem_create(char *name, int cnt)
{
- loc_Sem_t *pSem;
+ empth_sem_t *pSem;
pSem = malloc(sizeof(*pSem));
if (!pSem) {
* Hit/signal the specified semaphore.
*/
void
-empth_sem_signal(empth_sem_t *sm)
+empth_sem_signal(empth_sem_t *pSem)
{
- loc_Sem_t *pSem = (loc_Sem_t *)sm;
-
loc_debug("signal on semaphore %s:%d", pSem->szName, pSem->count);
/* Wait for the Semaphore */
* Wait for the specified signal semaphore to be signaled.
*/
void
-empth_sem_wait(empth_sem_t *sm)
+empth_sem_wait(empth_sem_t *pSem)
{
- loc_Thread_t *pThread =
- (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
- loc_Sem_t *pSem = (loc_Sem_t *)sm;
+ empth_t *pThread = TlsGetValue(dwTLSIndex);
loc_debug("wait on semaphore %s:%d", pSem->szName, pSem->count);
loc_RunThisThread();
}
-
-#endif /* _WIN32 */