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