#ifdef _WIN32 /* windows.h needs to be the top-most header usually */ # include #endif #include "std_testcase.h" #ifdef _WIN32 # include #else # include #endif #include "std_thread.h" struct _stdThread { #ifdef _WIN32 uintptr_t handle; #else pthread_t handle; #endif stdThreadRoutine start; void *args; }; #ifdef __cplusplus extern "C" { #endif #ifdef _WIN32 static unsigned __stdcall internal_start(void *args) #else static void *internal_start(void *args) #endif { stdThread thread = (stdThread)args; thread->start(thread->args); #ifdef _WIN32 _endthreadex(0); /* dead code, but return to avoid warnings */ return 0; #else pthread_exit(NULL); /* dead code, but return to avoid warnings */ return NULL; #endif } int stdThreadCreate(stdThreadRoutine start, void *args, stdThread *thread) { #ifdef _WIN32 uintptr_t handle; #else pthread_t handle; #endif stdThread my_thread; *thread = NULL; my_thread = (stdThread)malloc(sizeof(*my_thread)); if (my_thread == NULL) { return 0; } my_thread->start = start; my_thread->args = args; #ifdef _WIN32 handle = _beginthreadex(NULL, 0, internal_start, my_thread, 0, NULL); if (handle == 0) { free(my_thread); return 0; } #else if (0 != pthread_create(&handle, NULL, internal_start, my_thread)) { free(my_thread); return 0; } #endif /* clearly, you cannot access _stdThread.handle from within the thread * itself, because initialization of this field is not synchronized w.r.t. * multiple threads */ my_thread->handle = handle; *thread = my_thread; return 1; } int stdThreadJoin(stdThread thread) { #ifdef _WIN32 DWORD value; value = WaitForSingleObject((HANDLE)thread->handle, INFINITE); if (value != WAIT_OBJECT_0) return 0; #else void *dummy; if (0 != pthread_join(thread->handle, &dummy)) return 0; #endif return 1; } int stdThreadDestroy(stdThread thread) { #ifdef _WIN32 CloseHandle((HANDLE)thread->handle); #else #endif free(thread); return 1; } #ifdef __cplusplus } /* end extern "C" */ #endif struct _stdThreadLock { #ifdef _WIN32 CRITICAL_SECTION CriticalSection; #else pthread_mutex_t mutex; #endif }; #ifdef __cplusplus extern "C" { #endif int stdThreadLockCreate(stdThreadLock *lock) { stdThreadLock my_lock = NULL; *lock = NULL; my_lock = (stdThreadLock)malloc(sizeof(*my_lock)); if (my_lock == NULL) return 0; #ifdef _WIN32 __try { InitializeCriticalSection(&my_lock->CriticalSection); } __except (GetExceptionCode() == STATUS_NO_MEMORY) { free(my_lock); return 0; } #else if (0 != pthread_mutex_init(&my_lock->mutex, NULL)) { free(lock); return 0; } #endif *lock = my_lock; return 1; } void stdThreadLockAcquire(stdThreadLock lock) { /* pthread_mutex's and CRITICAL_SECTIONS differ * * CRITICAL_SECTION's are recursive, meaning a thread can acquire a * CRITICAL_SECTION multiple times, so long as it then releases it * the same number of times. * * pthread_mutex's seem to be undefined with regards to recursion, * meaning that acquiring the same mutex twice leads to undefined * behavior (it could deadlock, crash, act recursively, who knows) * * Therefore, we will define multiple acquisitions of a lock in a * single thread as "undefined" behavior, thereby allowing us to * ignore the platform compatibility issues here. */ #ifdef _WIN32 /* may throw an exception in Windows 2000 but documentation says to let * it terminate the process (i.e., don't handle it) */ EnterCriticalSection(&lock->CriticalSection); #else pthread_mutex_lock(&lock->mutex); #endif } void stdThreadLockRelease(stdThreadLock lock) { /* see comments in stdThreadLockAcquire with regards to lock * recursion */ #ifdef _WIN32 LeaveCriticalSection(&lock->CriticalSection); #else pthread_mutex_unlock(&lock->mutex); #endif } void stdThreadLockDestroy(stdThreadLock lock)\ { #ifdef _WIN32 DeleteCriticalSection(&lock->CriticalSection); #else pthread_mutex_destroy(&lock->mutex); #endif free(lock); } #ifdef __cplusplus } /* end extern "C" */ #endif