Pthread support from Gwl.

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3041 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
Meep-Eep
2008-08-21 20:03:54 +00:00
parent f726de4474
commit aa02a78da5
11 changed files with 846 additions and 9 deletions
+1
View File
@@ -1,4 +1,5 @@
Changes towards version 0.7: Changes towards version 0.7:
- Pthread support - Gwl
- Content Dirs completely reorganized; 3DO and PC segregation - Coredev - Content Dirs completely reorganized; 3DO and PC segregation - Coredev
- Voiceovers controlled by a synthetic '3dovoice' addon - Michael - Voiceovers controlled by a synthetic '3dovoice' addon - Michael
- CONVERSATION explicitly names text/voice/timestamps - Michael - CONVERSATION explicitly names text/voice/timestamps - Michael
+4 -1
View File
@@ -44,6 +44,7 @@ uqm_HAVE_REGEX='@HAVE_REGEX_H_FLAG@'
uqm_HAVE_OPENGL='@HAVE_OPENGL@' uqm_HAVE_OPENGL='@HAVE_OPENGL@'
uqm_USE_ZIP_IO='@USE_ZIP_IO@' uqm_USE_ZIP_IO='@USE_ZIP_IO@'
uqm_USE_PLATFORM_ACCEL='@USE_PLATFORM_ACCEL@' uqm_USE_PLATFORM_ACCEL='@USE_PLATFORM_ACCEL@'
uqm_THREADLIB='@THREADLIB@'
uqm_NETPLAY='@NETPLAY@' uqm_NETPLAY='@NETPLAY@'
uqm_USE_WINSOCK='@USE_WINSOCK@' uqm_USE_WINSOCK='@USE_WINSOCK@'
DEBUG='@DEBUG@' DEBUG='@DEBUG@'
@@ -52,4 +53,6 @@ MACRO___MINGW32__='@MACRO___MINGW32__@'
export BUILD_SYSTEM HOST_SYSTEM DEBUG export BUILD_SYSTEM HOST_SYSTEM DEBUG
export MACRO_WIN32 MACRO___MINGW32__ export MACRO_WIN32 MACRO___MINGW32__
export uqm_SOUNDMODULE uqm_USE_INTERNAL_MIKMOD uqm_HAVE_REGEX uqm_USE_WINSOCK export uqm_SOUNDMODULE uqm_USE_INTERNAL_MIKMOD uqm_HAVE_REGEX uqm_USE_WINSOCK
export uqm_HAVE_OPENGL uqm_USE_ZIP_IO uqm_USE_PLATFORM_ACCEL uqm_NETPLAY export uqm_HAVE_OPENGL uqm_USE_ZIP_IO uqm_USE_PLATFORM_ACCEL uqm_THREADLIB
export uqm_NETPLAY
+28 -2
View File
@@ -70,7 +70,7 @@ uqm_prepare_config()
{ {
# Describe the menu: # Describe the menu:
MENU_main_ITEMS="debug graphics sound mikmod ovcodec netplay joystick \ MENU_main_ITEMS="debug graphics sound mikmod ovcodec netplay joystick \
ioformat accel" ioformat accel threadlib"
case "$HOST_SYSTEM" in case "$HOST_SYSTEM" in
Darwin) Darwin)
# Installation directory not modifiable # Installation directory not modifiable
@@ -92,6 +92,7 @@ uqm_prepare_config()
MENU_main_ITEM_joystick_TYPE=CHOICE MENU_main_ITEM_joystick_TYPE=CHOICE
MENU_main_ITEM_ioformat_TYPE=CHOICE MENU_main_ITEM_ioformat_TYPE=CHOICE
MENU_main_ITEM_accel_TYPE=CHOICE MENU_main_ITEM_accel_TYPE=CHOICE
MENU_main_ITEM_threadlib_TYPE=CHOICE
MENU_main_ITEM_install_path_TYPE=MENU MENU_main_ITEM_install_path_TYPE=MENU
CHOICE_debug_OPTIONS="nodebug debug strictdebug" CHOICE_debug_OPTIONS="nodebug debug strictdebug"
@@ -290,6 +291,31 @@ uqm_prepare_config()
} }
CHOICE_accel_DEFAULT=asm CHOICE_accel_DEFAULT=asm
CHOICE_threadlib_OPTIONS="sdl pthread"
CHOICE_threadlib_TITLE="Thread library"
CHOICE_threadlib_OPTION_sdl_TITLE="SDL-controlled thread library"
CHOICE_threadlib_OPTION_sdl_ACTION="threadlib_sdl_action"
threadlib_sdl_action() {
CFLAGS="$CFLAGS -DTHREADLIB_SDL"
THREADLIB="SDL"
}
CHOICE_threadlib_OPTION_pthread_TITLE="Pthread thread library"
CHOICE_threadlib_OPTION_pthread_PRECOND="have_library pthread"
CHOICE_threadlib_OPTION_pthread_ACTION="threadlib_pthread_action"
threadlib_pthread_action() {
CFLAGS="$CFLAGS -DTHREADLIB_PTHREAD"
THREADLIB="PTHREAD"
use_library pthread
}
case "$HOST_SYSTEM" in
ARMV5|WINSCW)
CHOICE_threadlib_DEFAULT=pthread
;;
*)
CHOICE_threadlib_DEFAULT=sdl
;;
esac
MENU_install_path_ITEMS="install_prefix install_bindir install_libdir \ MENU_install_path_ITEMS="install_prefix install_bindir install_libdir \
install_sharedir" install_sharedir"
MENU_install_path_TITLE="Installation paths" MENU_install_path_TITLE="Installation paths"
@@ -359,7 +385,7 @@ uqm_process_config() {
MAKE ECHON SED DEBUG JOYSTICK NETPLAY \ MAKE ECHON SED DEBUG JOYSTICK NETPLAY \
OGGVORBIS SOUNDMODULE USE_INTERNAL_MIKMOD \ OGGVORBIS SOUNDMODULE USE_INTERNAL_MIKMOD \
HAVE_OPENGL HAVE_REGEX_H_FLAG USE_ZIP_IO \ HAVE_OPENGL HAVE_REGEX_H_FLAG USE_ZIP_IO \
USE_PLATFORM_ACCEL USE_WINSOCK \ USE_PLATFORM_ACCEL THREADLIB USE_WINSOCK \
INSTALL_LIBDIR INSTALL_BINDIR INSTALL_SHAREDIR \ INSTALL_LIBDIR INSTALL_BINDIR INSTALL_SHAREDIR \
REZ WINDRES $HAVE_SYMBOLS" REZ WINDRES $HAVE_SYMBOLS"
SUBSTITUTE_FILES="build.vars" SUBSTITUTE_FILES="build.vars"
+4
View File
@@ -1007,6 +1007,10 @@ set_host_system() {
HOST_SYSTEM="QNX" ;; HOST_SYSTEM="QNX" ;;
[Cc][Ee][Gg][Cc][Cc]) [Cc][Ee][Gg][Cc][Cc])
HOST_SYSTEM="cegcc" ;; HOST_SYSTEM="cegcc" ;;
[Ww][Ii][Nn][Ss][Cc][Ww])
HOST_SYSTEM="WINSCW" ;;
[Aa][Rr][Mm][Vv]5)
HOST_SYSTEM="ARMV5" ;;
*) *)
build_message "Warning: host type '$BUILD_HOST' unknown. Using defaults." build_message "Warning: host type '$BUILD_HOST' unknown. Using defaults."
;; ;;
+21
View File
@@ -222,6 +222,27 @@ LIB_zlib_DETECT="try_pkgconfig_lib zlib zlib"
LIB_zlib_DEPEND_DETECT_BIN="pkgconfig" LIB_zlib_DEPEND_DETECT_BIN="pkgconfig"
### pthread ###
LIB_pthread_NAME="pthread"
case "$HOST_SYSTEM" in
Linux)
LIB_pthread_CFLAGS=""
LIB_pthread_LDFLAGS=""
LIB_pthread_VERSION=""
;;
FreeBSD|OpenBSD)
LIB_pthread_CFLAGS="$(pthread-config --cflags)"
LIB_pthread_LDFLAGS="$(pthread-config --ldflags)"
LIB_pthread_VERSION="$(pthread-config --version)"
;;
*)
LIB_pthread_CFLAGS=""
LIB_pthread_LDFLAGS="-lpthread"
LIB_pthread_VERSION=""
;;
esac
# Additional platform-specific libraries for networking. # Additional platform-specific libraries for networking.
LIB_netlibs_NAME="Platform-specific network libraries" LIB_netlibs_NAME="Platform-specific network libraries"
case "$HOST_SYSTEM" in case "$HOST_SYSTEM" in
-2
View File
@@ -20,8 +20,6 @@
#ifndef _THREADLIB_H #ifndef _THREADLIB_H
#define _THREADLIB_H #define _THREADLIB_H
#define THREADLIB SDL
#define NAMED_SYNCHRO /* Should synchronizable objects have names? */ #define NAMED_SYNCHRO /* Should synchronizable objects have names? */
#define TRACK_CONTENTION /* Should we report when a thread sleeps on synchronize? */ #define TRACK_CONTENTION /* Should we report when a thread sleeps on synchronize? */
+7
View File
@@ -1,2 +1,9 @@
case "$uqm_THREADLIB" in
SDL)
uqm_SUBDIRS="sdl" uqm_SUBDIRS="sdl"
;;
PTHREAD)
uqm_SUBDIRS="pthread"
;;
esac
uqm_CFILES="thrcommon.c" uqm_CFILES="thrcommon.c"
@@ -0,0 +1 @@
uqm_CFILES="posixthreads.c"
@@ -0,0 +1,671 @@
/*
* This program 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
* (at your option) any later version.
*
* 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.
*/
#include <stdlib.h>
#include "misc.h"
#include "posixthreads.h"
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include "libs/log/uqmlog.h"
typedef struct _thread {
pthread_t native;
#ifdef NAMED_SYNCHRO
const char *name;
#endif
ThreadLocal *localData;
struct _thread *next;
} *TrueThread;
static volatile TrueThread threadQueue = NULL;
static pthread_mutex_t threadQueueMutex;
struct ThreadStartInfo
{
ThreadFunction func;
void *data;
sem_t sem;
TrueThread thread;
};
void
InitThreadSystem_PT (void)
{
pthread_mutex_init (&threadQueueMutex, NULL);
}
void
UnInitThreadSystem_PT (void)
{
pthread_mutex_destroy (&threadQueueMutex);
}
static void
QueueThread (TrueThread thread)
{
pthread_mutex_lock (&threadQueueMutex);
thread->next = threadQueue;
threadQueue = thread;
pthread_mutex_unlock (&threadQueueMutex);
}
static void
UnQueueThread (TrueThread thread)
{
volatile TrueThread *ptr;
pthread_mutex_lock (&threadQueueMutex);
ptr = &threadQueue;
while (*ptr != thread)
{
#ifdef DEBUG_THREADS
if (*ptr == NULL)
{
// Should not happen.
log_add (log_Debug, "Error: Trying to remove non-present thread "
"from thread queue.");
fflush (stderr);
explode ();
}
#endif /* DEBUG_THREADS */
ptr = &(*ptr)->next;
}
*ptr = (*ptr)->next;
pthread_mutex_unlock (&threadQueueMutex);
}
static TrueThread
FindThreadInfo (pthread_t threadID)
{
TrueThread ptr;
pthread_mutex_lock (&threadQueueMutex);
ptr = threadQueue;
while (ptr)
{
if (ptr->native == threadID)
{
pthread_mutex_unlock (&threadQueueMutex);
return ptr;
}
ptr = ptr->next;
}
pthread_mutex_unlock (&threadQueueMutex);
return NULL;
}
#ifdef NAMED_SYNCHRO
static const char *
MyThreadName (void)
{
TrueThread t = FindThreadInfo (pthread_self());
return t ? t->name : "Unknown (probably renderer)";
}
#endif
static void *
ThreadHelper (void *startInfo) {
ThreadFunction func;
void *data;
sem_t *sem;
TrueThread thread;
int result;
//log_add (log_Debug, "ThreadHelper()");
func = ((struct ThreadStartInfo *) startInfo)->func;
data = ((struct ThreadStartInfo *) startInfo)->data;
sem = &((struct ThreadStartInfo *) startInfo)->sem;
// Wait until the Thread structure is available.
if (sem_wait (sem))
{
log_add(log_Fatal, "ThreadHelper sem_wait fail");
exit(EXIT_FAILURE);
}
if (sem_destroy (sem))
{
log_add(log_Fatal, "ThreadHelper sem_destroy fail");
exit(EXIT_FAILURE);
}
thread = ((struct ThreadStartInfo *) startInfo)->thread;
HFree (startInfo);
result = (*func) (data);
#ifdef DEBUG_THREADS
log_add (log_Debug, "Thread '%s' done (returned %d).",
thread->name, result);
fflush (stderr);
#endif
UnQueueThread (thread);
DestroyThreadLocal (thread->localData);
FinishThread (thread);
/* Destroying the thread is the responsibility of ProcessThreadLifecycles() */
return (void*)result;
}
void
DestroyThread_PT (Thread t)
{
HFree (t);
}
Thread
CreateThread_PT (ThreadFunction func, void *data, SDWORD stackSize
#ifdef NAMED_SYNCHRO
, const char *name
#endif
)
{
TrueThread thread;
struct ThreadStartInfo *startInfo;
pthread_attr_t attr;
//log_add (log_Debug, "CreateThread_PT '%s'", name);
thread = (struct _thread *) HMalloc (sizeof *thread);
#ifdef NAMED_SYNCHRO
thread->name = name;
#endif
thread->localData = CreateThreadLocal ();
startInfo = (struct ThreadStartInfo *) HMalloc (sizeof (*startInfo));
startInfo->func = func;
startInfo->data = data;
if (sem_init(&startInfo->sem, 0, 0) < 0)
{
log_add (log_Fatal, "createthread seminit fail");
exit(EXIT_FAILURE);
}
startInfo->thread = thread;
pthread_attr_init(&attr);
if (pthread_attr_setstacksize(&attr, 75000))
{
log_add (log_Debug, "pthread stacksize fail");
}
if (pthread_create(&thread->native, &attr, ThreadHelper, (void *)startInfo))
{
log_add (log_Debug, "pthread create fail");
DestroyThreadLocal (thread->localData);
HFree (startInfo);
HFree (thread);
return NULL;
}
// The responsibility to free 'startInfo' and 'thread' is now by the new
// thread.
QueueThread (thread);
#ifdef DEBUG_THREADS
//#if 0
log_add (log_Debug, "Thread '%s' created.", thread->name);
fflush (stderr);
//#endif
#endif
// Signal to the new thread that the thread structure is ready
// and it can begin to use it.
if (sem_post (&startInfo->sem))
{
log_add(log_Fatal, "CreateThread sem_post fail");
exit(EXIT_FAILURE);
}
(void) stackSize; /* Satisfying compiler (unused parameter) */
return thread;
}
void
SleepThread_PT (TimeCount sleepTime)
{
usleep (sleepTime * 1000000 / ONE_SECOND);
}
void
SleepThreadUntil_PT (TimeCount wakeTime) {
TimeCount now;
now = GetTimeCounter ();
if (wakeTime <= now)
TaskSwitch_PT ();
else
usleep ((wakeTime - now) * 1000000 / ONE_SECOND);
}
void
TaskSwitch_PT (void) {
usleep (1000);
}
void
WaitThread_PT (Thread thread, int *status) {
//log_add(log_Debug, "WaitThread_PT '%s', status %x", ((TrueThread)thread)->name, status);
//pthread_join(((TrueThread)thread)->native, status);
pthread_join(((TrueThread)thread)->native, NULL);
//log_add(log_Debug, "WaitThread_PT '%s' complete", ((TrueThread)thread)->name);
}
ThreadLocal *
GetMyThreadLocal_PT (void)
{
TrueThread t = FindThreadInfo (pthread_self());
return t ? t->localData : NULL;
}
/* These are the pthread implementations of the UQM synchronization objects. */
/* Mutexes. */
/* TODO. The w_memlib uses Mutexes right now, so we can't use HMalloc
* or HFree. Once that goes, this needs to change. */
typedef struct _mutex {
pthread_mutex_t mutex;
#ifdef TRACK_CONTENTION
pthread_t owner;
#endif
#ifdef NAMED_SYNCHRO
const char *name;
DWORD syncClass;
#endif
} Mut;
Mutex
#ifdef NAMED_SYNCHRO
CreateMutex_PT (const char *name, DWORD syncClass)
#else
CreateMutex_PT (void)
#endif
{
Mut *mutex = malloc (sizeof (Mut));
if (mutex != NULL)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
if (pthread_mutex_init(&mutex->mutex, &attr))
{
#ifdef NAMED_SYNCHRO
/* logging depends on Mutexes, so we have to use the
* non-threaded version instead */
log_add_nothread (log_Fatal, "Could not initialize mutex '%s':"
"aborting.", name);
#else
log_add_nothread (log_Fatal, "Could not initialize mutex:"
"aborting.");
#endif
exit (EXIT_FAILURE);
}
pthread_mutexattr_destroy(&attr);
#ifdef TRACK_CONTENTION
mutex->owner = 0;
#endif
#ifdef NAMED_SYNCHRO
mutex->name = name;
mutex->syncClass = syncClass;
#endif
}
return mutex;
}
void
DestroyMutex_PT (Mutex m)
{
Mut *mutex = (Mut *)m;
//log_add_nothread(log_Debug, "Destroying mutex '%s'", mutex->name);
pthread_mutex_destroy (&mutex->mutex);
free (mutex);
}
void
LockMutex_PT (Mutex m)
{
Mut *mutex = (Mut *)m;
#ifdef TRACK_CONTENTION
/* This code isn't really quite right; race conditions between
* check and lock remain and can produce reports of contention
* where the thread never sleeps, or fail to report in
* situations where it does. If tracking with perfect
* accuracy becomes important, the TRACK_CONTENTION mutex will
* need to handle its own wake/sleep cycles with condition
* variables (check the history of this file for the
* CrossThreadMutex code). This almost-measure is being added
* because for the most part it should suffice. */
if (mutex->owner && (mutex->syncClass & TRACK_CONTENTION_CLASSES))
{ /* logging depends on Mutexes, so we have to use the
* non-threaded version instead */
log_add_nothread (log_Debug, "Thread '%s' blocking on mutex '%s'",
MyThreadName (), mutex->name);
}
#endif
while (pthread_mutex_lock (&mutex->mutex) != 0)
{
//log_add_nothread (log_Debug, "Attempt to acquire mutex '%s' failretry", mutex->name);
TaskSwitch_PT ();
}
#ifdef TRACK_CONTENTION
mutex->owner = pthread_self();
#endif
}
void
UnlockMutex_PT (Mutex m)
{
Mut *mutex = (Mut *)m;
#ifdef TRACK_CONTENTION
mutex->owner = 0;
#endif
while (pthread_mutex_unlock (&mutex->mutex) != 0)
{
TaskSwitch_PT ();
}
}
/* Semaphores. */
typedef struct _sem {
sem_t sem;
#ifdef NAMED_SYNCHRO
const char *name;
DWORD syncClass;
#endif
} Sem;
Semaphore
CreateSemaphore_PT (DWORD initial
#ifdef NAMED_SYNCHRO
, const char *name, DWORD syncClass
#endif
)
{
Sem *sem = (Sem *) HMalloc (sizeof (struct _sem));
#ifdef NAMED_SYNCHRO
sem->name = name;
sem->syncClass = syncClass;
#endif
//log_add (log_Debug, "Creating semaphore '%s'", sem->name);
if (sem_init(&sem->sem, 0, initial) < 0)
{
#ifdef NAMED_SYNCHRO
log_add (log_Fatal, "Could not initialize semaphore '%s':"
" aborting.", name);
#else
log_add (log_Fatal, "Could not initialize semaphore:"
" aborting.");
#endif
exit (EXIT_FAILURE);
}
//log_add (log_Debug, "Creating semaphore '%s' success", sem->name);
return sem;
}
void
DestroySemaphore_PT (Semaphore s)
{
Sem *sem = (Sem *)s;
//log_add (log_Debug, "Destroying semaphore '%s'", sem->name);
if (sem_destroy (&sem->sem))
{
log_add (log_Debug, "Destroying semaphore '%s' failed", sem->name);
}
HFree (sem);
}
void
SetSemaphore_PT (Semaphore s)
{
Sem *sem = (Sem *)s;
#ifdef TRACK_CONTENTION
int contention = 0;
sem_getvalue(&sem->sem, &contention);
contention = !contention;
if (contention && (sem->syncClass & TRACK_CONTENTION_CLASSES))
{
log_add (log_Debug, "Thread '%s' blocking on semaphore '%s'",
MyThreadName (), sem->name);
}
#endif
//log_add (log_Debug, "Attempt to set semaphore '%s'", sem->name);
while (sem_wait (&sem->sem) == -1)
{
//log_add (log_Debug, "Attempt to set semaphore '%s' failretry", sem->name);
TaskSwitch_PT ();
}
//log_add (log_Debug, "Attempt to set semaphore '%s' success", sem->name);
#ifdef TRACK_CONTENTION
if (contention && (sem->syncClass & TRACK_CONTENTION_CLASSES))
{
log_add (log_Debug, "Thread '%s' awakens,"
" released from semaphore '%s'", MyThreadName (), sem->name);
}
#endif
}
void
ClearSemaphore_PT (Semaphore s)
{
Sem *sem = (Sem *)s;
//log_add (log_Debug, "Attempt to clear semaphore '%s' %x", sem->name, sem);
while (sem_post (&sem->sem) == -1)
{
//log_add (log_Debug, "Attempt to clear semaphore %x failretry", sem);
TaskSwitch_PT ();
}
//log_add (log_Debug, "Attempt to clear semaphore %x success", sem);
}
/* Recursive mutexes. Adapted from mixSDL code, which was adapted from
the original DCQ code. */
typedef struct _recm {
pthread_mutex_t mutex;
pthread_t thread_id;
unsigned int locks;
#ifdef NAMED_SYNCHRO
const char *name;
DWORD syncClass;
#endif
} RecM;
RecursiveMutex
#ifdef NAMED_SYNCHRO
CreateRecursiveMutex_PT (const char *name, DWORD syncClass)
#else
CreateRecursiveMutex_PT (void)
#endif
{
RecM *mtx = (RecM *) HMalloc (sizeof (struct _recm));
mtx->thread_id = 0;
if (pthread_mutex_init(&mtx->mutex, NULL))
{
#ifdef NAMED_SYNCHRO
log_add (log_Fatal, "Could not initialize recursive "
"mutex '%s': aborting.", name);
#else
log_add (log_Fatal, "Could not initialize recursive "
"mutex: aborting.");
#endif
exit (EXIT_FAILURE);
}
#ifdef NAMED_SYNCHRO
mtx->name = name;
mtx->syncClass = syncClass;
#endif
mtx->locks = 0;
return (RecursiveMutex) mtx;
}
void
DestroyRecursiveMutex_PT (RecursiveMutex val)
{
RecM *mtx = (RecM *)val;
pthread_mutex_destroy(&mtx->mutex);
HFree (mtx);
}
void
LockRecursiveMutex_PT (RecursiveMutex val)
{
RecM *mtx = (RecM *)val;
pthread_t thread_id = pthread_self();
if (!mtx->locks || mtx->thread_id != thread_id)
{
#ifdef TRACK_CONTENTION
if (mtx->thread_id && (mtx->syncClass & TRACK_CONTENTION_CLASSES))
{
log_add (log_Debug, "Thread '%s' blocking on '%s'",
MyThreadName (), mtx->name);
}
#endif
while (pthread_mutex_lock (&mtx->mutex))
TaskSwitch_PT ();
mtx->thread_id = thread_id;
}
mtx->locks++;
}
void
UnlockRecursiveMutex_PT (RecursiveMutex val)
{
RecM *mtx = (RecM *)val;
pthread_t thread_id = pthread_self();
if (!mtx->locks || mtx->thread_id != thread_id)
{
#ifdef NAMED_SYNCHRO
log_add (log_Debug, "'%s' attempted to unlock %s when it "
"didn't hold it", MyThreadName (), mtx->name);
#endif
}
else
{
mtx->locks--;
if (!mtx->locks)
{
mtx->thread_id = 0;
pthread_mutex_unlock (&mtx->mutex);
}
}
}
int
GetRecursiveMutexDepth_PT (RecursiveMutex val)
{
RecM *mtx = (RecM *)val;
return mtx->locks;
}
typedef struct _cond {
pthread_cond_t cond;
pthread_mutex_t mutex;
#ifdef NAMED_SYNCHRO
const char *name;
DWORD syncClass;
#endif
} cvar;
CondVar
#ifdef NAMED_SYNCHRO
CreateCondVar_PT (const char *name, DWORD syncClass)
#else
CreateCondVar_PT (void)
#endif
{
int err1, err2;
cvar *cv = (cvar *) HMalloc (sizeof (cvar));
err1 = pthread_cond_init(&cv->cond, NULL);
err2 = pthread_mutex_init(&cv->mutex, NULL);
if (err1 || err2)
{
#ifdef NAMED_SYNCHRO
log_add (log_Fatal, "Could not initialize condition variable '%s':"
" aborting.", name);
#else
log_add (log_Fatal, "Could not initialize condition variable:"
" aborting.");
#endif
exit (EXIT_FAILURE);
}
#ifdef NAMED_SYNCHRO
cv->name = name;
cv->syncClass = syncClass;
#endif
return cv;
}
void
DestroyCondVar_PT (CondVar c)
{
cvar *cv = (cvar *) c;
pthread_cond_destroy(&cv->cond);
pthread_mutex_destroy(&cv->mutex);
HFree (cv);
}
void
WaitCondVar_PT (CondVar c)
{
cvar *cv = (cvar *) c;
pthread_mutex_lock (&cv->mutex);
#ifdef TRACK_CONTENTION
if (cv->syncClass & TRACK_CONTENTION_CLASSES)
{
log_add (log_Debug, "Thread '%s' waiting for signal from '%s'",
MyThreadName (), cv->name);
}
#endif
while (pthread_cond_wait (&cv->cond, &cv->mutex) != 0)
{
TaskSwitch_PT ();
}
#ifdef TRACK_CONTENTION
if (cv->syncClass & TRACK_CONTENTION_CLASSES)
{
log_add (log_Debug, "Thread '%s' received signal from '%s',"
" awakening.", MyThreadName (), cv->name);
}
#endif
pthread_mutex_unlock (&cv->mutex);
}
void
SignalCondVar_PT (CondVar c)
{
cvar *cv = (cvar *) c;
pthread_cond_signal(&cv->cond);
}
void
BroadcastCondVar_PT (CondVar c)
{
cvar *cv = (cvar *) c;
pthread_cond_broadcast(&cv->cond);
}
@@ -0,0 +1,103 @@
/*
* This program 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
* (at your option) any later version.
*
* 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.
*/
#ifndef _UQMPTHREADS_H
#define _UQMPTHREADS_H
#include "port.h"
#include "libs/threadlib.h"
void InitThreadSystem_PT (void);
void UnInitThreadSystem_PT (void);
#ifdef NAMED_SYNCHRO
/* Prototypes with the "name" field */
Thread CreateThread_PT (ThreadFunction func, void *data, SDWORD stackSize, const char *name);
Mutex CreateMutex_PT (const char *name, DWORD syncClass);
Semaphore CreateSemaphore_PT (DWORD initial, const char *name, DWORD syncClass);
RecursiveMutex CreateRecursiveMutex_PT (const char *name, DWORD syncClass);
CondVar CreateCondVar_PT (const char *name, DWORD syncClass);
#else
/* Prototypes without the "name" field. */
Thread CreateThread_PT (ThreadFunction func, void *data, SDWORD stackSize);
Mutex CreateMutex_PT (void);
Semaphore CreateSemaphore_PT (DWORD initial);
RecursiveMutex CreateRecursiveMutex_PT (void);
CondVar CreateCondVar_PT (void);
#endif
ThreadLocal *GetMyThreadLocal_PT (void);
void SleepThread_PT (TimeCount sleepTime);
void SleepThreadUntil_PT (TimeCount wakeTime);
void TaskSwitch_PT (void);
void WaitThread_PT (Thread thread, int *status);
void DestroyThread_PT (Thread thread);
void DestroyMutex_PT (Mutex m);
void LockMutex_PT (Mutex m);
void UnlockMutex_PT (Mutex m);
void DestroySemaphore_PT (Semaphore sem);
void SetSemaphore_PT (Semaphore sem);
void ClearSemaphore_PT (Semaphore sem);
void DestroyCondVar_PT (CondVar c);
void WaitCondVar_PT (CondVar c);
void SignalCondVar_PT (CondVar c);
void BroadcastCondVar_PT (CondVar c);
void DestroyRecursiveMutex_PT (RecursiveMutex m);
void LockRecursiveMutex_PT (RecursiveMutex m);
void UnlockRecursiveMutex_PT (RecursiveMutex m);
int GetRecursiveMutexDepth_PT (RecursiveMutex m);
#define NativeInitThreadSystem InitThreadSystem_PT
#define NativeUnInitThreadSystem UnInitThreadSystem_PT
#define NativeGetMyThreadLocal GetMyThreadLocal_PT
#define NativeCreateThread CreateThread_PT
#define NativeSleepThread SleepThread_PT
#define NativeSleepThreadUntil SleepThreadUntil_PT
#define NativeTaskSwitch TaskSwitch_PT
#define NativeWaitThread WaitThread_PT
#define NativeDestroyThread DestroyThread_PT
#define NativeCreateMutex CreateMutex_PT
#define NativeDestroyMutex DestroyMutex_PT
#define NativeLockMutex LockMutex_PT
#define NativeUnlockMutex UnlockMutex_PT
#define NativeCreateSemaphore CreateSemaphore_PT
#define NativeDestroySemaphore DestroySemaphore_PT
#define NativeSetSemaphore SetSemaphore_PT
#define NativeClearSemaphore ClearSemaphore_PT
#define NativeCreateCondVar CreateCondVar_PT
#define NativeDestroyCondVar DestroyCondVar_PT
#define NativeWaitCondVar WaitCondVar_PT
#define NativeSignalCondVar SignalCondVar_PT
#define NativeBroadcastCondVar BroadcastCondVar_PT
#define NativeCreateRecursiveMutex CreateRecursiveMutex_PT
#define NativeDestroyRecursiveMutex DestroyRecursiveMutex_PT
#define NativeLockRecursiveMutex LockRecursiveMutex_PT
#define NativeUnlockRecursiveMutex UnlockRecursiveMutex_PT
#define NativeGetRecursiveMutexDepth GetRecursiveMutexDepth_PT
#endif /* _PTTHREAD_H */
+4 -2
View File
@@ -18,9 +18,11 @@
#define _THRCOMMON_H #define _THRCOMMON_H
#if THREADLIB == SDL #if defined(THREADLIB_SDL)
# include "sdl/sdlthreads.h" # include "sdl/sdlthreads.h"
#endif /* THREADLIB == SDL */ #elif defined(THREADLIB_PTHREAD)
# include "pthread/posixthreads.h"
#endif /* defined(THREADLIB_PTHREAD) */
#endif /* _THR_COMMON_H */ #endif /* _THR_COMMON_H */