ObjFW
 All Classes Functions Variables
threading.h
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011, 2012
3  * Jonathan Schleifer <js@webkeks.org>
4  *
5  * All rights reserved.
6  *
7  * This file is part of ObjFW. It may be distributed under the terms of the
8  * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
9  * the packaging of this file.
10  *
11  * Alternatively, it may be distributed under the terms of the GNU General
12  * Public License, either version 2 or 3, which can be found in the file
13  * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
14  * file.
15  */
16 
17 #import "objfw-defs.h"
18 
19 #if !defined(OF_THREADS) || (!defined(OF_HAVE_PTHREADS) && !defined(_WIN32))
20 # error No threads available!
21 #endif
22 
23 #import "macros.h"
24 
25 #if defined(OF_HAVE_PTHREADS)
26 # include <pthread.h>
27 typedef pthread_t of_thread_t;
28 typedef pthread_key_t of_tlskey_t;
29 typedef pthread_mutex_t of_mutex_t;
30 typedef pthread_cond_t of_condition_t;
31 #elif defined(_WIN32)
32 # include <windows.h>
33 typedef HANDLE of_thread_t;
34 typedef DWORD of_tlskey_t;
35 typedef CRITICAL_SECTION of_mutex_t;
36 typedef struct {
37  HANDLE event;
38  int count;
39 } of_condition_t;
40 #endif
41 
42 #if defined(OF_ATOMIC_OPS)
43 # import "atomic.h"
44 typedef volatile int of_spinlock_t;
45 # define OF_SPINCOUNT 10
46 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
47 typedef pthread_spinlock_t of_spinlock_t;
48 #else
49 typedef of_mutex_t of_spinlock_t;
50 #endif
51 
52 #ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES
53 # define of_rmutex_t of_mutex_t
54 #else
55 typedef struct {
56  of_mutex_t mutex;
57  of_tlskey_t count;
58 } of_rmutex_t;
59 #endif
60 
61 #if defined(OF_HAVE_PTHREADS)
62 # define of_thread_is_current(t) pthread_equal(t, pthread_self())
63 # define of_thread_current pthread_self
64 #elif defined(_WIN32)
65 # define of_thread_is_current(t) (t == GetCurrentThread())
66 # define of_thread_current GetCurrentThread
67 #endif
68 
69 static OF_INLINE BOOL
70 of_thread_new(of_thread_t *thread, id (*function)(id), id data)
71 {
72 #if defined(OF_HAVE_PTHREADS)
73  return !pthread_create(thread, NULL, (void*(*)(void*))function,
74  (__bridge void*)data);
75 #elif defined(_WIN32)
76  *thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)function,
77  (__bridge void*)data, 0, NULL);
78 
79  return (thread != NULL);
80 #endif
81 }
82 
83 static OF_INLINE BOOL
84 of_thread_join(of_thread_t thread)
85 {
86 #if defined(OF_HAVE_PTHREADS)
87  void *ret;
88 
89  if (pthread_join(thread, &ret))
90  return NO;
91 
92  return (ret != PTHREAD_CANCELED);
93 #elif defined(_WIN32)
94  if (WaitForSingleObject(thread, INFINITE))
95  return NO;
96 
97  CloseHandle(thread);
98 
99  return YES;
100 #endif
101 }
102 
103 static OF_INLINE BOOL
104 of_thread_detach(of_thread_t thread)
105 {
106 #if defined(OF_HAVE_PTHREADS)
107  return !pthread_detach(thread);
108 #elif defined(_WIN32)
109  /* FIXME */
110  return YES;
111 #endif
112 }
113 
114 static OF_INLINE void
115 of_thread_exit(void)
116 {
117 #if defined(OF_HAVE_PTHREADS)
118  pthread_exit(NULL);
119 #elif defined(_WIN32)
120  ExitThread(0);
121 #endif
122 }
123 
124 static OF_INLINE BOOL
125 of_mutex_new(of_mutex_t *mutex)
126 {
127 #if defined(OF_HAVE_PTHREADS)
128  return !pthread_mutex_init(mutex, NULL);
129 #elif defined(_WIN32)
130  InitializeCriticalSection(mutex);
131  return YES;
132 #endif
133 }
134 
135 static OF_INLINE BOOL
136 of_mutex_free(of_mutex_t *mutex)
137 {
138 #if defined(OF_HAVE_PTHREADS)
139  return !pthread_mutex_destroy(mutex);
140 #elif defined(_WIN32)
141  DeleteCriticalSection(mutex);
142  return YES;
143 #endif
144 }
145 
146 static OF_INLINE BOOL
147 of_mutex_lock(of_mutex_t *mutex)
148 {
149 #if defined(OF_HAVE_PTHREADS)
150  return !pthread_mutex_lock(mutex);
151 #elif defined(_WIN32)
152  EnterCriticalSection(mutex);
153  return YES;
154 #endif
155 }
156 
157 static OF_INLINE BOOL
158 of_mutex_trylock(of_mutex_t *mutex)
159 {
160 #if defined(OF_HAVE_PTHREADS)
161  return !pthread_mutex_trylock(mutex);
162 #elif defined(_WIN32)
163  return TryEnterCriticalSection(mutex);
164 #endif
165 }
166 
167 static OF_INLINE BOOL
168 of_mutex_unlock(of_mutex_t *mutex)
169 {
170 #if defined(OF_HAVE_PTHREADS)
171  return !pthread_mutex_unlock(mutex);
172 #elif defined(_WIN32)
173  LeaveCriticalSection(mutex);
174  return YES;
175 #endif
176 }
177 
178 static OF_INLINE BOOL
179 of_condition_new(of_condition_t *condition)
180 {
181 #if defined(OF_HAVE_PTHREADS)
182  return !pthread_cond_init(condition, NULL);
183 #elif defined(_WIN32)
184  condition->count = 0;
185 
186  if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL)
187  return NO;
188 
189  return YES;
190 #endif
191 }
192 
193 static OF_INLINE BOOL
194 of_condition_wait(of_condition_t *condition, of_mutex_t *mutex)
195 {
196 #if defined(OF_HAVE_PTHREADS)
197  return !pthread_cond_wait(condition, mutex);
198 #elif defined(_WIN32)
199  if (!of_mutex_unlock(mutex))
200  return NO;
201 
202  of_atomic_inc_int(&condition->count);
203 
204  if (WaitForSingleObject(condition->event, INFINITE) != WAIT_OBJECT_0) {
205  of_mutex_lock(mutex);
206  return NO;
207  }
208 
209  of_atomic_dec_int(&condition->count);
210 
211  if (!of_mutex_lock(mutex))
212  return NO;
213 
214  return YES;
215 #endif
216 }
217 
218 static OF_INLINE BOOL
219 of_condition_signal(of_condition_t *condition)
220 {
221 #if defined(OF_HAVE_PTHREADS)
222  return !pthread_cond_signal(condition);
223 #elif defined(_WIN32)
224  return SetEvent(condition->event);
225 #endif
226 }
227 
228 static OF_INLINE BOOL
229 of_condition_broadcast(of_condition_t *condition)
230 {
231 #if defined(OF_HAVE_PTHREADS)
232  return !pthread_cond_broadcast(condition);
233 #elif defined(_WIN32)
234  size_t i;
235 
236  for (i = 0; i < condition->count; i++)
237  if (!SetEvent(condition->event))
238  return NO;
239 
240  return YES;
241 #endif
242 }
243 
244 static OF_INLINE BOOL
245 of_condition_free(of_condition_t *condition)
246 {
247 #if defined(OF_HAVE_PTHREADS)
248  return !pthread_cond_destroy(condition);
249 #elif defined(_WIN32)
250  if (condition->count)
251  return NO;
252 
253  return CloseHandle(condition->event);
254 #endif
255 }
256 
257 static OF_INLINE BOOL
258 of_tlskey_new(of_tlskey_t *key)
259 {
260 #if defined(OF_HAVE_PTHREADS)
261  return !pthread_key_create(key, NULL);
262 #elif defined(_WIN32)
263  return ((*key = TlsAlloc()) != TLS_OUT_OF_INDEXES);
264 #endif
265 }
266 
267 static OF_INLINE void*
268 of_tlskey_get(of_tlskey_t key)
269 {
270 #if defined(OF_HAVE_PTHREADS)
271  return pthread_getspecific(key);
272 #elif defined(_WIN32)
273  return TlsGetValue(key);
274 #endif
275 }
276 
277 static OF_INLINE BOOL
278 of_tlskey_set(of_tlskey_t key, void *ptr)
279 {
280 #if defined(OF_HAVE_PTHREADS)
281  return !pthread_setspecific(key, ptr);
282 #elif defined(_WIN32)
283  return TlsSetValue(key, ptr);
284 #endif
285 }
286 
287 static OF_INLINE BOOL
288 of_tlskey_free(of_tlskey_t key)
289 {
290 #if defined(OF_HAVE_PTHREADS)
291  return !pthread_key_delete(key);
292 #elif defined(_WIN32)
293  return TlsFree(key);
294 #endif
295 }
296 
297 static OF_INLINE BOOL
298 of_spinlock_new(of_spinlock_t *spinlock)
299 {
300 #if defined(OF_ATOMIC_OPS)
301  *spinlock = 0;
302  return YES;
303 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
304  return !pthread_spin_init(spinlock, 0);
305 #else
306  return of_mutex_new(spinlock);
307 #endif
308 }
309 
310 static OF_INLINE BOOL
311 of_spinlock_trylock(of_spinlock_t *spinlock)
312 {
313 #if defined(OF_ATOMIC_OPS)
314  return of_atomic_cmpswap_int(spinlock, 0, 1);
315 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
316  return !pthread_spin_trylock(spinlock);
317 #else
318  return of_mutex_trylock(spinlock);
319 #endif
320 }
321 
322 static OF_INLINE BOOL
323 of_spinlock_lock(of_spinlock_t *spinlock)
324 {
325 #if defined(OF_ATOMIC_OPS)
326 # if defined(OF_HAVE_SCHED_YIELD) || defined(_WIN32)
327  int i;
328 
329  for (i = 0; i < OF_SPINCOUNT; i++)
330  if (of_spinlock_trylock(spinlock))
331  return YES;
332 
333  while (!of_spinlock_trylock(spinlock))
334 # ifndef _WIN32
335  sched_yield();
336 # else
337  Sleep(0);
338 # endif
339 # else
340  while (!of_spinlock_trylock(spinlock));
341 # endif
342 
343  return YES;
344 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
345  return !pthread_spin_lock(spinlock);
346 #else
347  return of_mutex_lock(spinlock);
348 #endif
349 }
350 
351 static OF_INLINE BOOL
352 of_spinlock_unlock(of_spinlock_t *spinlock)
353 {
354 #if defined(OF_ATOMIC_OPS)
355  *spinlock = 0;
356  return YES;
357 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
358  return !pthread_spin_unlock(spinlock);
359 #else
360  return of_mutex_unlock(spinlock);
361 #endif
362 }
363 
364 static OF_INLINE BOOL
365 of_spinlock_free(of_spinlock_t *spinlock)
366 {
367 #if defined(OF_ATOMIC_OPS)
368  return YES;
369 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
370  return !pthread_spin_destroy(spinlock);
371 #else
372  return of_mutex_free(spinlock);
373 #endif
374 }
375 
376 #ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES
377 static OF_INLINE BOOL
378 of_rmutex_new(of_mutex_t *mutex)
379 {
380  pthread_mutexattr_t attr;
381 
382  if (pthread_mutexattr_init(&attr))
383  return NO;
384 
385  if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
386  return NO;
387 
388  if (pthread_mutex_init(mutex, &attr))
389  return NO;
390 
391  if (pthread_mutexattr_destroy(&attr))
392  return NO;
393 
394  return YES;
395 }
396 
397 # define of_rmutex_lock of_mutex_lock
398 # define of_rmutex_trylock of_mutex_trylock
399 # define of_rmutex_unlock of_mutex_unlock
400 # define of_rmutex_free of_mutex_free
401 #else
402 static OF_INLINE BOOL
403 of_rmutex_new(of_rmutex_t *rmutex)
404 {
405  if (!of_mutex_new(&rmutex->mutex))
406  return NO;
407 
408  if (!of_tlskey_new(&rmutex->count))
409  return NO;
410 
411  return YES;
412 }
413 
414 static OF_INLINE BOOL
415 of_rmutex_lock(of_rmutex_t *rmutex)
416 {
417  uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count);
418 
419  if (count > 0) {
420  if (!of_tlskey_set(rmutex->count, (void*)(count + 1)))
421  return NO;
422  return YES;
423  }
424 
425  if (!of_mutex_lock(&rmutex->mutex))
426  return NO;
427 
428  if (!of_tlskey_set(rmutex->count, (void*)1)) {
429  of_mutex_unlock(&rmutex->mutex);
430  return NO;
431  }
432 
433  return YES;
434 }
435 
436 static OF_INLINE BOOL
437 of_rmutex_trylock(of_rmutex_t *rmutex)
438 {
439  uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count);
440 
441  if (count > 0) {
442  if (!of_tlskey_set(rmutex->count, (void*)(count + 1)))
443  return NO;
444  return YES;
445  }
446 
447  if (!of_mutex_trylock(&rmutex->mutex))
448  return NO;
449 
450  if (!of_tlskey_set(rmutex->count, (void*)1)) {
451  of_mutex_unlock(&rmutex->mutex);
452  return NO;
453  }
454 
455  return YES;
456 }
457 
458 static OF_INLINE BOOL
459 of_rmutex_unlock(of_rmutex_t *rmutex)
460 {
461  uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count);
462 
463  if (count > 1) {
464  if (!of_tlskey_set(rmutex->count, (void*)(count - 1)))
465  return NO;
466  return YES;
467  }
468 
469  if (!of_tlskey_set(rmutex->count, (void*)0))
470  return NO;
471 
472  if (!of_mutex_unlock(&rmutex->mutex))
473  return NO;
474 
475  return YES;
476 }
477 
478 static OF_INLINE BOOL
479 of_rmutex_free(of_rmutex_t *rmutex)
480 {
481  if (!of_mutex_free(&rmutex->mutex))
482  return NO;
483 
484  if (!of_tlskey_free(rmutex->count))
485  return NO;
486 
487  return YES;
488 }
489 #endif