ObjFW
threading.h
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
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_HAVE_THREADS) || \
20  (!defined(OF_HAVE_PTHREADS) && !defined(_WIN32))
21 # error No threads available!
22 #endif
23 
24 #include <math.h>
25 
26 #import "OFObject.h"
27 
28 #if defined(OF_HAVE_PTHREADS)
29 # include <pthread.h>
30 # include <sched.h>
31 typedef pthread_t of_thread_t;
32 typedef pthread_key_t of_tlskey_t;
33 typedef pthread_mutex_t of_mutex_t;
34 typedef pthread_cond_t of_condition_t;
35 typedef pthread_once_t of_once_t;
36 # define OF_ONCE_INIT PTHREAD_ONCE_INIT
37 #elif defined(_WIN32)
38 /*
39  * winsock2.h needs to be included before windows.h. Not including it here
40  * would make it impossible to use sockets after threading.h has been
41  * imported.
42  */
43 # ifdef OF_HAVE_SOCKETS
44 # include <winsock2.h>
45 # endif
46 # include <windows.h>
47 typedef HANDLE of_thread_t;
48 typedef DWORD of_tlskey_t;
49 typedef CRITICAL_SECTION of_mutex_t;
50 typedef struct {
51  HANDLE event;
52  int count;
53 } of_condition_t;
54 typedef volatile LONG of_once_t;
55 # define OF_ONCE_INIT 0
56 #else
57 # error No threads available!
58 #endif
59 
60 #if defined(OF_HAVE_ATOMIC_OPS)
61 # import "atomic.h"
62 typedef volatile int of_spinlock_t;
63 # define OF_SPINCOUNT 10
64 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
65 typedef pthread_spinlock_t of_spinlock_t;
66 #else
67 typedef of_mutex_t of_spinlock_t;
68 #endif
69 
70 #ifdef OF_HAVE_SCHED_YIELD
71 # include <sched.h>
72 #endif
73 
74 #if defined(OF_HAVE_RECURSIVE_PTHREAD_MUTEXES) || defined(_WIN32)
75 # define of_rmutex_t of_mutex_t
76 #else
77 typedef struct {
78  of_mutex_t mutex;
79  of_tlskey_t count;
80 } of_rmutex_t;
81 #endif
82 
83 typedef struct of_thread_attr_t {
84  float priority;
85  size_t stackSize;
86 } of_thread_attr_t;
87 
88 #if defined(OF_HAVE_PTHREADS)
89 # define of_thread_is_current(t) pthread_equal(t, pthread_self())
90 # define of_thread_current pthread_self
91 #elif defined(_WIN32)
92 # define of_thread_is_current(t) (t == GetCurrentThread())
93 # define of_thread_current GetCurrentThread
94 #else
95 # error of_thread_is_current not implemented!
96 # error of_thread_current not implemented!
97 #endif
98 
99 extern bool of_thread_attr_init(of_thread_attr_t *attr);
100 extern bool of_thread_new(of_thread_t *thread, void (*function)(id), id object,
101  const of_thread_attr_t *attr);
102 extern void of_thread_set_name(of_thread_t thread, const char *name);
103 extern bool of_thread_join(of_thread_t thread);
104 extern bool of_thread_detach(of_thread_t thread);
105 extern void OF_NO_RETURN_FUNC of_thread_exit(void);
106 extern void of_once(of_once_t *control, void (*func)(void));
107 extern bool of_mutex_new(of_mutex_t *mutex);
108 extern bool of_mutex_lock(of_mutex_t *mutex);
109 extern bool of_mutex_trylock(of_mutex_t *mutex);
110 extern bool of_mutex_unlock(of_mutex_t *mutex);
111 extern bool of_mutex_free(of_mutex_t *mutex);
112 extern bool of_rmutex_new(of_rmutex_t *rmutex);
113 extern bool of_rmutex_lock(of_rmutex_t *rmutex);
114 extern bool of_rmutex_trylock(of_rmutex_t *rmutex);
115 extern bool of_rmutex_unlock(of_rmutex_t *rmutex);
116 extern bool of_rmutex_free(of_rmutex_t *rmutex);
117 extern bool of_condition_new(of_condition_t *condition);
118 extern bool of_condition_signal(of_condition_t *condition);
119 extern bool of_condition_broadcast(of_condition_t *condition);
120 extern bool of_condition_wait(of_condition_t *condition, of_mutex_t *mutex);
121 extern bool of_condition_timed_wait(of_condition_t *condition,
122  of_mutex_t *mutex, of_time_interval_t timeout);
123 extern bool of_condition_free(of_condition_t *condition);
124 
125 /* TLS keys and spinlocks are inlined for performance. */
126 
127 static OF_INLINE bool
128 of_tlskey_new(of_tlskey_t *key)
129 {
130 #if defined(OF_HAVE_PTHREADS)
131  return !pthread_key_create(key, NULL);
132 #elif defined(_WIN32)
133  return ((*key = TlsAlloc()) != TLS_OUT_OF_INDEXES);
134 #else
135 # error of_tlskey_new not implemented!
136 #endif
137 }
138 
139 static OF_INLINE void*
140 of_tlskey_get(of_tlskey_t key)
141 {
142 #if defined(OF_HAVE_PTHREADS)
143  return pthread_getspecific(key);
144 #elif defined(_WIN32)
145  return TlsGetValue(key);
146 #else
147 # error of_tlskey_get not implemented!
148 #endif
149 }
150 
151 static OF_INLINE bool
152 of_tlskey_set(of_tlskey_t key, void *ptr)
153 {
154 #if defined(OF_HAVE_PTHREADS)
155  return !pthread_setspecific(key, ptr);
156 #elif defined(_WIN32)
157  return TlsSetValue(key, ptr);
158 #else
159 # error of_tlskey_set not implemented!
160 #endif
161 }
162 
163 static OF_INLINE bool
164 of_tlskey_free(of_tlskey_t key)
165 {
166 #if defined(OF_HAVE_PTHREADS)
167  return !pthread_key_delete(key);
168 #elif defined(_WIN32)
169  return TlsFree(key);
170 #else
171 # error of_tlskey_free not implemented!
172 #endif
173 }
174 
175 static OF_INLINE bool
176 of_spinlock_new(of_spinlock_t *spinlock)
177 {
178 #if defined(OF_HAVE_ATOMIC_OPS)
179  *spinlock = 0;
180  return true;
181 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
182  return !pthread_spin_init(spinlock, 0);
183 #else
184  return of_mutex_new(spinlock);
185 #endif
186 }
187 
188 static OF_INLINE bool
189 of_spinlock_trylock(of_spinlock_t *spinlock)
190 {
191 #if defined(OF_HAVE_ATOMIC_OPS)
192  return of_atomic_int_cmpswap(spinlock, 0, 1);
193 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
194  return !pthread_spin_trylock(spinlock);
195 #else
196  return of_mutex_trylock(spinlock);
197 #endif
198 }
199 
200 static OF_INLINE bool
201 of_spinlock_lock(of_spinlock_t *spinlock)
202 {
203 #if defined(OF_HAVE_ATOMIC_OPS)
204 # if defined(OF_HAVE_SCHED_YIELD) || defined(_WIN32)
205  int i;
206 
207  for (i = 0; i < OF_SPINCOUNT; i++)
208  if (of_spinlock_trylock(spinlock))
209  return true;
210 
211  while (!of_spinlock_trylock(spinlock))
212 # ifndef _WIN32
213  sched_yield();
214 # else
215  Sleep(0);
216 # endif
217 # else
218  while (!of_spinlock_trylock(spinlock));
219 # endif
220 
221  return true;
222 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
223  return !pthread_spin_lock(spinlock);
224 #else
225  return of_mutex_lock(spinlock);
226 #endif
227 }
228 
229 static OF_INLINE bool
230 of_spinlock_unlock(of_spinlock_t *spinlock)
231 {
232 #if defined(OF_HAVE_ATOMIC_OPS)
233  return of_atomic_int_cmpswap(spinlock, 1, 0);
234 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
235  return !pthread_spin_unlock(spinlock);
236 #else
237  return of_mutex_unlock(spinlock);
238 #endif
239 }
240 
241 static OF_INLINE bool
242 of_spinlock_free(of_spinlock_t *spinlock)
243 {
244 #if defined(OF_HAVE_ATOMIC_OPS)
245  return true;
246 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
247  return !pthread_spin_destroy(spinlock);
248 #else
249  return of_mutex_free(spinlock);
250 #endif
251 }
double of_time_interval_t
A time interval in seconds.
Definition: OFObject.h:90