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