]> git.pond.sub.org Git - empserver/blobdiff - src/lib/empthread/ntthread.c
Spell ID and UID consistently all-caps
[empserver] / src / lib / empthread / ntthread.c
index 88192db02d547b46ce2b6f2793491596a8aece3f..c53c9892eea90c12abd9703eb6e2c5ad188d6946 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  Empire - A multi-player, client/server Internet based war game.
- *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
- *                           Ken Stevens, Steve McClure
+ *  Copyright (C) 1986-2017, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *                Ken Stevens, Steve McClure, Markus Armbruster
  *
- *  This program is free software; you can redistribute it and/or modify
+ *  Empire 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
+ *  the Free Software Foundation, either version 3 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
  *  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
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  *  ---
  *
  *  ---
  *
  *  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-2009
  */
 
 /*
 #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>
 #include "misc.h"
 #include "empthread.h"
+#include "file.h"
 #include "prototypes.h"
+#include "server.h"
+#include "sys/socket.h"
 
 #define loc_MIN_THREAD_STACK  16384
 
@@ -68,9 +68,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;
@@ -78,9 +76,6 @@ struct loc_Thread {
     /* The user data passed in at create time. */
     void *pvUserData;
 
-    /* True if this thread has been killed. */
-    BOOL bKilled;
-
     /* The entry function for the thread. */
     void (*pfnEntry) (void *);
 
@@ -93,23 +88,7 @@ struct loc_Thread {
 
 
 /************************
- * loc_Sem
- */
-struct loc_Sem {
-
-    char szName[17];
-
-    /* An exclusion semaphore for this sem. */
-    HANDLE hMutex;
-    /* An Event that the thread(s) will sleep on. */
-
-    HANDLE hEvent;
-    /* The count variable */
-    int count;
-};
-
-/************************
- * loc_RWLock_t
+ * loc_RWLock
  *
  * Invariants
  *     must hold at function call, return, sleep
@@ -118,7 +97,7 @@ struct loc_Sem {
  * any state:
  *     nwrite >= 0
  *     nread >= 0
-
+ *
  * if unlocked:
  *     can_read set
  *     can_write set
@@ -147,8 +126,8 @@ struct loc_Sem {
  * thread changing it holds hThreadMutex.
  *
  */
-struct loc_RWLock_t {
-    char name[17];     /* The thread name, passed in at create time. */
+struct loc_RWLock {
+    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 */
@@ -185,6 +164,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
@@ -236,7 +216,8 @@ loc_FreeThreadInfo(empth_t *pThread)
     if (pThread) {
        if (pThread->hThreadEvent)
            CloseHandle(pThread->hThreadEvent);
-       memset(pThread, 0, sizeof(*pThread));
+       if (pThread->szName != NULL)
+           free(pThread->szName);
        free(pThread);
     }
 }
@@ -255,14 +236,6 @@ loc_RunThisThread(HANDLE hWaitObject)
 
     empth_t *pThread = TlsGetValue(dwTLSIndex);
 
-    if (pThread->bKilled) {
-       if (!pThread->bMainThread) {
-           TlsSetValue(dwTLSIndex, NULL);
-           loc_FreeThreadInfo(pThread);
-           _endthread();
-       }
-    }
-
     hWaitObjects[0] = hThreadMutex;
     hWaitObjects[1] = hWaitObject;
 
@@ -311,19 +284,19 @@ 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) { 
-        case CTRL_C_EVENT:
-        case CTRL_CLOSE_EVENT:
-        case CTRL_BREAK_EVENT: 
-        case CTRL_LOGOFF_EVENT: 
-        case CTRL_SHUTDOWN_EVENT: 
-           empth_request_shutdown();
-            return TRUE;
-        default:
-            return FALSE;
+    switch (fdwCtrlType) {
+    case CTRL_C_EVENT:
+    case CTRL_CLOSE_EVENT:
+    case CTRL_BREAK_EVENT:
+    case CTRL_LOGOFF_EVENT:
+    case CTRL_SHUTDOWN_EVENT:
+       empth_request_shutdown();
+       return TRUE;
+    default:
+       return FALSE;
     }
 }
 
@@ -332,12 +305,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... */
@@ -353,10 +327,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);
 
@@ -405,10 +375,10 @@ empth_init(void **ctx_ptr, int flags)
     /* Manual reset */
     hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (!hShutdownEvent) {
-        logerror("Failed to create shutdown event %lu", GetLastError());
+       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));
@@ -418,9 +388,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;
 
@@ -429,7 +397,6 @@ empth_init(void **ctx_ptr, int flags)
     /* Make this the running thread. */
     loc_RunThisThread(NULL);
 
-    logerror("NT pthreads initialized");
     return 0;
 }
 
@@ -439,35 +406,32 @@ 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);
+    ef_make_stale();
 
     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;
@@ -479,17 +443,16 @@ 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;
     }
 
-    loc_debug("new thread id is %ld", pThread->ulThreadID);
+    loc_debug("new thread ID is %ld", pThread->ulThreadID);
     empth_yield();
     return pThread;
 
-  bad:
+bad:
     if (pThread) {
        loc_FreeThreadInfo(pThread);
     }
@@ -503,9 +466,28 @@ empth_create(int prio, void (*entry)(void *), int size, int flags,
 empth_t *
 empth_self(void)
 {
-    empth_t *pThread = TlsGetValue(dwTLSIndex);
+    return ppvUserData ? TlsGetValue(dwTLSIndex) : NULL;
+}
 
-    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);
 }
 
 /************************
@@ -517,6 +499,7 @@ empth_exit(void)
     empth_t *pThread = TlsGetValue(dwTLSIndex);
 
     loc_debug("empth_exit");
+    ef_make_stale();
     loc_BlockThisThread();
 
     TlsSetValue(dwTLSIndex, NULL);
@@ -532,24 +515,12 @@ empth_exit(void)
 void
 empth_yield(void)
 {
+    ef_make_stale();
     loc_BlockThisThread();
+    Sleep(0);
     loc_RunThisThread(NULL);
 }
 
-/************************
- * empth_terminate
- *
- * Kill off the thread.
- */
-void
-empth_terminate(empth_t *pThread)
-{
-    loc_debug("killing thread %s", pThread->szName);
-    pThread->bKilled = TRUE;
-
-    SetEvent(pThread->hThreadEvent);
-}
-
 /************************
  * empth_select
  *
@@ -558,35 +529,64 @@ 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)
 {
+    SOCKET sock;
     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);
+    ef_make_stale();
     loc_BlockThisThread();
 
     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();
+    sock = w32_fd2socket(fd);
+    CANT_HAPPEN(sock == (SOCKET)-1);
+
+    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(sock, 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_EVENT_0:
+       res = 1;
+       break;
+    case WSA_WAIT_EVENT_0 + 1:
+    case WSA_WAIT_TIMEOUT:
+       res = 0;
+       break;
+    case WSA_WAIT_FAILED:
+       w32_set_winsock_errno();
+       res = -1;
+       break;
+    default:
+       CANT_REACH();
+       errno = EINVAL;
+       res = -1;
     }
 
-    WSAWaitForMultipleEvents(2, hEventObject, FALSE, WSA_INFINITE, FALSE);
-
-    WSAEventSelect(fd, hEventObject[0], 0);
+    WSAEventSelect(sock, hEventObject[0], 0);
 
     WSACloseEvent(hEventObject[0]);
 
     loc_RunThisThread(NULL);
+    return res;
 }
 
 /************************
@@ -608,21 +608,28 @@ empth_wakeup(empth_t *pThread)
  *
  * Put the given thread to sleep...
  */
-void
+int
 empth_sleep(time_t until)
 {
+    time_t now;
     long lSec;
+    empth_t *pThread = TlsGetValue(dwTLSIndex);
+    DWORD result;
 
+    ef_make_stale();
     loc_BlockThisThread();
 
-    while ((lSec = until - time(0)) > 0) {
-        loc_debug("going to sleep %ld sec", lSec);
-       Sleep(lSec * 1000L);
-    }
+    do {
+       now = time(NULL);
+       lSec = until >= now ? until - now : 0;
+       loc_debug("going to sleep %ld sec", lSec);
+       result = WaitForSingleObject(pThread->hThreadEvent, lSec * 1000L);
+    } while (result != WAIT_TIMEOUT && result != WAIT_OBJECT_0);
 
     loc_debug("sleep done. Waiting to run.");
-
     loc_RunThisThread(NULL);
+
+    return result == WAIT_TIMEOUT ? 0 : -1;
 }
 
 /************************
@@ -640,85 +647,10 @@ empth_request_shutdown(void)
 int
 empth_wait_for_signal(void)
 {
+    ef_make_stale();
     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->hMutex = CreateMutex(NULL, FALSE, NULL);
-    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);
-
-    /* Wait for the Semaphore */
-    WaitForSingleObject(pSem->hMutex, INFINITE);
-
-    if (pSem->count++ < 0) {
-       SetEvent(pSem->hEvent);
-    }
-
-    ReleaseMutex(pSem->hMutex);
-}
-
-/************************
- * 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);
-
-    /* Remove the thread from the running state. */
-    loc_BlockThisThread();
-
-    /* Wait for the Semaphore */
-    WaitForSingleObject(pSem->hMutex, INFINITE);
-    if (--pSem->count < 0) {
-       loc_debug("blocking");
-       ReleaseMutex(pSem->hMutex);
-
-       WaitForSingleObject(pSem->hEvent, INFINITE);
-
-       loc_debug("waking up");
-    } else
-       ReleaseMutex(pSem->hMutex);
-
-    loc_RunThisThread(NULL);
+    return SIGTERM;
 }
 
 empth_rwlock_t *
@@ -731,18 +663,20 @@ 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__);
+                name, __FILE__, __LINE__);
+       free(rwlock->name);
        free(rwlock);
        return NULL;
     }
 
     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__);
+                name, __FILE__, __LINE__);
+       free(rwlock->name);
        CloseHandle(rwlock->can_read);
        free(rwlock);
        return NULL;
@@ -755,6 +689,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);
@@ -763,6 +699,7 @@ empth_rwlock_destroy(empth_rwlock_t *rwlock)
 void
 empth_rwlock_wrlock(empth_rwlock_t *rwlock)
 {
+    ef_make_stale();
     /* block any new readers */
     ResetEvent(rwlock->can_read);
     rwlock->nwrite++;
@@ -774,6 +711,7 @@ empth_rwlock_wrlock(empth_rwlock_t *rwlock)
 void
 empth_rwlock_rdlock(empth_rwlock_t *rwlock)
 {
+    ef_make_stale();
     loc_BlockThisThread();
     loc_RunThisThread(rwlock->can_read);
     ResetEvent(rwlock->can_write);
@@ -785,7 +723,7 @@ empth_rwlock_unlock(empth_rwlock_t *rwlock)
 {
     if (CANT_HAPPEN(!rwlock->nread && !rwlock->nwrite))
        return;
-   if (rwlock->nread) { /* holding read lock */
+    if (rwlock->nread) {       /* holding read lock */
        rwlock->nread--;
        if (rwlock->nread == 0)
            SetEvent(rwlock->can_write);