Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -847,10 +847,11 @@ 4BA85BC7140ECCE800E91D51 /* OFMutableSet_hashtable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFMutableSet_hashtable.m; path = src/OFMutableSet_hashtable.m; sourceTree = ""; }; 4BA85BC8140ECCE800E91D51 /* OFSet_hashtable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFSet_hashtable.h; path = src/OFSet_hashtable.h; sourceTree = ""; }; 4BA85BC9140ECCE800E91D51 /* OFSet_hashtable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFSet_hashtable.m; path = src/OFSet_hashtable.m; sourceTree = ""; }; 4BA9CFA315E129D30076DC74 /* autorelease.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = autorelease.h; path = src/autorelease.h; sourceTree = ""; }; 4BAA60C714D09699006F068D /* OFJSONTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFJSONTests.m; path = tests/OFJSONTests.m; sourceTree = ""; }; + 4BABC29A197A8212006A93BD /* threading_pthread.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = threading_pthread.m; path = src/threading_pthread.m; sourceTree = ""; }; 4BAE7353139C507F00F682ED /* serialization.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = serialization.xml; path = tests/serialization.xml; sourceTree = ""; }; 4BAF5F46123460C900F4E111 /* OFCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFCollection.h; path = src/OFCollection.h; sourceTree = ""; }; 4BAF5F49123460C900F4E111 /* OFStreamSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStreamSocket.h; path = src/OFStreamSocket.h; sourceTree = ""; }; 4BAF5F4A123460C900F4E111 /* OFStreamSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamSocket.m; path = src/OFStreamSocket.m; sourceTree = ""; }; 4BAFC166182EAA7800BE5E57 /* OFOptionsParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFOptionsParser.h; path = src/OFOptionsParser.h; sourceTree = ""; }; @@ -1417,10 +1418,11 @@ 4B7DD58718943D4A00990FD6 /* socket.h */, 4B40EC1A189FE2650031E19E /* socket.m */, 4B7DD58118942FE200990FD6 /* socket_helpers.h */, 4B67998B1099E7C50041064A /* threading.h */, 4B3379CE1979326A0088E97E /* threading.m */, + 4BABC29A197A8212006A93BD /* threading_pthread.m */, 4B67998C1099E7C50041064A /* unicode.h */, 4BFBDD1610A0724800051AFB /* unicode.m */, 4B6AF97210A8D42E0003FB0A /* windows_1252.m */, ); name = ObjFW; Index: src/threading.m ================================================================== --- src/threading.m +++ src/threading.m @@ -14,162 +14,17 @@ * 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 OF_NO_RETURN -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 -} +#if defined(OF_HAVE_PTHREADS) +# include "threading_pthread.m" +#elif defined(_WIN32) +# include "threading_winapi.m" +#else +# error No threads available! +#endif bool of_rmutex_new(of_rmutex_t *rmutex) { #ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES @@ -291,128 +146,5 @@ 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 -} ADDED src/threading_pthread.m Index: src/threading_pthread.m ================================================================== --- src/threading_pthread.m +++ src/threading_pthread.m @@ -0,0 +1,131 @@ +/* + * 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) +{ + return (pthread_create(thread, NULL, (void*(*)(void*))function, + (__bridge void*)data) == 0); +} + +bool +of_thread_join(of_thread_t thread) +{ + void *ret; + + if (pthread_join(thread, &ret) != 0) + return false; + +#ifdef PTHREAD_CANCELED + return (ret != PTHREAD_CANCELED); +#else + return true; +#endif +} + +bool +of_thread_detach(of_thread_t thread) +{ + return (pthread_detach(thread) == 0); +} + +void OF_NO_RETURN +of_thread_exit(void) +{ + pthread_exit(NULL); + + OF_UNREACHABLE +} + +void +of_once(of_once_t *control, void (*func)(void)) +{ + pthread_once(control, func); +} + +bool +of_mutex_new(of_mutex_t *mutex) +{ + return (pthread_mutex_init(mutex, NULL) == 0); +} + +bool +of_mutex_lock(of_mutex_t *mutex) +{ + return (pthread_mutex_lock(mutex) == 0); +} + +bool +of_mutex_trylock(of_mutex_t *mutex) +{ + return (pthread_mutex_trylock(mutex) == 0); +} + +bool +of_mutex_unlock(of_mutex_t *mutex) +{ + return (pthread_mutex_unlock(mutex) == 0); +} + +bool +of_mutex_free(of_mutex_t *mutex) +{ + return (pthread_mutex_destroy(mutex) == 0); +} + +bool +of_condition_new(of_condition_t *condition) +{ + return (pthread_cond_init(condition, NULL) == 0); +} + +bool +of_condition_signal(of_condition_t *condition) +{ + return (pthread_cond_signal(condition) == 0); +} + +bool +of_condition_broadcast(of_condition_t *condition) +{ + return (pthread_cond_broadcast(condition) == 0); +} + +bool +of_condition_wait(of_condition_t *condition, of_mutex_t *mutex) +{ + return (pthread_cond_wait(condition, mutex) == 0); +} + +bool +of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex, + of_time_interval_t timeout) +{ + 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) == 0); +} + +bool +of_condition_free(of_condition_t *condition) +{ + return (pthread_cond_destroy(condition) == 0); +} ADDED src/threading_winapi.m Index: src/threading_winapi.m ================================================================== --- src/threading_winapi.m +++ src/threading_winapi.m @@ -0,0 +1,187 @@ +/* + * 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) +{ + *thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)function, + (__bridge void*)data, 0, NULL); + + return (thread != NULL); +} + +bool +of_thread_join(of_thread_t thread) +{ + if (WaitForSingleObject(thread, INFINITE)) + return false; + + CloseHandle(thread); + + return true; +} + +bool +of_thread_detach(of_thread_t thread) +{ + /* FIXME */ + return true; +} + +void OF_NO_RETURN +of_thread_exit(void) +{ + ExitThread(0); + + OF_UNREACHABLE +} + +void +of_once(of_once_t *control, void (*func)(void)) +{ + switch (InterlockedCompareExchange(control, 1, 0)) { + case 0: + func(); + InterlockedIncrement(control); + break; + case 1: + while (*control == 1) + Sleep(0); + break; + } +} + +bool +of_mutex_new(of_mutex_t *mutex) +{ + InitializeCriticalSection(mutex); + + return true; +} + +bool +of_mutex_lock(of_mutex_t *mutex) +{ + EnterCriticalSection(mutex); + + return true; +} + +bool +of_mutex_trylock(of_mutex_t *mutex) +{ + return TryEnterCriticalSection(mutex); +} + +bool +of_mutex_unlock(of_mutex_t *mutex) +{ + LeaveCriticalSection(mutex); + + return true; +} + +bool +of_mutex_free(of_mutex_t *mutex) +{ + DeleteCriticalSection(mutex); + + return true; +} + +bool +of_condition_new(of_condition_t *condition) +{ + condition->count = 0; + + if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) + return false; + + return true; +} + +bool +of_condition_signal(of_condition_t *condition) +{ + return SetEvent(condition->event); +} + +bool +of_condition_broadcast(of_condition_t *condition) +{ + int i; + + for (i = 0; i < condition->count; i++) + if (!SetEvent(condition->event)) + return false; + + return true; +} + +bool +of_condition_wait(of_condition_t *condition, of_mutex_t *mutex) +{ + 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; +} + +bool +of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex, + of_time_interval_t timeout) +{ + 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; +} + +bool +of_condition_free(of_condition_t *condition) +{ + if (condition->count != 0) + return false; + + return CloseHandle(condition->event); +}