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