summaryrefslogtreecommitdiff
path: root/mtsupport.c
diff options
context:
space:
mode:
authorRuss Allbery <rra@debian.org>2013-07-21 13:49:36 -0700
committerRuss Allbery <rra@debian.org>2013-07-21 13:49:36 -0700
commit02afa49ca106bbd29895a61ce16c110d3d819b3d (patch)
tree5b1c86964e47ed31dca8c4f96fa9b88c48f28e0a /mtsupport.c
parent71a137c6c77cadddd4ed628cf0dcc310fbb32a49 (diff)
Imported Upstream version 1.01.003
Diffstat (limited to 'mtsupport.c')
-rw-r--r--mtsupport.c530
1 files changed, 530 insertions, 0 deletions
diff --git a/mtsupport.c b/mtsupport.c
new file mode 100644
index 0000000..5e3341d
--- /dev/null
+++ b/mtsupport.c
@@ -0,0 +1,530 @@
+/*
+ * multithread.c
+ *
+ * by Jon Kinsey, 2008
+ *
+ * Multithreaded operations
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 3 or later of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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
+ *
+ * $Id: mtsupport.c,v 1.1 2013/07/10 13:54:27 mdpetch Exp $
+ */
+
+#include "config.h"
+#include "multithread.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#if USE_GTK
+#include <gtk/gtk.h>
+#include <gtkgame.h>
+#endif
+
+#include "speed.h"
+#include "rollout.h"
+#include "util.h"
+#include "lib/simd.h"
+
+SSE_ALIGN(ThreadData td);
+
+extern ThreadLocalData *
+MT_CreateThreadLocalData(int id)
+{
+ ThreadLocalData *tld = (ThreadLocalData *)malloc(sizeof(ThreadLocalData));
+ tld->id = id;
+ tld->pnnState = (NNState *)malloc(sizeof(NNState)*3);
+ memset(tld->pnnState, 0, sizeof(NNState)*3);
+ tld->pnnState[CLASS_RACE - CLASS_RACE].savedBase = malloc(nnRace.cHidden * sizeof(float));
+ memset(tld->pnnState[CLASS_RACE - CLASS_RACE].savedBase, 0, nnRace.cHidden * sizeof(float));
+ tld->pnnState[CLASS_RACE - CLASS_RACE].savedIBase = malloc(nnRace.cInput * sizeof(float));
+ memset(tld->pnnState[CLASS_RACE - CLASS_RACE].savedIBase, 0, nnRace.cInput * sizeof(float));
+ tld->pnnState[CLASS_CRASHED - CLASS_RACE].savedBase = malloc(nnCrashed.cHidden * sizeof(float));
+ memset(tld->pnnState[CLASS_CRASHED - CLASS_RACE].savedBase, 0, nnCrashed.cHidden * sizeof(float));
+ tld->pnnState[CLASS_CRASHED - CLASS_RACE].savedIBase = malloc(nnCrashed.cInput * sizeof(float));
+ memset(tld->pnnState[CLASS_CRASHED - CLASS_RACE].savedIBase, 0, nnCrashed.cInput * sizeof(float));
+ tld->pnnState[CLASS_CONTACT - CLASS_RACE].savedBase = malloc(nnContact.cHidden * sizeof(float));
+ memset(tld->pnnState[CLASS_CONTACT - CLASS_RACE].savedBase, 0, nnContact.cHidden * sizeof(float));
+ tld->pnnState[CLASS_CONTACT - CLASS_RACE].savedIBase = malloc(nnContact.cInput * sizeof(float));
+ memset(tld->pnnState[CLASS_CONTACT - CLASS_RACE].savedIBase, 0, nnContact.cInput * sizeof(float));
+
+ tld->aMoves = (move *)malloc(sizeof(move)*MAX_INCOMPLETE_MOVES);
+ memset (tld->aMoves, 0, sizeof(move)*MAX_INCOMPLETE_MOVES);
+ return tld;
+}
+
+#if USE_MULTITHREAD
+
+#define UI_UPDATETIME 250
+
+#if defined(DEBUG_MULTITHREADED) && defined(WIN32)
+unsigned int mainThreadID;
+#endif
+
+
+#ifdef GLIB_THREADS
+#if GLIB_CHECK_VERSION (2,32,0)
+static GMutex condMutex; /* Extra mutex needed for waiting */
+#else
+GMutex *condMutex = NULL; /* Extra mutex needed for waiting */
+#endif
+GAsyncQueue *async_queue = NULL; /* Needed for async waiting */
+#endif
+
+#ifdef GLIB_THREADS
+
+#if GLIB_CHECK_VERSION (2,32,0)
+/* Dynamic allocation of GPrivate is deprecated */
+GPrivate private_item;
+
+extern void
+TLSCreate(TLSItem * pItem)
+{
+ *pItem = &private_item;
+}
+#else
+extern void
+TLSCreate(TLSItem * pItem)
+{
+ *pItem = g_private_new(g_free);
+}
+#endif
+
+extern void
+TLSFree(TLSItem UNUSED(pItem))
+{ /* Done automaticaly by glib */
+}
+
+extern void
+TLSSetValue(TLSItem pItem, size_t value)
+{
+ size_t *pNew = (size_t *) malloc(sizeof(size_t));
+ *pNew = value;
+ g_private_set(pItem, (gpointer) pNew);
+}
+
+#define TLSGet(item) *((size_t*)g_private_get(item))
+
+extern void
+InitManualEvent(ManualEvent * pME)
+{
+ ManualEvent pNewME = malloc(sizeof(*pNewME));
+#if GLIB_CHECK_VERSION (2,32,0)
+ g_cond_init(&pNewME->cond);
+#else
+ pNewME->cond = g_cond_new();
+#endif
+ pNewME->signalled = FALSE;
+ *pME = pNewME;
+}
+
+extern void
+FreeManualEvent(ManualEvent ME)
+{
+#if GLIB_CHECK_VERSION (2,32,0)
+ g_cond_clear(&ME->cond);
+#else
+ g_cond_free(ME->cond);
+#endif
+ free(ME);
+}
+
+extern void
+WaitForManualEvent(ManualEvent ME)
+{
+#if GLIB_CHECK_VERSION (2,32,0)
+ gint64 end_time;
+#else
+ GTimeVal tv;
+#endif
+ multi_debug("wait for manual event locks");
+#if GLIB_CHECK_VERSION (2,32,0)
+ g_mutex_lock(&condMutex);
+ end_time = g_get_monotonic_time() + 10 * G_TIME_SPAN_SECOND;
+#else
+ g_mutex_lock(condMutex);
+#endif
+ while (!ME->signalled) {
+ multi_debug("waiting for manual event");
+#if GLIB_CHECK_VERSION (2,32,0)
+ if (!g_cond_wait_until(&ME->cond, &condMutex, end_time))
+#else
+ g_get_current_time(&tv);
+ g_time_val_add(&tv, 10 * 1000 * 1000);
+ if (g_cond_timed_wait(ME->cond, condMutex, &tv))
+#endif
+ break;
+ else {
+ multi_debug("still waiting for manual event");
+ }
+ }
+
+#if GLIB_CHECK_VERSION (2,32,0)
+ g_mutex_unlock(&condMutex);
+#else
+ g_mutex_unlock(condMutex);
+#endif
+ multi_debug("wait for manual event unlocks");
+}
+
+extern void
+ResetManualEvent(ManualEvent ME)
+{
+ multi_debug("reset manual event locks");
+#if GLIB_CHECK_VERSION (2,32,0)
+ g_mutex_lock(&condMutex);
+ ME->signalled = FALSE;
+ g_mutex_unlock(&condMutex);
+#else
+ g_mutex_lock(condMutex);
+ ME->signalled = FALSE;
+ g_mutex_unlock(condMutex);
+#endif
+ multi_debug("reset manual event unlocks");
+}
+
+extern void
+SetManualEvent(ManualEvent ME)
+{
+ multi_debug("reset manual event locks");
+#if GLIB_CHECK_VERSION (2,32,0)
+ g_mutex_lock(&condMutex);
+ ME->signalled = TRUE;
+ g_cond_broadcast(&ME->cond);
+ g_mutex_unlock(&condMutex);
+#else
+ g_mutex_lock(condMutex);
+ ME->signalled = TRUE;
+ g_cond_broadcast(ME->cond);
+ g_mutex_unlock(condMutex);
+#endif
+ multi_debug("reset manual event unlocks");
+}
+
+#if GLIB_CHECK_VERSION (2,32,0)
+extern void
+InitMutex(Mutex * pMutex)
+{
+ g_mutex_init(pMutex);
+}
+
+extern void
+FreeMutex(Mutex mutex)
+{
+ g_mutex_clear(&mutex);
+}
+#else
+extern void
+InitMutex(Mutex * pMutex)
+{
+ *pMutex = g_mutex_new();
+}
+
+extern void
+FreeMutex(Mutex mutex)
+{
+ g_mutex_free(mutex);
+}
+#endif
+
+extern void
+Mutex_Lock(Mutex mutex, const char *reason)
+{
+#ifdef DEBUG_MULTITHREADED
+ multi_debug(reason);
+#else
+ (void) reason;
+#endif
+#if GLIB_CHECK_VERSION (2,32,0)
+ g_mutex_lock(&mutex);
+#else
+ g_mutex_lock(mutex);
+#endif
+}
+
+extern void
+Mutex_Release(Mutex mutex)
+{
+#ifdef DEBUG_MULTITHREADED
+ multi_debug("Releasing lock");
+#endif
+#if GLIB_CHECK_VERSION (2,32,0)
+ g_mutex_unlock(&mutex);
+#else
+ g_mutex_unlock(mutex);
+#endif
+}
+
+#else /* win32 */
+
+extern void
+TLSCreate(TLSItem * ppItem)
+{
+ *ppItem = TlsAlloc();
+ if (*ppItem == TLS_OUT_OF_INDEXES)
+ PrintSystemError("calling TlsAlloc");
+}
+
+extern void
+TLSFree(TLSItem pItem)
+{
+ free(TlsGetValue(pItem));
+ TlsFree(pItem);
+}
+
+extern void
+TLSSetValue(TLSItem pItem, int value)
+{
+ int *pNew = (int *) malloc(sizeof(int));
+ *pNew = value;
+ if (TlsSetValue(pItem, pNew) == 0)
+ PrintSystemError("calling TLSSetValue");
+}
+
+#define TLSGet(item) *((int*)TlsGetValue(item))
+
+extern void
+InitManualEvent(ManualEvent * pME)
+{
+ *pME = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (*pME == NULL)
+ PrintSystemError("creating manual event");
+}
+
+extern void
+FreeManualEvent(ManualEvent ME)
+{
+ CloseHandle(ME);
+}
+
+extern void
+InitMutex(Mutex * pMutex)
+{
+ *pMutex = CreateMutex(NULL, FALSE, NULL);
+ if (*pMutex == NULL)
+ PrintSystemError("creating mutex");
+}
+
+extern void
+FreeMutex(Mutex mutex)
+{
+ CloseHandle(mutex);
+}
+
+#ifdef DEBUG_MULTITHREADED
+void
+Mutex_Lock(Mutex mutex, const char *reason)
+{
+ if (WaitForSingleObject(mutex, 0) == WAIT_OBJECT_0) { /* Got mutex */
+ multi_debug("%s: lock acquired", reason);
+ } else {
+ multi_debug("%s: waiting on lock", reason);
+ WaitForSingleObject(mutex, INFINITE);
+ multi_debug("lock relinquished");
+ }
+}
+
+void
+Mutex_Release(Mutex mutex)
+{
+ multi_debug("Releasing lock");
+ ReleaseMutex(mutex);
+}
+
+#else
+#define Mutex_Lock(mutex, reason) WaitForSingleObject(mutex, INFINITE)
+#define Mutex_Release(mutex) ReleaseMutex(mutex)
+#endif
+
+#endif
+
+extern void
+MT_InitThreads(void)
+{
+#if !GLIB_CHECK_VERSION (2,32,0)
+ if (!g_thread_supported())
+ g_thread_init(NULL);
+ g_assert(g_thread_supported());
+#endif
+
+ td.tasks = NULL;
+ td.doneTasks = td.addedTasks = 0;
+ td.totalTasks = -1;
+ InitManualEvent(&td.activity);
+ TLSCreate(&td.tlsItem);
+ TLSSetValue(td.tlsItem, (size_t)MT_CreateThreadLocalData(0)); /* Main thread shares id 0 */
+
+#if defined(DEBUG_MULTITHREADED) && defined(WIN32)
+ mainThreadID = GetCurrentThreadId();
+#endif
+ InitMutex(&td.multiLock);
+ InitMutex(&td.queueLock);
+ InitManualEvent(&td.syncStart);
+ InitManualEvent(&td.syncEnd);
+#if defined(GLIB_THREADS) && !GLIB_CHECK_VERSION (2,32,0)
+ if (condMutex == NULL)
+ condMutex = g_mutex_new();
+#endif
+ td.numThreads = 0;
+}
+
+extern void
+CloseThread(void *UNUSED(unused))
+{
+ int i;
+ NNState *pnnState = ((ThreadLocalData *)TLSGet(td.tlsItem))->pnnState;
+
+ g_assert(td.closingThreads);
+ free(((ThreadLocalData *)TLSGet(td.tlsItem))->aMoves);
+ for (i = 0; i < 3; i++) {
+ free(pnnState[i].savedBase);
+ free(pnnState[i].savedIBase);
+ }
+ free(((ThreadLocalData *)TLSGet(td.tlsItem))->pnnState);
+ free((void *)TLSGet(td.tlsItem));
+ MT_SafeInc(&td.result);
+}
+
+/* Revisit this later for inclusion */
+#if 0
+extern void
+MT_CloseThreads(void)
+{
+ td.closingThreads = TRUE;
+ mt_add_tasks(td.numThreads, CloseThread, NULL, NULL);
+ if (MT_WaitForTasks(NULL, 0, FALSE) != (int) td.numThreads)
+ g_print("Error closing threads!\n");
+}
+#endif
+
+extern void
+MT_Close(void)
+{
+ MT_CloseThreads();
+
+ FreeManualEvent(td.activity);
+ FreeMutex(td.multiLock);
+ FreeMutex(td.queueLock);
+
+ FreeManualEvent(td.syncStart);
+ FreeManualEvent(td.syncEnd);
+ TLSFree(td.tlsItem);
+}
+
+extern void
+MT_Exclusive(void)
+{
+ Mutex_Lock(td.multiLock, "Exclusive lock");
+}
+
+extern void
+MT_Release(void)
+{
+ Mutex_Release(td.multiLock);
+}
+
+#ifdef DEBUG_MULTITHREADED
+extern void
+multi_debug(const char *str, ...)
+{
+ int id;
+ va_list vl;
+ char tn[5];
+ char buf[1024];
+
+ /* Sync output so order makes some sense */
+#ifdef WIN32
+ WaitForSingleObject(td.multiLock, INFINITE);
+#endif
+ /* With glib threads, locking here doesn't seem to work :
+ * GLib (gthread-posix.c): Unexpected error from C library during 'pthread_mutex_lock': Resource deadlock avoided. Aborting.
+ * Timestamp the output instead.
+ * Maybe the g_get_*_time() calls will sync output as well anyway... */
+
+ va_start(vl, str);
+ vsprintf(buf, str, vl);
+
+ id = MT_GetThreadID();
+#if defined(WIN32)
+ if (id == 0 && GetCurrentThreadId() == mainThreadID)
+#else
+ if (id == 0)
+#endif
+ strcpy(tn, "MT");
+ else
+ sprintf(tn, "T%d", id + 1);
+
+#ifdef GLIB_THREADS
+#if GLIB_CHECK_VERSION (2,28,0)
+ printf("%" G_GINT64_FORMAT " %s: %s\n", g_get_monotonic_time(), tn, buf);
+#else
+ {
+ GTimeVal tv;
+
+ g_get_current_time(&tv);
+ printf("%lu %s: %s\n", 1000000UL * tv.tv_sec + tv.tv_usec, tn, buf);
+ }
+#endif
+#else
+ printf("%s: %s\n", tn, buf);
+#endif
+
+#ifdef WIN32
+ ReleaseMutex(td.multiLock);
+#endif
+}
+
+#endif
+
+#else
+#include "multithread.h"
+#include <stdlib.h>
+#if USE_GTK
+#include <gtk/gtk.h>
+#include <gtkgame.h>
+#endif
+
+#define UI_UPDATETIME 250
+
+SSE_ALIGN(ThreadData td);
+
+extern void
+MT_InitThreads(void)
+{
+ td.tld = MT_CreateThreadLocalData(0); /* Main thread shares id 0 */
+}
+
+extern void
+MT_Close(void)
+{
+ int i;
+ NNState *pnnState;
+
+ if (!td.tld)
+ return;
+
+ free(td.tld->aMoves);
+ pnnState = td.tld->pnnState;
+ for (i = 0; i < 3; i++) {
+ free(pnnState[i].savedBase);
+ free(pnnState[i].savedIBase);
+ }
+ free(pnnState);
+ free(td.tld);
+}
+
+#endif
+
+