1 #include "system.h"
2
3 #ifndef _WIN32
4
5 #include <stdlib.h>
6 #include <time.h>
7 #include <errno.h>
8 #include <unistd.h>
9 #if defined(__linux) || defined(__linux__)
10 #include <sys/prctl.h>
11 #endif
12
13 #define nullptr 0
14
15 struct Event
16 {
17 Event * volatile pMultipleCond;
18 pthread_mutex_t mutex;
19 pthread_cond_t cond;
20 volatile bool signaled;
21 bool manual_reset;
22 };
23
InitEvent(Event * e)24 static bool InitEvent(Event *e)
25 {
26 #if (defined(ANDROID) && !defined(__LP64__)) || defined(__APPLE__)
27 if (pthread_cond_init(&e->cond, NULL))
28 return false;
29 #else
30 pthread_condattr_t attr;
31 if (pthread_condattr_init(&attr))
32 return false;
33 if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC))
34 {
35 pthread_condattr_destroy(&attr);
36 return false;
37 }
38 if (pthread_cond_init(&e->cond, &attr))
39 {
40 pthread_condattr_destroy(&attr);
41 return false;
42 }
43 pthread_condattr_destroy(&attr);
44 #endif
45 if (pthread_mutex_init(&e->mutex, NULL))
46 {
47 pthread_cond_destroy(&e->cond);
48 return false;
49 }
50 e->pMultipleCond = NULL;
51 return true;
52 }
53
54 #ifdef __APPLE__
55 #include <mach/mach_time.h>
GetAbsTimeInNanoseconds()56 static inline uint64_t GetAbsTimeInNanoseconds()
57 {
58 static mach_timebase_info_data_t g_timebase_info;
59 if (g_timebase_info.denom == 0)
60 mach_timebase_info(&g_timebase_info);
61 return mach_absolute_time()*g_timebase_info.numer/g_timebase_info.denom;
62 }
63 #endif
64
GetAbsTime(timespec * ts,uint32_t timeout)65 static inline void GetAbsTime(timespec *ts, uint32_t timeout)
66 {
67 #if defined(__APPLE__)
68 uint64_t cur_time = GetAbsTimeInNanoseconds();
69 ts->tv_sec = cur_time/1000000000u + timeout/1000u;
70 ts->tv_nsec = (cur_time % 1000000000u) + (timeout % 1000u)*1000000u;
71 #else
72 clock_gettime(CLOCK_MONOTONIC, ts);
73 ts->tv_sec += timeout/1000u;
74 ts->tv_nsec += (timeout % 1000u)*1000000u;
75 #endif
76 if (ts->tv_nsec >= 1000000000)
77 {
78 ts->tv_nsec -= 1000000000;
79 ts->tv_sec++;
80 }
81 }
82
CondTimedWait(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * abstime)83 static inline int CondTimedWait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
84 {
85 #if defined(ANDROID) && !defined(__LP64__)
86 return pthread_cond_timedwait_monotonic_np(cond, mutex, abstime);
87 #elif defined(__APPLE__)
88 timespec reltime;
89 uint64_t cur_time = GetAbsTimeInNanoseconds();
90 reltime.tv_sec = abstime->tv_sec - cur_time/1000000000u;
91 reltime.tv_nsec = abstime->tv_nsec - (cur_time % 1000000000u);
92 if (reltime.tv_nsec < 0)
93 {
94 reltime.tv_nsec += 1000000000;
95 reltime.tv_sec--;
96 }
97 if ((reltime.tv_sec < 0) || ((reltime.tv_sec == 0) && (reltime.tv_nsec == 0)))
98 return ETIMEDOUT;
99 return pthread_cond_timedwait_relative_np(cond, mutex, &reltime);
100 #else
101 return pthread_cond_timedwait(cond, mutex, abstime);
102 #endif
103 }
104
WaitForEvent(Event * e,uint32_t timeout,bool * signaled)105 static bool WaitForEvent(Event *e, uint32_t timeout, bool *signaled)
106 {
107 if (pthread_mutex_lock(&e->mutex))
108 return false;
109
110 if (timeout == INFINITE)
111 {
112 while (!e->signaled)
113 pthread_cond_wait(&e->cond, &e->mutex);
114 } else if (timeout != 0)
115 {
116 timespec t;
117 GetAbsTime(&t, timeout);
118 while (!e->signaled)
119 {
120 if (CondTimedWait(&e->cond, &e->mutex, &t))
121 break;
122 }
123 }
124 *signaled = e->signaled;
125 if (!e->manual_reset)
126 e->signaled = false;
127
128 if (pthread_mutex_unlock(&e->mutex))
129 return false;
130 return true;
131 }
132
WaitForMultipleEvents(Event ** e,uint32_t count,uint32_t timeout,bool waitAll,int * signaled_num)133 static bool WaitForMultipleEvents(Event **e, uint32_t count, uint32_t timeout, bool waitAll, int *signaled_num)
134 {
135 uint32_t i;
136 #define PTHR(func, num) for (i = num; i < count; i++)\
137 if (func(&e[i]->mutex))\
138 return false;
139 PTHR(pthread_mutex_lock, 0);
140
141 int sig_num = -1;
142 if (timeout == 0)
143 {
144 #define CHECK_SIGNALED \
145 if (waitAll)\
146 {\
147 for (i = 0; i < count; i++)\
148 if (!e[i]->signaled)\
149 break;\
150 if (i == count)\
151 for (i = 0; i < count; i++)\
152 {\
153 if (sig_num < 0 && e[i]->signaled)\
154 sig_num = (int)i;\
155 if (!e[i]->manual_reset)\
156 e[i]->signaled = false;\
157 }\
158 } else\
159 {\
160 for (i = 0; i < count; i++)\
161 if (e[i]->signaled)\
162 {\
163 sig_num = (int)i;\
164 if (!e[i]->manual_reset)\
165 e[i]->signaled = false;\
166 break;\
167 }\
168 }
169 CHECK_SIGNALED;
170 } else
171 if (timeout == INFINITE)
172 {
173 #define SET_MULTIPLE(val) for (i = 1; i < count; i++)\
174 e[i]->pMultipleCond = val;
175 SET_MULTIPLE(e[0]);
176 for (;;)
177 {
178 CHECK_SIGNALED;
179 if (sig_num >= 0)
180 break;
181 PTHR(pthread_mutex_unlock, 1);
182 pthread_cond_wait(&e[0]->cond, &e[0]->mutex);
183 PTHR(pthread_mutex_lock, 1);
184 }
185 SET_MULTIPLE(0);
186 } else
187 {
188 SET_MULTIPLE(e[0]);
189 timespec t;
190 GetAbsTime(&t, timeout);
191 for (;;)
192 {
193 CHECK_SIGNALED;
194 if (sig_num >= 0)
195 break;
196 PTHR(pthread_mutex_unlock, 1);
197 int res = CondTimedWait(&e[0]->cond, &e[0]->mutex, &t);
198 PTHR(pthread_mutex_lock, 1);
199 if (res)
200 break;
201 }
202 SET_MULTIPLE(0);
203 }
204 PTHR(pthread_mutex_unlock, 0);
205 *signaled_num = sig_num;
206 return true;
207 }
208
SignalEvent(Event * e)209 static bool SignalEvent(Event *e)
210 {
211 if (pthread_mutex_lock(&e->mutex))
212 return false;
213
214 Event *pMultipleCond = e->pMultipleCond;
215 e->signaled = true;
216 if (pthread_cond_signal(&e->cond))
217 return false;
218
219 if (pthread_mutex_unlock(&e->mutex))
220 return false;
221
222 if (pMultipleCond && pMultipleCond != e)
223 {
224 if (pthread_mutex_lock(&pMultipleCond->mutex))
225 return false;
226 if (pthread_cond_signal(&pMultipleCond->cond))
227 return false;
228 if (pthread_mutex_unlock(&pMultipleCond->mutex))
229 return false;
230 }
231 return true;
232 }
233
ResetEvent(Event * e)234 static bool ResetEvent(Event *e)
235 {
236 if (pthread_mutex_lock(&e->mutex))
237 return false;
238 e->signaled = false;
239 if (pthread_mutex_unlock(&e->mutex))
240 return false;
241 return true;
242 }
243
event_create(bool manualReset,bool initialState)244 HANDLE event_create(bool manualReset, bool initialState)
245 {
246 Event *e = (Event *)malloc(sizeof(*e));
247 if (!e)
248 return NULL;
249 if (!InitEvent(e))
250 {
251 free(e);
252 return NULL;
253 }
254 e->manual_reset = manualReset;
255 e->signaled = initialState;
256 return (HANDLE)e;
257 }
258
event_destroy(HANDLE event)259 bool event_destroy(HANDLE event)
260 {
261 Event *e = (Event *)event;
262 if (!e)
263 return false;
264 if (pthread_cond_destroy(&e->cond))
265 return false;
266 if (pthread_mutex_destroy(&e->mutex))
267 return false;
268 free((void *)e);
269 return true;
270 }
271
event_set(HANDLE event)272 bool event_set(HANDLE event)
273 {
274 return SignalEvent((Event *)event);
275 }
276
event_reset(HANDLE event)277 bool event_reset(HANDLE event)
278 {
279 return ResetEvent((Event *)event);
280 }
281
event_wait(HANDLE event,uint32_t milliseconds)282 int event_wait(HANDLE event, uint32_t milliseconds)
283 {
284 bool signaled;
285 if (!WaitForEvent((Event *)event, milliseconds, &signaled))
286 return WAIT_FAILED;
287 return signaled ? WAIT_OBJECT : WAIT_TIMEOUT;
288 }
289
event_wait_multiple(uint32_t count,const HANDLE * events,bool waitAll,uint32_t milliseconds)290 int event_wait_multiple(uint32_t count, const HANDLE *events, bool waitAll, uint32_t milliseconds)
291 {
292 if (count == 1)
293 return event_wait(events[0], milliseconds);
294 int signaled_num = -1;
295 if (!WaitForMultipleEvents((Event **)events, count, milliseconds, waitAll, &signaled_num))
296 return WAIT_FAILED;
297 return (signaled_num < 0) ? WAIT_TIMEOUT : (WAIT_OBJECT_0 + signaled_num);
298 }
299
InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection)300 bool InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
301 {
302 pthread_mutexattr_t ma;
303 if (pthread_mutexattr_init(&ma))
304 return false;
305 if (pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE))
306 {
307 pthread_mutexattr_destroy(&ma);
308 return false;
309 }
310 if (pthread_mutex_init((pthread_mutex_t *)lpCriticalSection, &ma))
311 {
312 pthread_mutexattr_destroy(&ma);
313 return false;
314 }
315 if (pthread_mutexattr_destroy(&ma))
316 return false;
317 return true;
318 }
319
DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)320 bool DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
321 {
322 if (pthread_mutex_destroy((pthread_mutex_t *)lpCriticalSection))
323 return false;
324 return true;
325 }
326
EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)327 bool EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
328 {
329 if (pthread_mutex_lock((pthread_mutex_t *)lpCriticalSection))
330 return false;
331 return true;
332 }
333
LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)334 bool LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
335 {
336 if (pthread_mutex_unlock((pthread_mutex_t *)lpCriticalSection))
337 return false;
338 return true;
339 }
340
thread_create(LPTHREAD_START_ROUTINE lpStartAddress,void * lpParameter)341 HANDLE thread_create(LPTHREAD_START_ROUTINE lpStartAddress, void *lpParameter)
342 {
343 pthread_t *t = (pthread_t *)malloc(sizeof(*t));
344 if (!t)
345 return nullptr;
346 if (pthread_create(t, 0, lpStartAddress, lpParameter))
347 {
348 free(t);
349 return nullptr;
350 }
351 //if (lpThreadId)
352 // *lpThreadId = (uint32_t)*t;
353 return (HANDLE)t;
354 }
355
thread_close(HANDLE thread)356 bool thread_close(HANDLE thread)
357 {
358 if (!thread)
359 return false;
360 pthread_t *t = (pthread_t *)thread;
361 if (*t)
362 pthread_detach(*t);
363 free(t);
364 return true;
365 }
366
thread_wait(HANDLE thread)367 void *thread_wait(HANDLE thread)
368 {
369 if (!thread)
370 return (void*)-1;
371 void *ret = 0;
372 pthread_t *t = (pthread_t *)thread;
373 if (!*t)
374 return ret;
375 int res = pthread_join(*t, &ret);
376 if (res)
377 return (void*)-1;
378 #if 0
379 if (timeout == 0)
380 {
381 int res = pthread_tryjoin_np(*t, &ret);
382 if (res)
383 return false;
384 } else
385 if (timeout == INFINITE)
386 {
387 int res = pthread_join(*t, &ret);
388 if (res)
389 return false;
390 } else
391 {
392 timespec ts;
393 GetAbsTime(&ts, timeout);
394 int res = pthread_timedjoin_np(*t, &ret, &ts);
395 if (res)
396 return false;
397 }
398 #endif
399 *t = 0; // thread joined - no need to detach
400 return ret;
401 }
402
403 #else //_WIN32
404
event_destroy(HANDLE event)405 bool event_destroy(HANDLE event)
406 {
407 CloseHandle(event);
408 return true;
409 }
410
thread_close(HANDLE thread)411 bool thread_close(HANDLE thread)
412 {
413 CloseHandle(thread);
414 return true;
415 }
416
thread_wait(HANDLE thread)417 bool thread_wait(HANDLE thread)
418 {
419 return WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0;
420 }
421
422 #endif //_WIN32
423
thread_name(const char * name)424 bool thread_name(const char *name)
425 {
426 #ifdef _WIN32
427 struct tagTHREADNAME_INFO
428 {
429 DWORD dwType;
430 LPCSTR szName;
431 DWORD dwThreadID;
432 DWORD dwFlags;
433 } info = { 0x1000, name, (DWORD)-1, 0 };
434 __try
435 {
436 RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
437 }
438 __except(EXCEPTION_EXECUTE_HANDLER)
439 {
440 }
441 return true;
442 #elif defined(__linux) || defined(__linux__)
443 return (0 == prctl(PR_SET_NAME, name, 0, 0, 0));
444 //return (0 == pthread_setname_np(pthread_self(), name));
445 #else // macos, ios
446 return (0 == pthread_setname_np(name));
447 #endif
448 }
449
thread_sleep(uint32_t milliseconds)450 void thread_sleep(uint32_t milliseconds)
451 {
452 #ifdef _WIN32
453 Sleep(milliseconds);
454 #else
455 usleep((useconds_t)milliseconds*1000);
456 #endif
457 }
458
GetTime()459 uint64_t GetTime()
460 {
461 uint64_t time;
462 #ifdef _WIN32
463 QueryPerformanceCounter((LARGE_INTEGER*)&time);
464 #elif defined(__APPLE__)
465 time = GetAbsTimeInNanoseconds() / 1000u;
466 #else
467 timespec ts;
468 // CLOCK_PROCESS_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID
469 clock_gettime(CLOCK_MONOTONIC, &ts);
470 time = (uint64_t)ts.tv_sec * 1000000u + ts.tv_nsec / 1000u;
471 #endif
472 return time;
473 }
474