1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <fs/thread.h>
6 #include <fs/base.h>
7 #include <stdlib.h>
8 #ifdef USE_GLIB
9 #include <glib.h>
10 #endif
11 #ifdef USE_SDL2
12 #define USE_SDL
13 #endif
14 #ifdef USE_SDL
15 #include <SDL.h>
16 #include <SDL_thread.h>
17 #endif
18 #ifdef USE_PTHREADS
19 #include <pthread.h>
20 #define USE_PSEM
21 #endif
22 #ifdef USE_PSEM
23 #include <semaphore.h>
24 #endif
25
26 struct fs_thread {
27 #if defined(USE_PTHREADS)
28 pthread_t thread;
29 pthread_attr_t attr;
30 #elif defined(USE_GLIB)
31 GThread *thread;
32 #endif
33 };
34
35 struct fs_mutex {
36 #if defined(USE_PTHREADS)
37 pthread_mutex_t mutex;
38 #elif defined(USE_GLIB)
39 GMutex mutex;
40 #elif defined(USE_SDL)
41 SDL_mutex* mutex;
42 #endif
43 };
44
45 struct fs_condition {
46 #if defined(USE_PTHREADS)
47 pthread_cond_t condition;
48 #elif defined(USE_GLIB)
49 GCond condition;
50 #elif defined(USE_SDL)
51 SDL_cond* condition;
52 #endif
53 };
54
55 struct fs_semaphore {
56 #if defined(USE_PSEM)
57 sem_t semaphore;
58 #elif defined(USE_SDL)
59 SDL_sem* semaphore;
60 #endif
61 };
62
fs_thread_id(void)63 fs_thread_id_t fs_thread_id(void)
64 {
65 fs_thread_id_t thread_id = 0;
66 #if defined(USE_GLIB)
67 thread_id = (uintptr_t) g_thread_self();
68 #else
69 #error no thread support
70 #endif
71 return thread_id;
72 }
73
fs_thread_create(const char * name,fs_thread_function fn,void * data)74 fs_thread *fs_thread_create(
75 const char *name, fs_thread_function fn, void *data)
76 {
77 fs_thread *thread = (fs_thread *) g_malloc(sizeof(fs_thread));
78 #if defined(USE_PTHREADS)
79 pthread_attr_init(&thread->attr);
80 pthread_attr_setdetachstate(&thread->attr, PTHREAD_CREATE_JOINABLE);
81 pthread_create(&thread->thread, &thread->attr, fn, data);
82 #elif defined(USE_GLIB)
83 thread->thread = g_thread_new(name, fn, data);
84 #else
85 #error no thread support
86 #endif
87 return thread;
88 }
89
90 #if 0
91 fs_thread *fs_thread_create_detached(
92 const char *name, fs_thread_function fn, void *data)
93 {
94 fs_thread *thread = (fs_thread *) g_malloc(sizeof(fs_thread));
95 #if defined(USE_PTHREADS)
96 pthread_attr_init(&thread->attr);
97 pthread_attr_setdetachstate(&thread->attr, PTHREAD_CREATE_DETACHED);
98 pthread_create(&thread->thread, &thread->attr, fn, data);
99 #elif defined(USE_GLIB)
100 thread->thread = g_thread_create(fn, data, FALSE, NULL);
101 #else
102 #error no thread support
103 #endif
104 return thread;
105 }
106 #endif
107
fs_thread_wait(fs_thread * thread)108 void *fs_thread_wait(fs_thread *thread)
109 {
110 void *result;
111 #if defined(USE_PTHREADS)
112 pthread_join(thread->thread, &result);
113 pthread_attr_destroy(&thread->attr);
114 #elif defined(USE_GLIB)
115 /* FIXME: can use g_thread_ref if we want to keep a reference, and
116 * implement fs_thread_destroy separately */
117 result = g_thread_join(thread->thread);
118 #else
119 #error no thread support
120 #endif
121 return result;
122 }
123
fs_thread_free(fs_thread * thread)124 void fs_thread_free(fs_thread *thread)
125 {
126 g_free(thread);
127 }
128
fs_mutex_create()129 fs_mutex *fs_mutex_create()
130 {
131 fs_mutex *mutex = (fs_mutex *) g_malloc(sizeof(fs_mutex));
132 #if defined(USE_PTHREADS)
133 pthread_mutex_init(&mutex->mutex, NULL);
134 #elif defined(USE_GLIB)
135 g_mutex_init(&mutex->mutex);
136 #elif defined(USE_SDL)
137 mutex->mutex = SDL_CreateMutex();
138 #else
139 #error no thread support
140 #endif
141 return mutex;
142 }
143
fs_mutex_destroy(fs_mutex * mutex)144 void fs_mutex_destroy(fs_mutex *mutex)
145 {
146 #if defined(USE_PTHREADS)
147 pthread_mutex_destroy(&mutex->mutex);
148 #elif defined(USE_GLIB)
149 g_mutex_clear(&mutex->mutex);
150 #elif defined(USE_SDL)
151 SDL_DestroyMutex(mutex->mutex);
152 #else
153 #error no thread support
154 #endif
155 g_free(mutex);
156 }
157
fs_mutex_lock(fs_mutex * mutex)158 int fs_mutex_lock(fs_mutex *mutex)
159 {
160 #if defined(USE_PTHREADS)
161 return pthread_mutex_lock(&mutex->mutex);
162 #elif defined(USE_GLIB)
163 g_mutex_lock(&mutex->mutex);
164 return 0;
165 #elif defined(USE_SDL)
166 return SDL_mutexP(mutex->mutex);
167 #else
168 #error no thread support
169 #endif
170 }
171
fs_mutex_unlock(fs_mutex * mutex)172 int fs_mutex_unlock(fs_mutex *mutex)
173 {
174 #if defined(USE_PTHREADS)
175 return pthread_mutex_unlock(&mutex->mutex);
176 #elif defined(USE_GLIB)
177 g_mutex_unlock(&mutex->mutex);
178 return 0;
179 #elif defined(USE_SDL)
180 return SDL_mutexV(mutex->mutex);
181 #else
182 #error no thread support
183 #endif
184 }
185
fs_condition_create(void)186 fs_condition *fs_condition_create(void)
187 {
188 fs_condition *condition = (fs_condition *) g_malloc(sizeof(fs_condition));
189 #if defined(USE_PTHREADS)
190 pthread_cond_init(&condition->condition, NULL);
191 #elif defined(USE_GLIB)
192 g_cond_init(&condition->condition);
193 #elif defined(USE_SDL)
194 condition->condition = SDL_CreateCond();
195 #else
196 #error no thread support
197 #endif
198 return condition;
199 }
200
fs_condition_destroy(fs_condition * condition)201 void fs_condition_destroy(fs_condition *condition)
202 {
203 #if defined(USE_PTHREADS)
204 pthread_cond_destroy(&condition->condition);
205 #elif defined(USE_GLIB)
206 g_cond_clear(&condition->condition);
207 #elif defined(USE_SDL)
208 SDL_DestroyCond(condition->condition);
209 #else
210 #error no thread support
211 #endif
212 g_free(condition);
213 }
214
fs_condition_wait(fs_condition * condition,fs_mutex * mutex)215 int fs_condition_wait (fs_condition *condition, fs_mutex *mutex)
216 {
217 #if defined(USE_PTHREADS)
218 return pthread_cond_wait(&condition->condition, &mutex->mutex);
219 #elif defined(USE_GLIB)
220 g_cond_wait(&condition->condition, &mutex->mutex);
221 return 0;
222 #elif defined(USE_SDL)
223 return SDL_CondWait(condition->condition, mutex->mutex);
224 #else
225 #error no thread support
226 #endif
227 }
228
fs_condition_get_wait_end_time(int period)229 int64_t fs_condition_get_wait_end_time(int period)
230 {
231 #if defined(USE_PTHREADS)
232 #error FIXME: implement with clock_gettime(CLOCK_REALTIME, &ts);
233 #elif defined(USE_GLIB)
234 return g_get_monotonic_time() + period;
235 #else
236 return fs_get_current_time() + period;
237 #endif
238 }
239
fs_condition_wait_until(fs_condition * condition,fs_mutex * mutex,int64_t end_time)240 int fs_condition_wait_until(
241 fs_condition *condition, fs_mutex *mutex, int64_t end_time)
242 {
243 #if defined(USE_PTHREADS)
244 struct timespec tv;
245 tv.tv_sec = end_time / 1000000;
246 tv.tv_nsec = (end_time % 1000000) * 1000;
247 return pthread_cond_timedwait(&condition->condition, &mutex->mutex, &tv);
248 #elif defined(USE_GLIB)
249 gboolean result = g_cond_wait_until(
250 &condition->condition, &mutex->mutex, end_time);
251 return !result;
252 #elif defined(USE_SDL2)
253 #error FIXME: implement with SDL_CondWaitTimeout
254 #elif defined(USE_SDL)
255 #error no support for timed condition wait
256 #else
257 #error no thread support
258 #endif
259 }
260
fs_condition_signal(fs_condition * condition)261 int fs_condition_signal(fs_condition *condition)
262 {
263 #if defined(USE_PTHREADS)
264 return pthread_cond_signal(&condition->condition);
265 #elif defined(USE_GLIB)
266 g_cond_signal(&condition->condition);
267 return 0;
268 #elif defined(USE_SDL)
269 return SDL_CondSignal(condition->condition);
270 #else
271 #error no thread support
272 #endif
273 }
274
fs_semaphore_create(int value)275 fs_semaphore *fs_semaphore_create(int value)
276 {
277 fs_semaphore *semaphore = (fs_semaphore *) g_malloc(sizeof(fs_semaphore));
278 #if defined(USE_PSEM)
279 sem_init(&semaphore->semaphore, 1, value);
280 #elif defined(USE_SDL)
281 semaphore->semaphore = SDL_CreateSemaphore(value);
282 #else
283 #error no thread support
284 #endif
285 return semaphore;
286 }
287
fs_semaphore_destroy(fs_semaphore * semaphore)288 void fs_semaphore_destroy(fs_semaphore *semaphore)
289 {
290 #if defined(USE_PSEM)
291 sem_destroy(&semaphore->semaphore);
292 #elif defined(USE_SDL)
293 SDL_DestroySemaphore(semaphore->semaphore);
294 #else
295 #error no thread support
296 #endif
297 g_free(semaphore);
298 }
299
fs_semaphore_post(fs_semaphore * semaphore)300 int fs_semaphore_post(fs_semaphore *semaphore)
301 {
302 #if defined(USE_PSEM)
303 return sem_post(&semaphore->semaphore);
304 #elif defined(USE_SDL)
305 return SDL_SemPost(semaphore->semaphore);
306 #else
307 #error no thread support
308 #endif
309 }
310
fs_semaphore_wait(fs_semaphore * semaphore)311 int fs_semaphore_wait(fs_semaphore *semaphore)
312 {
313 #if defined(USE_PSEM)
314 return sem_wait(&semaphore->semaphore);
315 #elif defined(USE_SDL)
316 return SDL_SemWait(semaphore->semaphore);
317 #else
318 #error no thread support
319 #endif
320 }
321
fs_semaphore_try_wait(fs_semaphore * semaphore)322 int fs_semaphore_try_wait(fs_semaphore *semaphore)
323 {
324 #if defined(USE_PSEM)
325 return sem_trywait(&semaphore->semaphore);
326 #elif defined(USE_SDL)
327 return SDL_SemTryWait(semaphore->semaphore);
328 #else
329 #error no thread support
330 #endif
331 }
332