]> git.pond.sub.org Git - empserver/blobdiff - src/lib/empthread/ntthread.c
Update copyright notice
[empserver] / src / lib / empthread / ntthread.c
index 29b018db181a447de812b1e876dd6df4e985f4cb..b1c66b2bc34114d4542ccb6373d8a3c33e3ef34b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *  Copyright (C) 1986-2009, Dave Pare, Jeff Bailey, Thomas Ruschak,
  *                           Ken Stevens, Steve McClure
  *
  *  This program is free software; you can redistribute it and/or modify
  *  ---
  *
  *  ntthread.c: Interface from Empire threads to Windows NT threads
- * 
+ *
  *  Known contributors to this file:
  *     Doug Hay, 1998
  *     Steve McClure, 1998
- *     Ron Koenderink, 2004-2007
+ *     Ron Koenderink, 2004-2008
  */
 
 /*
 #include <errno.h>
 #include <signal.h>
 #include <stdio.h>
+#include <stdarg.h>
 #include <sys/types.h>
 #include <time.h>
-#define WIN32
 #include <winsock2.h>
 #undef NS_ALL
 #include <windows.h>
 #include <process.h>
+/* Note: unistd.h(posixio.c) is not thread-safe.
+ * It may be used *only* while holding hThreadMutex.
+ */
+#include "unistd.h"
 #include "misc.h"
 #include "empthread.h"
 #include "prototypes.h"
+#include "server.h"
 
 #define loc_MIN_THREAD_STACK  16384
 
@@ -68,9 +73,7 @@
 struct loc_Thread {
 
     /* The thread name, passed in at create time. */
-    char szName[17];
-    /* The thread description, passed in at create time. */
-    char szDesc[80];
+    char *szName;
 
     /* True if this is the main line, and not a real thread. */
     BOOL bMainThread;
@@ -92,21 +95,6 @@ struct loc_Thread {
 };
 
 
-/************************
- * loc_Sem
- */
-struct loc_Sem {
-
-    /* The semaphore name, passed in at create time. */
-    char szName[17];
-
-    /* An Event that the thread(s) will sleep on. */
-    HANDLE hEvent;
-
-    /* The count variable */
-    int count;
-};
-
 /************************
  * loc_RWLock
  *
@@ -147,7 +135,7 @@ struct loc_Sem {
  *
  */
 struct loc_RWLock {
-    char name[17];     /* The thread name, passed in at create time. */
+    char *name;                /* The lock name, passed in at create time. */
     HANDLE can_read;   /* Manual event -- allows read locks */
     HANDLE can_write;  /* Auto-reset event -- allows write locks */
     int nread;         /* number of active readers */
@@ -184,6 +172,7 @@ static void **ppvUserData;
 /* Global flags.  From empth_init parameter. */
 static int global_flags;
 
+static void loc_debug(const char *, ...) ATTRIBUTE((format(printf, 1, 2)));
 
 /************************
  * loc_debug
@@ -235,6 +224,8 @@ loc_FreeThreadInfo(empth_t *pThread)
     if (pThread) {
        if (pThread->hThreadEvent)
            CloseHandle(pThread->hThreadEvent);
+       if (pThread->szName != NULL)
+           free(pThread->szName);
        memset(pThread, 0, sizeof(*pThread));
        free(pThread);
     }
@@ -310,15 +301,15 @@ loc_BlockThisThread(void)
  * System-Shutdown will initiate a shutdown.
  * This is done by calling empth_request_shutdown()
  */
-static BOOL
+static BOOL WINAPI
 loc_Exit_Handler(DWORD fdwCtrlType)
 {
-    switch (fdwCtrlType) { 
+    switch (fdwCtrlType) {
         case CTRL_C_EVENT:
         case CTRL_CLOSE_EVENT:
-        case CTRL_BREAK_EVENT: 
-        case CTRL_LOGOFF_EVENT: 
-        case CTRL_SHUTDOWN_EVENT: 
+        case CTRL_BREAK_EVENT:
+        case CTRL_LOGOFF_EVENT:
+        case CTRL_SHUTDOWN_EVENT:
            empth_request_shutdown();
             return TRUE;
         default:
@@ -331,12 +322,13 @@ loc_Exit_Handler(DWORD fdwCtrlType)
  *
  * This is the main line of each thread.
  * This is really a static local func....
+ * Note: As the POSIX compatibility layer is not thread safe
+ * this function can not open or create any files or sockets until
+ * loc_RunThisThread() is called
  */
 static void
 empth_threadMain(void *pvData)
 {
-    time_t now;
-
     empth_t *pThread = pvData;
 
     /* Out of here... */
@@ -352,10 +344,6 @@ empth_threadMain(void *pvData)
     /* Signal that the thread has started. */
     SetEvent(hThreadStartEvent);
 
-    /* seed the rand() function */
-    time(&now);
-    srand(now ^ (unsigned)pThread);
-
     /* Switch to this thread context */
     loc_RunThisThread(NULL);
 
@@ -407,7 +395,7 @@ empth_init(void **ctx_ptr, int flags)
         logerror("Failed to create shutdown event %lu", GetLastError());
        return 0;
     }
-    SetConsoleCtrlHandler((PHANDLER_ROUTINE)loc_Exit_Handler, TRUE);
+    SetConsoleCtrlHandler(loc_Exit_Handler, TRUE);
 
     /* Create the global Thread context. */
     pThread = malloc(sizeof(*pThread));
@@ -417,9 +405,7 @@ empth_init(void **ctx_ptr, int flags)
     }
     memset(pThread, 0, sizeof(*pThread));
 
-    strncpy(pThread->szName, "Main", sizeof(pThread->szName) - 1);
-    strncpy(pThread->szDesc, "The main process",
-           sizeof(pThread->szDesc) - 1);
+    pThread->szName = strdup("Main");
     pThread->ulThreadID = GetCurrentThreadId();
     pThread->bMainThread = TRUE;
 
@@ -438,35 +424,31 @@ empth_init(void **ctx_ptr, int flags)
  *
  * Create a new thread.
  *
- * prio  - priority, not particularly useful in our context.
  * entry - entry point function for thread.
  * size  - stack size.
  * flags - debug control.
  *           LWP_STACKCHECK  - not needed
  * name  - name of the thread, for debug.
- * desc  - description of thread, for debug.
  * ud    - "user data".  The "ctx_ptr" gets this value
  *         when the thread is active.
  *         It is also passed to the entry function...
  */
 empth_t *
-empth_create(int prio, void (*entry)(void *), int size, int flags,
-            char *name, char *desc, void *ud)
+empth_create(void (*entry)(void *), int size, int flags,
+            char *name, void *ud)
 {
     empth_t *pThread = NULL;
 
-    loc_debug("creating new thread %s:%s", name, desc);
+    loc_debug("creating new thread %s", name);
 
     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", name);
        return NULL;
     }
     memset(pThread, 0, sizeof(*pThread));
 
-    strncpy(pThread->szName, name, sizeof(pThread->szName) - 1);
-    strncpy(pThread->szDesc, desc, sizeof(pThread->szDesc) - 1);
+    pThread->szName = strdup(name);
     pThread->pvUserData = ud;
     pThread->pfnEntry = entry;
     pThread->bMainThread = FALSE;
@@ -478,9 +460,8 @@ empth_create(int prio, void (*entry)(void *), int size, int flags,
        size = loc_MIN_THREAD_STACK;
 
     pThread->ulThreadID = _beginthread(empth_threadMain, size, pThread);
-    if (pThread->ulThreadID == -1) {
-       logerror("can not create thread: %s (%s): %s",
-                name, desc, strerror(errno));
+    if (pThread->ulThreadID == 1L || pThread->ulThreadID == 0L) {
+       logerror("can not create thread: %s: %s", name, strerror(errno));
        goto bad;
     }
 
@@ -507,6 +488,27 @@ empth_self(void)
     return pThread;
 }
 
+/************************
+ * empth_name
+ */
+char *
+empth_name(empth_t *thread)
+{
+    return thread->szName;
+}
+
+/************************
+ * empth_set_name
+ * Set the thread name
+ */
+void
+empth_set_name(empth_t *thread, char *name)
+{
+    if (thread->szName != NULL)
+       free(thread->szName);
+    thread->szName = strdup(name);
+}
+
 /************************
  * empth_exit
  */
@@ -532,6 +534,7 @@ void
 empth_yield(void)
 {
     loc_BlockThisThread();
+    Sleep(0);
     loc_RunThisThread(NULL);
 }
 
@@ -557,11 +560,15 @@ empth_terminate(empth_t *pThread)
  *
  * This would be one of the main functions used within gen\io.c
  */
-void
-empth_select(int fd, int flags)
+int
+empth_select(int fd, int flags, struct timeval *timeout)
 {
+    int handle;
     WSAEVENT hEventObject[2];
+    long events;
+    DWORD result, msec;
     empth_t *pThread = TlsGetValue(dwTLSIndex);
+    int res;
 
     loc_debug("%s select on %d",
              flags == EMPTH_FD_READ ? "read" : "write", fd);
@@ -570,22 +577,40 @@ empth_select(int fd, int flags)
     hEventObject[0] = WSACreateEvent();
     hEventObject[1] = pThread->hThreadEvent;
 
-    if (flags == EMPTH_FD_READ)
-       WSAEventSelect(fd, hEventObject[0], FD_READ | FD_ACCEPT | FD_CLOSE);
-    else if (flags == EMPTH_FD_WRITE)
-       WSAEventSelect(fd, hEventObject[0], FD_WRITE | FD_CLOSE);
-    else {
-       logerror("bad flag %d passed to empth_select", flags);
-       empth_exit();
+    handle = posix_fd2socket(fd);
+    CANT_HAPPEN(handle < 0);
+
+    events = 0;
+    if (flags & EMPTH_FD_READ)
+       events |= FD_READ | FD_ACCEPT | FD_CLOSE;
+    if (flags & EMPTH_FD_WRITE)
+       events |= FD_WRITE | FD_CLOSE;
+    WSAEventSelect(handle, hEventObject[0], events);
+
+    if (timeout)
+       msec = timeout->tv_sec * 1000L + timeout->tv_usec / 1000L;
+    else
+       msec = WSA_INFINITE;
+    result = WSAWaitForMultipleEvents(2, hEventObject, FALSE, msec, FALSE);
+
+    switch (result) {
+    case WSA_WAIT_TIMEOUT:
+       res = 0;
+       break;
+    case WSA_WAIT_FAILED:
+       errno = WSAGetLastError();
+       res = -1;
+       break;
+    default:
+       res = 1;
     }
 
-    WSAWaitForMultipleEvents(2, hEventObject, FALSE, WSA_INFINITE, FALSE);
-
-    WSAEventSelect(fd, hEventObject[0], 0);
+    WSAEventSelect(handle, hEventObject[0], 0);
 
     WSACloseEvent(hEventObject[0]);
 
     loc_RunThisThread(NULL);
+    return res;
 }
 
 /************************
@@ -607,21 +632,26 @@ empth_wakeup(empth_t *pThread)
  *
  * Put the given thread to sleep...
  */
-void
+int
 empth_sleep(time_t until)
 {
-    long lSec;
+    long lSec = until - time(0) > 0 ? until - time(0) : 0;
+    empth_t *pThread = TlsGetValue(dwTLSIndex);
+    int iReturn = 0;
 
-    loc_BlockThisThread();
+    do {
+       loc_BlockThisThread();
+       loc_debug("going to sleep %ld sec", lSec);
 
-    while ((lSec = until - time(0)) > 0) {
-        loc_debug("going to sleep %ld sec", lSec);
-       Sleep(lSec * 1000L);
-    }
+       if (WaitForSingleObject(pThread->hThreadEvent, lSec * 1000L) !=
+           WAIT_TIMEOUT)
+           iReturn = -1;
 
-    loc_debug("sleep done. Waiting to run.");
+       loc_debug("sleep done. Waiting to run.");
+       loc_RunThisThread(NULL);
+    } while (!iReturn && ((lSec = until - time(0)) > 0));
 
-    loc_RunThisThread(NULL);
+    return iReturn;
 }
 
 /************************
@@ -641,67 +671,7 @@ empth_wait_for_signal(void)
 {
     loc_BlockThisThread();
     loc_RunThisThread(hShutdownEvent);
-    return 0;
-}
-
-/************************
- * empth_sem_create
- *
- * Create a signalling semaphore.
- */
-empth_sem_t *
-empth_sem_create(char *name, int cnt)
-{
-    empth_sem_t *pSem;
-
-    pSem = malloc(sizeof(*pSem));
-    if (!pSem) {
-       logerror("out of memory at %s:%d", __FILE__, __LINE__);
-       return NULL;
-    }
-
-    memset(pSem, 0, sizeof(pSem));
-    strncpy(pSem->szName, name, sizeof(pSem->szName) - 1);
-
-    pSem->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    pSem->count = cnt;
-
-    return pSem;
-}
-
-/************************
- * empth_sem_signal
- *
- * Hit/signal the specified semaphore.
- */
-void
-empth_sem_signal(empth_sem_t *pSem)
-{
-    loc_debug("signal on semaphore %s:%d", pSem->szName, pSem->count);
-
-    if (pSem->count++ < 0) {
-       SetEvent(pSem->hEvent);
-    }
-}
-
-/************************
- * empth_sem_wait
- *
- * Wait for the specified signal semaphore to be signaled.
- */
-void
-empth_sem_wait(empth_sem_t *pSem)
-{
-    empth_t *pThread = TlsGetValue(dwTLSIndex);
-
-    loc_debug("wait on semaphore %s:%d", pSem->szName, pSem->count);
-    if (--pSem->count < 0) {
-       /* Remove the thread from the running state. */
-       loc_BlockThisThread();
-       loc_debug("blocking");
-       loc_RunThisThread(pSem->hEvent);
-       loc_debug("waking up");
-    }
+    return SIGTERM;
 }
 
 empth_rwlock_t *
@@ -714,11 +684,12 @@ empth_rwlock_create(char *name)
        return NULL;
 
     memset(rwlock, 0, sizeof(*rwlock));
-    strncpy(rwlock->name, name, sizeof(rwlock->name) - 1);
+    rwlock->name = strdup(name);
 
     if ((rwlock->can_read = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL) {
        logerror("rwlock_create: failed to create reader event %s at %s:%d",
            name, __FILE__, __LINE__);
+       free(rwlock->name);
        free(rwlock);
        return NULL;
     }
@@ -726,6 +697,7 @@ empth_rwlock_create(char *name)
     if ((rwlock->can_write = CreateEvent(NULL, FALSE, TRUE, NULL)) == NULL) {
        logerror("rwlock_create: failed to create writer event %s at %s:%d",
            name, __FILE__, __LINE__);
+       free(rwlock->name);
        CloseHandle(rwlock->can_read);
        free(rwlock);
        return NULL;
@@ -738,6 +710,8 @@ empth_rwlock_destroy(empth_rwlock_t *rwlock)
 {
     if (CANT_HAPPEN(rwlock->nread || rwlock->nwrite))
        return;
+    if (rwlock->name != NULL)
+       free(rwlock->name);
     CloseHandle(rwlock->can_read);
     CloseHandle(rwlock->can_write);
     free(rwlock);