diff options
author | Russ Allbery <rra@debian.org> | 2013-07-21 13:49:36 -0700 |
---|---|---|
committer | Russ Allbery <rra@debian.org> | 2013-07-21 13:49:36 -0700 |
commit | 02afa49ca106bbd29895a61ce16c110d3d819b3d (patch) | |
tree | 5b1c86964e47ed31dca8c4f96fa9b88c48f28e0a /mtsupport.c | |
parent | 71a137c6c77cadddd4ed628cf0dcc310fbb32a49 (diff) |
Imported Upstream version 1.01.003
Diffstat (limited to 'mtsupport.c')
-rw-r--r-- | mtsupport.c | 530 |
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 + + |