Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -142,10 +142,11 @@ 4B2B3E84140D430500EC2F7C /* OFMutableDictionary_hashtable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3E7A140D430500EC2F7C /* OFMutableDictionary_hashtable.m */; }; 4B325EDD1605F3A0007836CA /* OFRunLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B325ED91605F3A0007836CA /* OFRunLoop.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B325EDE1605F3A0007836CA /* OFRunLoop.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B325EDA1605F3A0007836CA /* OFRunLoop.m */; }; 4B325EDF1605F3A0007836CA /* OFTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B325EDB1605F3A0007836CA /* OFTimer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B325EE01605F3A0007836CA /* OFTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B325EDC1605F3A0007836CA /* OFTimer.m */; }; + 4B3379CF1979326A0088E97E /* threading.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B3379CE1979326A0088E97E /* threading.m */; }; 4B39844213D3A24600E6F825 /* OFSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B39844013D3A24600E6F825 /* OFSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B39844313D3A24600E6F825 /* OFSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B39844113D3A24600E6F825 /* OFSet.m */; }; 4B39844713D3AFB400E6F825 /* OFMutableSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B39844513D3AFB400E6F825 /* OFMutableSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B39844813D3AFB400E6F825 /* OFMutableSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B39844613D3AFB400E6F825 /* OFMutableSet.m */; }; 4B3B0798166978780044E634 /* OFMapTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B3B0796166978780044E634 /* OFMapTable.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -618,10 +619,11 @@ 4B2B3E7A140D430500EC2F7C /* OFMutableDictionary_hashtable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFMutableDictionary_hashtable.m; path = src/OFMutableDictionary_hashtable.m; sourceTree = ""; }; 4B325ED91605F3A0007836CA /* OFRunLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFRunLoop.h; path = src/OFRunLoop.h; sourceTree = ""; }; 4B325EDA1605F3A0007836CA /* OFRunLoop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFRunLoop.m; path = src/OFRunLoop.m; sourceTree = ""; }; 4B325EDB1605F3A0007836CA /* OFTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFTimer.h; path = src/OFTimer.h; sourceTree = ""; }; 4B325EDC1605F3A0007836CA /* OFTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFTimer.m; path = src/OFTimer.m; sourceTree = ""; }; + 4B3379CE1979326A0088E97E /* threading.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = threading.m; path = src/threading.m; sourceTree = ""; }; 4B39844013D3A24600E6F825 /* OFSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFSet.h; path = src/OFSet.h; sourceTree = ""; }; 4B39844113D3A24600E6F825 /* OFSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFSet.m; path = src/OFSet.m; sourceTree = ""; }; 4B39844513D3AFB400E6F825 /* OFMutableSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFMutableSet.h; path = src/OFMutableSet.h; sourceTree = ""; }; 4B39844613D3AFB400E6F825 /* OFMutableSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFMutableSet.m; path = src/OFMutableSet.m; sourceTree = ""; }; 4B3B0796166978780044E634 /* OFMapTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFMapTable.h; path = src/OFMapTable.h; sourceTree = ""; }; @@ -1414,10 +1416,11 @@ 4B7769EC1895C07D00D12284 /* resolver.m */, 4B7DD58718943D4A00990FD6 /* socket.h */, 4B40EC1A189FE2650031E19E /* socket.m */, 4B7DD58118942FE200990FD6 /* socket_helpers.h */, 4B67998B1099E7C50041064A /* threading.h */, + 4B3379CE1979326A0088E97E /* threading.m */, 4B67998C1099E7C50041064A /* unicode.h */, 4BFBDD1610A0724800051AFB /* unicode.m */, 4B6AF97210A8D42E0003FB0A /* windows_1252.m */, ); name = ObjFW; @@ -2008,10 +2011,11 @@ 4B3D23B51337FC0D00DD29B8 /* foundation-compat.m in Sources */, 4B3D23EE1337FFD000DD29B8 /* of_asprintf.m in Sources */, 4BA355BA14879BDD00442EF4 /* of_strptime.m in Sources */, 4B7769EE1895C07D00D12284 /* resolver.m in Sources */, 4B40EC1B189FE2650031E19E /* socket.m in Sources */, + 4B3379CF1979326A0088E97E /* threading.m in Sources */, 4B3D23B91337FC0D00DD29B8 /* unicode.m in Sources */, 4B3D23BA1337FC0D00DD29B8 /* windows_1252.m in Sources */, 4B90B79F133AD87D00BD33CB /* OFAcceptFailedException.m in Sources */, 4B90B7A1133AD87D00BD33CB /* OFAddressTranslationFailedException.m in Sources */, 4B17FF80133A2D17003E6DCD /* OFAllocFailedException.m in Sources */, Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -561,11 +561,10 @@ ;; esac AC_DEFINE(OF_HAVE_THREADS, 1, [Whether we have threads]) AC_SUBST(USE_SRCS_THREADS, '${SRCS_THREADS}') - AC_SUBST(USE_INCLUDES_THREADS, '${INCLUDES_THREADS}') AC_ARG_ENABLE(compiler-tls, AS_HELP_STRING([--disable-compiler-tls], [disable compiler thread local storage])) AS_IF([test x"$enable_compiler_tls" != x"no"], [ Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -45,10 +45,9 @@ RUNTIME_LIB_A = @RUNTIME_LIB_A@ RUN_TESTS = @RUN_TESTS@ TESTPLUGIN = @TESTPLUGIN@ TESTS_LIBS = @TESTS_LIBS@ TEST_LAUNCHER = @TEST_LAUNCHER@ -USE_INCLUDES_THREADS = @USE_INCLUDES_THREADS@ USE_SRCS_FILES = @USE_SRCS_FILES@ USE_SRCS_PLUGINS = @USE_SRCS_PLUGINS@ USE_SRCS_SOCKETS = @USE_SRCS_SOCKETS@ USE_SRCS_THREADS = @USE_SRCS_THREADS@ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -94,13 +94,13 @@ resolver.m \ socket.m SRCS_THREADS = OFCondition.m \ OFMutex.m \ OFRecursiveMutex.m \ - OFThreadPool.m + OFThreadPool.m \ + threading.m -INCLUDES_THREADS = threading.h INCLUDES := ${SRCS:.m=.h} \ OFCollection.h \ OFHash.h \ OFJSONRepresentation.h \ OFLocking.h \ @@ -112,12 +112,11 @@ autorelease.h \ ${ATOMIC_H} \ block.h \ instance.h \ macros.h \ - objfw-defs.h \ - ${USE_INCLUDES_THREADS} + objfw-defs.h SRCS += OFArray_adjacent.m \ OFArray_adjacentSubarray.m \ OFCountedSet_hashtable.m \ OFDictionary_hashtable.m \ Index: src/threading.h ================================================================== --- src/threading.h +++ src/threading.h @@ -84,285 +84,34 @@ #else # error of_thread_is_current not implemented! # error of_thread_current not implemented! #endif -static OF_INLINE bool -of_thread_new(of_thread_t *thread, id (*function)(id), id data) -{ -#if defined(OF_HAVE_PTHREADS) - return (pthread_create(thread, NULL, (void*(*)(void*))function, - (__bridge void*)data) == 0); -#elif defined(_WIN32) - *thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)function, - (__bridge void*)data, 0, NULL); - - return (thread != NULL); -#else -# error of_thread_new not implemented! -#endif -} - -static OF_INLINE bool -of_thread_join(of_thread_t thread) -{ -#if defined(OF_HAVE_PTHREADS) - void *ret; - - if (pthread_join(thread, &ret) != 0) - return false; - -# ifdef PTHREAD_CANCELED - return (ret != PTHREAD_CANCELED); -# else - return true; -# endif -#elif defined(_WIN32) - if (WaitForSingleObject(thread, INFINITE)) - return false; - - CloseHandle(thread); - - return true; -#else -# error of_thread_join not implemented! -#endif -} - -static OF_INLINE bool -of_thread_detach(of_thread_t thread) -{ -#if defined(OF_HAVE_PTHREADS) - return !pthread_detach(thread); -#elif defined(_WIN32) - /* FIXME */ - return true; -#else -# error of_thread_detach not implemented! -#endif -} - -static OF_INLINE void noreturn -of_thread_exit(void) -{ -#if defined(OF_HAVE_PTHREADS) - pthread_exit(NULL); -#elif defined(_WIN32) - ExitThread(0); -#else -# error of_thread_exit not implemented! -#endif - OF_UNREACHABLE -} - -static OF_INLINE void -of_once(of_once_t *control, void (*func)(void)) -{ -#if defined(OF_HAVE_PTHREADS) - pthread_once(control, func); -#elif defined(_WIN32) - switch (InterlockedCompareExchange(control, 1, 0)) { - case 0: - func(); - InterlockedIncrement(control); - break; - case 1: - while (*control == 1) - Sleep(0); - break; - } -#else -# error of_once not implemented! -#endif -} - -static OF_INLINE bool -of_mutex_new(of_mutex_t *mutex) -{ -#if defined(OF_HAVE_PTHREADS) - return !pthread_mutex_init(mutex, NULL); -#elif defined(_WIN32) - InitializeCriticalSection(mutex); - return true; -#else -# error of_mutex_new not implemented! -#endif -} - -static OF_INLINE bool -of_mutex_free(of_mutex_t *mutex) -{ -#if defined(OF_HAVE_PTHREADS) - return !pthread_mutex_destroy(mutex); -#elif defined(_WIN32) - DeleteCriticalSection(mutex); - return true; -#else -# error of_mutex_free not implemented! -#endif -} - -static OF_INLINE bool -of_mutex_lock(of_mutex_t *mutex) -{ -#if defined(OF_HAVE_PTHREADS) - return !pthread_mutex_lock(mutex); -#elif defined(_WIN32) - EnterCriticalSection(mutex); - return true; -#else -# error of_mutex_lock not implemented! -#endif -} - -static OF_INLINE bool -of_mutex_trylock(of_mutex_t *mutex) -{ -#if defined(OF_HAVE_PTHREADS) - return !pthread_mutex_trylock(mutex); -#elif defined(_WIN32) - return TryEnterCriticalSection(mutex); -#else -# error of_mutex_trylock not implemented! -#endif -} - -static OF_INLINE bool -of_mutex_unlock(of_mutex_t *mutex) -{ -#if defined(OF_HAVE_PTHREADS) - return (pthread_mutex_unlock(mutex) == 0); -#elif defined(_WIN32) - LeaveCriticalSection(mutex); - return true; -#else -# error of_mutex_unlock not implemented! -#endif -} - -static OF_INLINE bool -of_condition_new(of_condition_t *condition) -{ -#if defined(OF_HAVE_PTHREADS) - return (pthread_cond_init(condition, NULL) == 0); -#elif defined(_WIN32) - condition->count = 0; - - if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) - return false; - - return true; -#else -# error of_condition_new not implemented! -#endif -} - -static OF_INLINE bool -of_condition_wait(of_condition_t *condition, of_mutex_t *mutex) -{ -#if defined(OF_HAVE_PTHREADS) - return !pthread_cond_wait(condition, mutex); -#elif defined(_WIN32) - if (!of_mutex_unlock(mutex)) - return false; - - of_atomic_int_inc(&condition->count); - - if (WaitForSingleObject(condition->event, INFINITE) != WAIT_OBJECT_0) { - of_mutex_lock(mutex); - return false; - } - - of_atomic_int_dec(&condition->count); - - if (!of_mutex_lock(mutex)) - return false; - - return true; -#else -# error of_condition_wait not implemented! -#endif -} - -static OF_INLINE bool -of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex, - of_time_interval_t timeout) -{ -#if defined(OF_HAVE_PTHREADS) - struct timespec ts; - - ts.tv_sec = (time_t)timeout; - ts.tv_nsec = lrint((timeout - ts.tv_sec) * 1000000000); - - return !pthread_cond_timedwait(condition, mutex, &ts); -#elif defined(_WIN32) - if (!of_mutex_unlock(mutex)) - return false; - - of_atomic_int_inc(&condition->count); - - if (WaitForSingleObject(condition->event, - timeout * 1000) != WAIT_OBJECT_0) { - of_mutex_lock(mutex); - return false; - } - - of_atomic_int_dec(&condition->count); - - if (!of_mutex_lock(mutex)) - return false; - - return true; -#else -# error of_condition_timed_wait not implemented! -#endif -} - -static OF_INLINE bool -of_condition_signal(of_condition_t *condition) -{ -#if defined(OF_HAVE_PTHREADS) - return !pthread_cond_signal(condition); -#elif defined(_WIN32) - return SetEvent(condition->event); -#else -# error of_condition_signal not implemented! -#endif -} - -static OF_INLINE bool -of_condition_broadcast(of_condition_t *condition) -{ -#if defined(OF_HAVE_PTHREADS) - return !pthread_cond_broadcast(condition); -#elif defined(_WIN32) - int i; - - for (i = 0; i < condition->count; i++) - if (!SetEvent(condition->event)) - return false; - - return true; -#else -# error of_condition_broadcast not implemented! -#endif -} - -static OF_INLINE bool -of_condition_free(of_condition_t *condition) -{ -#if defined(OF_HAVE_PTHREADS) - return !pthread_cond_destroy(condition); -#elif defined(_WIN32) - if (condition->count) - return false; - - return CloseHandle(condition->event); -#else -# error of_condition_free not implemented! -#endif -} +extern bool of_thread_new(of_thread_t *thread, id (*function)(id), id data); +extern bool of_thread_join(of_thread_t thread); +extern bool of_thread_detach(of_thread_t thread); +extern void noreturn of_thread_exit(void); +extern void of_once(of_once_t *control, void (*func)(void)); +extern bool of_mutex_new(of_mutex_t *mutex); +extern bool of_mutex_lock(of_mutex_t *mutex); +extern bool of_mutex_trylock(of_mutex_t *mutex); +extern bool of_mutex_unlock(of_mutex_t *mutex); +extern bool of_mutex_free(of_mutex_t *mutex); +extern bool of_rmutex_new(of_rmutex_t *rmutex); +extern bool of_rmutex_lock(of_rmutex_t *rmutex); +extern bool of_rmutex_trylock(of_rmutex_t *rmutex); +extern bool of_rmutex_unlock(of_rmutex_t *rmutex); +extern bool of_rmutex_free(of_rmutex_t *rmutex); +extern bool of_condition_new(of_condition_t *condition); +extern bool of_condition_signal(of_condition_t *condition); +extern bool of_condition_broadcast(of_condition_t *condition); +extern bool of_condition_wait(of_condition_t *condition, of_mutex_t *mutex); +extern bool of_condition_timed_wait(of_condition_t *condition, + of_mutex_t *mutex, of_time_interval_t timeout); +extern bool of_condition_free(of_condition_t *condition); + +/* TLS keys and spinlocks are inlined for performance. */ static OF_INLINE bool of_tlskey_new(of_tlskey_t *key) { #if defined(OF_HAVE_PTHREADS) @@ -485,123 +234,5 @@ return !pthread_spin_destroy(spinlock); #else return of_mutex_free(spinlock); #endif } - -#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES -static OF_INLINE bool -of_rmutex_new(of_mutex_t *mutex) -{ - pthread_mutexattr_t attr; - - if (pthread_mutexattr_init(&attr) != 0) - return false; - - if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) - return false; - - if (pthread_mutex_init(mutex, &attr) != 0) - return false; - - if (pthread_mutexattr_destroy(&attr) != 0) - return false; - - return true; -} - -# define of_rmutex_lock of_mutex_lock -# define of_rmutex_trylock of_mutex_trylock -# define of_rmutex_unlock of_mutex_unlock -# define of_rmutex_free of_mutex_free -#else -static OF_INLINE bool -of_rmutex_new(of_rmutex_t *rmutex) -{ - if (!of_mutex_new(&rmutex->mutex)) - return false; - - if (!of_tlskey_new(&rmutex->count)) - return false; - - return true; -} - -static OF_INLINE bool -of_rmutex_lock(of_rmutex_t *rmutex) -{ - uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count); - - if (count > 0) { - if (!of_tlskey_set(rmutex->count, (void*)(count + 1))) - return false; - - return true; - } - - if (!of_mutex_lock(&rmutex->mutex)) - return false; - - if (!of_tlskey_set(rmutex->count, (void*)1)) { - of_mutex_unlock(&rmutex->mutex); - return false; - } - - return true; -} - -static OF_INLINE bool -of_rmutex_trylock(of_rmutex_t *rmutex) -{ - uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count); - - if (count > 0) { - if (!of_tlskey_set(rmutex->count, (void*)(count + 1))) - return false; - - return true; - } - - if (!of_mutex_trylock(&rmutex->mutex)) - return false; - - if (!of_tlskey_set(rmutex->count, (void*)1)) { - of_mutex_unlock(&rmutex->mutex); - return false; - } - - return true; -} - -static OF_INLINE bool -of_rmutex_unlock(of_rmutex_t *rmutex) -{ - uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count); - - if (count > 1) { - if (!of_tlskey_set(rmutex->count, (void*)(count - 1))) - return false; - - return true; - } - - if (!of_tlskey_set(rmutex->count, (void*)0)) - return false; - - if (!of_mutex_unlock(&rmutex->mutex)) - return false; - - return true; -} - -static OF_INLINE bool -of_rmutex_free(of_rmutex_t *rmutex) -{ - if (!of_mutex_free(&rmutex->mutex)) - return false; - - if (!of_tlskey_free(rmutex->count)) - return false; - - return true; -} -#endif ADDED src/threading.m Index: src/threading.m ================================================================== --- src/threading.m +++ src/threading.m @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "threading.h" + +bool +of_thread_new(of_thread_t *thread, id (*function)(id), id data) +{ +#if defined(OF_HAVE_PTHREADS) + return (pthread_create(thread, NULL, (void*(*)(void*))function, + (__bridge void*)data) == 0); +#elif defined(_WIN32) + *thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)function, + (__bridge void*)data, 0, NULL); + + return (thread != NULL); +#else +# error of_thread_new not implemented! +#endif +} + +bool +of_thread_join(of_thread_t thread) +{ +#if defined(OF_HAVE_PTHREADS) + void *ret; + + if (pthread_join(thread, &ret) != 0) + return false; + +# ifdef PTHREAD_CANCELED + return (ret != PTHREAD_CANCELED); +# else + return true; +# endif +#elif defined(_WIN32) + if (WaitForSingleObject(thread, INFINITE)) + return false; + + CloseHandle(thread); + + return true; +#else +# error of_thread_join not implemented! +#endif +} + +bool +of_thread_detach(of_thread_t thread) +{ +#if defined(OF_HAVE_PTHREADS) + return !pthread_detach(thread); +#elif defined(_WIN32) + /* FIXME */ + return true; +#else +# error of_thread_detach not implemented! +#endif +} + +void noreturn +of_thread_exit(void) +{ +#if defined(OF_HAVE_PTHREADS) + pthread_exit(NULL); +#elif defined(_WIN32) + ExitThread(0); +#else +# error of_thread_exit not implemented! +#endif + OF_UNREACHABLE +} + +void +of_once(of_once_t *control, void (*func)(void)) +{ +#if defined(OF_HAVE_PTHREADS) + pthread_once(control, func); +#elif defined(_WIN32) + switch (InterlockedCompareExchange(control, 1, 0)) { + case 0: + func(); + InterlockedIncrement(control); + break; + case 1: + while (*control == 1) + Sleep(0); + break; + } +#else +# error of_once not implemented! +#endif +} + +bool +of_mutex_new(of_mutex_t *mutex) +{ +#if defined(OF_HAVE_PTHREADS) + return !pthread_mutex_init(mutex, NULL); +#elif defined(_WIN32) + InitializeCriticalSection(mutex); + return true; +#else +# error of_mutex_new not implemented! +#endif +} + +bool +of_mutex_lock(of_mutex_t *mutex) +{ +#if defined(OF_HAVE_PTHREADS) + return !pthread_mutex_lock(mutex); +#elif defined(_WIN32) + EnterCriticalSection(mutex); + return true; +#else +# error of_mutex_lock not implemented! +#endif +} + +bool +of_mutex_trylock(of_mutex_t *mutex) +{ +#if defined(OF_HAVE_PTHREADS) + return !pthread_mutex_trylock(mutex); +#elif defined(_WIN32) + return TryEnterCriticalSection(mutex); +#else +# error of_mutex_trylock not implemented! +#endif +} + +bool +of_mutex_unlock(of_mutex_t *mutex) +{ +#if defined(OF_HAVE_PTHREADS) + return (pthread_mutex_unlock(mutex) == 0); +#elif defined(_WIN32) + LeaveCriticalSection(mutex); + return true; +#else +# error of_mutex_unlock not implemented! +#endif +} + +bool +of_mutex_free(of_mutex_t *mutex) +{ +#if defined(OF_HAVE_PTHREADS) + return !pthread_mutex_destroy(mutex); +#elif defined(_WIN32) + DeleteCriticalSection(mutex); + return true; +#else +# error of_mutex_free not implemented! +#endif +} + +bool +of_rmutex_new(of_rmutex_t *rmutex) +{ +#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES + pthread_mutexattr_t attr; + + if (pthread_mutexattr_init(&attr) != 0) + return false; + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) + return false; + + if (pthread_mutex_init(rmutex, &attr) != 0) + return false; + + if (pthread_mutexattr_destroy(&attr) != 0) + return false; + + return true; +#else + if (!of_mutex_new(&rmutex->mutex)) + return false; + + if (!of_tlskey_new(&rmutex->count)) + return false; + + return true; +#endif +} + +bool +of_rmutex_lock(of_rmutex_t *rmutex) +{ +#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES + return of_mutex_lock(rmutex); +#else + uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count); + + if (count > 0) { + if (!of_tlskey_set(rmutex->count, (void*)(count + 1))) + return false; + + return true; + } + + if (!of_mutex_lock(&rmutex->mutex)) + return false; + + if (!of_tlskey_set(rmutex->count, (void*)1)) { + of_mutex_unlock(&rmutex->mutex); + return false; + } + + return true; +#endif +} + +bool +of_rmutex_trylock(of_rmutex_t *rmutex) +{ +#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES + return of_mutex_trylock(rmutex); +#else + uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count); + + if (count > 0) { + if (!of_tlskey_set(rmutex->count, (void*)(count + 1))) + return false; + + return true; + } + + if (!of_mutex_trylock(&rmutex->mutex)) + return false; + + if (!of_tlskey_set(rmutex->count, (void*)1)) { + of_mutex_unlock(&rmutex->mutex); + return false; + } + + return true; +#endif +} + +bool +of_rmutex_unlock(of_rmutex_t *rmutex) +{ +#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES + return of_mutex_unlock(rmutex); +#else + uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count); + + if (count > 1) { + if (!of_tlskey_set(rmutex->count, (void*)(count - 1))) + return false; + + return true; + } + + if (!of_tlskey_set(rmutex->count, (void*)0)) + return false; + + if (!of_mutex_unlock(&rmutex->mutex)) + return false; + + return true; +#endif +} + +bool +of_rmutex_free(of_rmutex_t *rmutex) +{ +#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES + return of_mutex_free(rmutex); +#else + if (!of_mutex_free(&rmutex->mutex)) + return false; + + if (!of_tlskey_free(rmutex->count)) + return false; + + return true; +#endif +} + +bool +of_condition_new(of_condition_t *condition) +{ +#if defined(OF_HAVE_PTHREADS) + return (pthread_cond_init(condition, NULL) == 0); +#elif defined(_WIN32) + condition->count = 0; + + if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) + return false; + + return true; +#else +# error of_condition_new not implemented! +#endif +} + +bool +of_condition_signal(of_condition_t *condition) +{ +#if defined(OF_HAVE_PTHREADS) + return !pthread_cond_signal(condition); +#elif defined(_WIN32) + return SetEvent(condition->event); +#else +# error of_condition_signal not implemented! +#endif +} + +bool +of_condition_broadcast(of_condition_t *condition) +{ +#if defined(OF_HAVE_PTHREADS) + return !pthread_cond_broadcast(condition); +#elif defined(_WIN32) + int i; + + for (i = 0; i < condition->count; i++) + if (!SetEvent(condition->event)) + return false; + + return true; +#else +# error of_condition_broadcast not implemented! +#endif +} + +bool +of_condition_wait(of_condition_t *condition, of_mutex_t *mutex) +{ +#if defined(OF_HAVE_PTHREADS) + return !pthread_cond_wait(condition, mutex); +#elif defined(_WIN32) + if (!of_mutex_unlock(mutex)) + return false; + + of_atomic_int_inc(&condition->count); + + if (WaitForSingleObject(condition->event, INFINITE) != WAIT_OBJECT_0) { + of_mutex_lock(mutex); + return false; + } + + of_atomic_int_dec(&condition->count); + + if (!of_mutex_lock(mutex)) + return false; + + return true; +#else +# error of_condition_wait not implemented! +#endif +} + +bool +of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex, + of_time_interval_t timeout) +{ +#if defined(OF_HAVE_PTHREADS) + struct timespec ts; + + ts.tv_sec = (time_t)timeout; + ts.tv_nsec = lrint((timeout - ts.tv_sec) * 1000000000); + + return !pthread_cond_timedwait(condition, mutex, &ts); +#elif defined(_WIN32) + if (!of_mutex_unlock(mutex)) + return false; + + of_atomic_int_inc(&condition->count); + + if (WaitForSingleObject(condition->event, + timeout * 1000) != WAIT_OBJECT_0) { + of_mutex_lock(mutex); + return false; + } + + of_atomic_int_dec(&condition->count); + + if (!of_mutex_lock(mutex)) + return false; + + return true; +#else +# error of_condition_timed_wait not implemented! +#endif +} + +bool +of_condition_free(of_condition_t *condition) +{ +#if defined(OF_HAVE_PTHREADS) + return !pthread_cond_destroy(condition); +#elif defined(_WIN32) + if (condition->count) + return false; + + return CloseHandle(condition->event); +#else +# error of_condition_free not implemented! +#endif +}