ObjFW
src/threading.h
00001 /*
00002  * Copyright (c) 2008, 2009, 2010, 2011
00003  *   Jonathan Schleifer <js@webkeks.org>
00004  *
00005  * All rights reserved.
00006  *
00007  * This file is part of ObjFW. It may be distributed under the terms of the
00008  * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
00009  * the packaging of this file.
00010  *
00011  * Alternatively, it may be distributed under the terms of the GNU General
00012  * Public License, either version 2 or 3, which can be found in the file
00013  * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
00014  * file.
00015  */
00016 
00017 #import "objfw-defs.h"
00018 
00019 #if !defined(OF_THREADS) || (!defined(OF_HAVE_PTHREADS) && !defined(_WIN32))
00020 # error No threads available!
00021 #endif
00022 
00023 #import "macros.h"
00024 
00025 #if defined(OF_HAVE_PTHREADS)
00026 # include <pthread.h>
00027 typedef pthread_t of_thread_t;
00028 typedef pthread_key_t of_tlskey_t;
00029 typedef pthread_mutex_t of_mutex_t;
00030 typedef pthread_cond_t of_condition_t;
00031 #elif defined(_WIN32)
00032 # include <windows.h>
00033 typedef HANDLE of_thread_t;
00034 typedef DWORD of_tlskey_t;
00035 typedef CRITICAL_SECTION of_mutex_t;
00036 typedef struct {
00037         HANDLE event;
00038         int count;
00039 } of_condition_t;
00040 #endif
00041 
00042 #if defined(OF_ATOMIC_OPS)
00043 # import "atomic.h"
00044 typedef volatile int of_spinlock_t;
00045 # define OF_SPINCOUNT 10
00046 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
00047 typedef pthread_spinlock_t of_spinlock_t;
00048 #else
00049 typedef of_mutex_t of_spinlock_t;
00050 #endif
00051 
00052 #if defined(OF_HAVE_PTHREADS)
00053 # define of_thread_is_current(t) pthread_equal(t, pthread_self())
00054 # define of_thread_current() pthread_self()
00055 #elif defined(_WIN32)
00056 # define of_thread_is_current(t) (t == GetCurrentThread())
00057 # define of_thread_current() GetCurrentThread()
00058 #endif
00059 
00060 static OF_INLINE BOOL
00061 of_thread_new(of_thread_t *thread, id (*main)(id), id data)
00062 {
00063 #if defined(OF_HAVE_PTHREADS)
00064         return (pthread_create(thread, NULL, (void*(*)(void*))main,
00065             (void*)data) ? NO : YES);
00066 #elif defined(_WIN32)
00067         *thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)main,
00068             (void*)data, 0, NULL);
00069 
00070         return (thread == NULL ? NO : YES);
00071 #endif
00072 }
00073 
00074 static OF_INLINE BOOL
00075 of_thread_join(of_thread_t thread)
00076 {
00077 #if defined(OF_HAVE_PTHREADS)
00078         void *ret;
00079 
00080         if (pthread_join(thread, &ret))
00081                 return NO;
00082 
00083         return (ret != PTHREAD_CANCELED ? YES : NO);
00084 #elif defined(_WIN32)
00085         if (WaitForSingleObject(thread, INFINITE))
00086                 return NO;
00087 
00088         CloseHandle(thread);
00089 
00090         return YES;
00091 #endif
00092 }
00093 
00094 static OF_INLINE BOOL
00095 of_thread_detach(of_thread_t thread)
00096 {
00097 #if defined(OF_HAVE_PTHREADS)
00098         return !pthread_detach(thread);
00099 #elif defined(_WIN32)
00100         /* FIXME */
00101         return YES;
00102 #endif
00103 }
00104 
00105 static OF_INLINE void
00106 of_thread_exit()
00107 {
00108 #if defined(OF_HAVE_PTHREADS)
00109         pthread_exit(NULL);
00110 #elif defined(_WIN32)
00111         ExitThread(0);
00112 #endif
00113 }
00114 
00115 static OF_INLINE BOOL
00116 of_mutex_new(of_mutex_t *mutex)
00117 {
00118 #if defined(OF_HAVE_PTHREADS)
00119         return (pthread_mutex_init(mutex, NULL) ? NO : YES);
00120 #elif defined(_WIN32)
00121         InitializeCriticalSection(mutex);
00122         return YES;
00123 #endif
00124 }
00125 
00126 static OF_INLINE BOOL
00127 of_mutex_free(of_mutex_t *mutex)
00128 {
00129 #if defined(OF_HAVE_PTHREADS)
00130         return (pthread_mutex_destroy(mutex) ? NO : YES);
00131 #elif defined(_WIN32)
00132         DeleteCriticalSection(mutex);
00133         return YES;
00134 #endif
00135 }
00136 
00137 static OF_INLINE BOOL
00138 of_mutex_lock(of_mutex_t *mutex)
00139 {
00140 #if defined(OF_HAVE_PTHREADS)
00141         return (pthread_mutex_lock(mutex) ? NO : YES);
00142 #elif defined(_WIN32)
00143         EnterCriticalSection(mutex);
00144         return YES;
00145 #endif
00146 }
00147 
00148 static OF_INLINE BOOL
00149 of_mutex_trylock(of_mutex_t *mutex)
00150 {
00151 #if defined(OF_HAVE_PTHREADS)
00152         return (pthread_mutex_trylock(mutex) ? NO : YES);
00153 #elif defined(_WIN32)
00154         return (TryEnterCriticalSection(mutex) ? YES : NO);
00155 #endif
00156 }
00157 
00158 static OF_INLINE BOOL
00159 of_mutex_unlock(of_mutex_t *mutex)
00160 {
00161 #if defined(OF_HAVE_PTHREADS)
00162         return (pthread_mutex_unlock(mutex) ? NO : YES);
00163 #elif defined(_WIN32)
00164         LeaveCriticalSection(mutex);
00165         return YES;
00166 #endif
00167 }
00168 
00169 static OF_INLINE BOOL
00170 of_condition_new(of_condition_t *condition)
00171 {
00172 #if defined(OF_HAVE_PTHREADS)
00173         return (pthread_cond_init(condition, NULL) ? NO : YES);
00174 #elif defined(_WIN32)
00175         condition->count = 0;
00176 
00177         if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL)
00178                 return NO;
00179 
00180         return YES;
00181 #endif
00182 }
00183 
00184 static OF_INLINE BOOL
00185 of_condition_wait(of_condition_t *condition, of_mutex_t *mutex)
00186 {
00187 #if defined(OF_HAVE_PTHREADS)
00188         return (pthread_cond_wait(condition, mutex) ? NO : YES);
00189 #elif defined(_WIN32)
00190         if (!of_mutex_unlock(mutex))
00191                 return NO;
00192 
00193         of_atomic_inc_int(&condition->count);
00194 
00195         if (WaitForSingleObject(condition->event, INFINITE) != WAIT_OBJECT_0) {
00196                 of_mutex_lock(mutex);
00197                 return NO;
00198         }
00199 
00200         of_atomic_dec_int(&condition->count);
00201 
00202         if (!of_mutex_lock(mutex))
00203                 return NO;
00204 
00205         return YES;
00206 #endif
00207 }
00208 
00209 static OF_INLINE BOOL
00210 of_condition_signal(of_condition_t *condition)
00211 {
00212 #if defined(OF_HAVE_PTHREADS)
00213         return (pthread_cond_signal(condition) ? NO : YES);
00214 #elif defined(_WIN32)
00215         return (SetEvent(condition->event) ? YES : NO);
00216 #endif
00217 }
00218 
00219 static OF_INLINE BOOL
00220 of_condition_broadcast(of_condition_t *condition)
00221 {
00222 #if defined(OF_HAVE_PTHREADS)
00223         return (pthread_cond_broadcast(condition) ? NO : YES);
00224 #elif defined(_WIN32)
00225         size_t i;
00226 
00227         for (i = 0; i < condition->count; i++)
00228                 if (!SetEvent(condition->event))
00229                         return NO;
00230 
00231         return YES;
00232 #endif
00233 }
00234 
00235 static OF_INLINE BOOL
00236 of_condition_free(of_condition_t *condition)
00237 {
00238 #if defined(OF_HAVE_PTHREADS)
00239         return (pthread_cond_destroy(condition) ? NO : YES);
00240 #elif defined(_WIN32)
00241         if (condition->count)
00242                 return NO;
00243 
00244         return (CloseHandle(condition->event) ? YES : NO);
00245 #endif
00246 }
00247 
00248 static OF_INLINE BOOL
00249 of_tlskey_new(of_tlskey_t *key)
00250 {
00251 #if defined(OF_HAVE_PTHREADS)
00252         return (pthread_key_create(key, NULL) ? NO : YES);
00253 #elif defined(_WIN32)
00254         return ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES ? NO : YES);
00255 #endif
00256 }
00257 
00258 static OF_INLINE id
00259 of_tlskey_get(of_tlskey_t key)
00260 {
00261 #if defined(OF_HAVE_PTHREADS)
00262         void *ret = pthread_getspecific(key);
00263 #elif defined(_WIN32)
00264         void *ret = TlsGetValue(key);
00265 #endif
00266 
00267         /* NULL and nil might be different! */
00268         if (ret == NULL)
00269                 return nil;
00270 
00271         return (id)ret;
00272 }
00273 
00274 static OF_INLINE BOOL
00275 of_tlskey_set(of_tlskey_t key, id obj)
00276 {
00277         void *p = (obj != nil ? (void*)obj : NULL);
00278 
00279 #if defined(OF_HAVE_PTHREADS)
00280         return (pthread_setspecific(key, p) ? NO : YES);
00281 #elif defined(_WIN32)
00282         return (TlsSetValue(key, p) ? YES : NO);
00283 #endif
00284 }
00285 
00286 static OF_INLINE BOOL
00287 of_tlskey_free(of_tlskey_t key)
00288 {
00289 #if defined(OF_HAVE_PTHREADS)
00290         return (pthread_key_delete(key) ? NO : YES);
00291 #elif defined(_WIN32)
00292         return (TlsFree(key) ? YES : NO);
00293 #endif
00294 }
00295 
00296 static OF_INLINE BOOL
00297 of_spinlock_new(of_spinlock_t *s)
00298 {
00299 #if defined(OF_ATOMIC_OPS)
00300         *s = 0;
00301         return YES;
00302 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
00303         return (pthread_spin_init(s, 0) ? NO : YES);
00304 #else
00305         return of_mutex_new(s);
00306 #endif
00307 }
00308 
00309 static OF_INLINE BOOL
00310 of_spinlock_trylock(of_spinlock_t *s)
00311 {
00312 #if defined(OF_ATOMIC_OPS)
00313         return (of_atomic_cmpswap_int(s, 0, 1) ? YES : NO);
00314 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
00315         return (pthread_spin_trylock(s) ? NO : YES);
00316 #else
00317         return of_mutex_trylock(s);
00318 #endif
00319 }
00320 
00321 static OF_INLINE BOOL
00322 of_spinlock_lock(of_spinlock_t *s)
00323 {
00324 #if defined(OF_ATOMIC_OPS)
00325 # if defined(OF_HAVE_SCHED_YIELD) || defined(_WIN32)
00326         int i;
00327 
00328         for (i = 0; i < OF_SPINCOUNT; i++)
00329                 if (of_spinlock_trylock(s))
00330                         return YES;
00331 
00332         while (!of_spinlock_trylock(s))
00333 #  ifndef _WIN32
00334                 sched_yield();
00335 #  else
00336                 Sleep(0);
00337 #  endif
00338 # else
00339         while (!of_spinlock_trylock(s));
00340 # endif
00341 
00342         return YES;
00343 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
00344         return (pthread_spin_lock(s) ? NO : YES);
00345 #else
00346         return of_mutex_lock(s);
00347 #endif
00348 }
00349 
00350 static OF_INLINE BOOL
00351 of_spinlock_unlock(of_spinlock_t *s)
00352 {
00353 #if defined(OF_ATOMIC_OPS)
00354         *s = 0;
00355         return YES;
00356 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
00357         return (pthread_spin_unlock(s) ? NO : YES);
00358 #else
00359         return of_mutex_unlock(s);
00360 #endif
00361 }
00362 
00363 static OF_INLINE BOOL
00364 of_spinlock_free(of_spinlock_t *s)
00365 {
00366 #if defined(OF_ATOMIC_OPS)
00367         return YES;
00368 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
00369         return (pthread_spin_destroy(s) ? NO : YES);
00370 #else
00371         return of_mutex_free(s);
00372 #endif
00373 }
 All Classes Functions Variables