threading.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. #if defined(GB_SYSTEM_LINUX)
  2. #include <signal.h>
  3. #endif
  4. struct BlockingMutex;
  5. struct RecursiveMutex;
  6. struct Semaphore;
  7. struct Condition;
  8. struct Thread;
  9. #define THREAD_PROC(name) isize name(struct Thread *thread)
  10. typedef THREAD_PROC(ThreadProc);
  11. struct Thread {
  12. #if defined(GB_SYSTEM_WINDOWS)
  13. void * win32_handle;
  14. #else
  15. pthread_t posix_handle;
  16. #endif
  17. ThreadProc * proc;
  18. void * user_data;
  19. isize user_index;
  20. isize volatile return_value;
  21. Semaphore * semaphore;
  22. isize stack_size;
  23. std::atomic<bool> is_running;
  24. };
  25. void mutex_init (BlockingMutex *m);
  26. void mutex_destroy (BlockingMutex *m);
  27. void mutex_lock (BlockingMutex *m);
  28. bool mutex_try_lock(BlockingMutex *m);
  29. void mutex_unlock (BlockingMutex *m);
  30. void mutex_init (RecursiveMutex *m);
  31. void mutex_destroy (RecursiveMutex *m);
  32. void mutex_lock (RecursiveMutex *m);
  33. bool mutex_try_lock(RecursiveMutex *m);
  34. void mutex_unlock (RecursiveMutex *m);
  35. void semaphore_init (Semaphore *s);
  36. void semaphore_destroy(Semaphore *s);
  37. void semaphore_post (Semaphore *s, i32 count);
  38. void semaphore_wait (Semaphore *s);
  39. void semaphore_release(Semaphore *s) { semaphore_post(s, 1); }
  40. void condition_init(Condition *c);
  41. void condition_destroy(Condition *c);
  42. void condition_broadcast(Condition *c);
  43. void condition_signal(Condition *c);
  44. void condition_wait(Condition *c, BlockingMutex *m);
  45. void condition_wait_with_timeout(Condition *c, BlockingMutex *m, u32 timeout_in_ms);
  46. u32 thread_current_id(void);
  47. void thread_init (Thread *t);
  48. void thread_destroy (Thread *t);
  49. void thread_start (Thread *t, ThreadProc *proc, void *data);
  50. void thread_start_with_stack(Thread *t, ThreadProc *proc, void *data, isize stack_size);
  51. void thread_join (Thread *t);
  52. bool thread_is_running (Thread const *t);
  53. void thread_set_name (Thread *t, char const *name);
  54. void yield_thread(void);
  55. void yield_process(void);
  56. #if defined(GB_SYSTEM_WINDOWS)
  57. struct BlockingMutex {
  58. SRWLOCK srwlock;
  59. };
  60. void mutex_init(BlockingMutex *m) {
  61. }
  62. void mutex_destroy(BlockingMutex *m) {
  63. }
  64. void mutex_lock(BlockingMutex *m) {
  65. AcquireSRWLockExclusive(&m->srwlock);
  66. }
  67. bool mutex_try_lock(BlockingMutex *m) {
  68. return !!TryAcquireSRWLockExclusive(&m->srwlock);
  69. }
  70. void mutex_unlock(BlockingMutex *m) {
  71. ReleaseSRWLockExclusive(&m->srwlock);
  72. }
  73. struct RecursiveMutex {
  74. CRITICAL_SECTION win32_critical_section;
  75. };
  76. void mutex_init(RecursiveMutex *m) {
  77. InitializeCriticalSection(&m->win32_critical_section);
  78. }
  79. void mutex_destroy(RecursiveMutex *m) {
  80. DeleteCriticalSection(&m->win32_critical_section);
  81. }
  82. void mutex_lock(RecursiveMutex *m) {
  83. EnterCriticalSection(&m->win32_critical_section);
  84. }
  85. bool mutex_try_lock(RecursiveMutex *m) {
  86. return TryEnterCriticalSection(&m->win32_critical_section) != 0;
  87. }
  88. void mutex_unlock(RecursiveMutex *m) {
  89. LeaveCriticalSection(&m->win32_critical_section);
  90. }
  91. struct Semaphore {
  92. void *win32_handle;
  93. };
  94. void semaphore_init(Semaphore *s) {
  95. s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL);
  96. }
  97. void semaphore_destroy(Semaphore *s) {
  98. CloseHandle(s->win32_handle);
  99. }
  100. void semaphore_post(Semaphore *s, i32 count) {
  101. ReleaseSemaphore(s->win32_handle, count, NULL);
  102. }
  103. void semaphore_wait(Semaphore *s) {
  104. WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE);
  105. }
  106. struct Condition {
  107. CONDITION_VARIABLE cond;
  108. };
  109. void condition_init(Condition *c) {
  110. }
  111. void condition_destroy(Condition *c) {
  112. }
  113. void condition_broadcast(Condition *c) {
  114. WakeAllConditionVariable(&c->cond);
  115. }
  116. void condition_signal(Condition *c) {
  117. WakeConditionVariable(&c->cond);
  118. }
  119. void condition_wait(Condition *c, BlockingMutex *m) {
  120. SleepConditionVariableSRW(&c->cond, &m->srwlock, INFINITE, 0);
  121. }
  122. void condition_wait_with_timeout(Condition *c, BlockingMutex *m, u32 timeout_in_ms) {
  123. SleepConditionVariableSRW(&c->cond, &m->srwlock, timeout_in_ms, 0);
  124. }
  125. #else
  126. struct BlockingMutex {
  127. pthread_mutex_t pthread_mutex;
  128. };
  129. void mutex_init(BlockingMutex *m) {
  130. pthread_mutex_init(&m->pthread_mutex, nullptr);
  131. }
  132. void mutex_destroy(BlockingMutex *m) {
  133. pthread_mutex_destroy(&m->pthread_mutex);
  134. }
  135. void mutex_lock(BlockingMutex *m) {
  136. pthread_mutex_lock(&m->pthread_mutex);
  137. }
  138. bool mutex_try_lock(BlockingMutex *m) {
  139. return pthread_mutex_trylock(&m->pthread_mutex) == 0;
  140. }
  141. void mutex_unlock(BlockingMutex *m) {
  142. pthread_mutex_unlock(&m->pthread_mutex);
  143. }
  144. struct RecursiveMutex {
  145. pthread_mutex_t pthread_mutex;
  146. pthread_mutexattr_t pthread_mutexattr;
  147. };
  148. void mutex_init(RecursiveMutex *m) {
  149. pthread_mutexattr_init(&m->pthread_mutexattr);
  150. pthread_mutexattr_settype(&m->pthread_mutexattr, PTHREAD_MUTEX_RECURSIVE);
  151. pthread_mutex_init(&m->pthread_mutex, &m->pthread_mutexattr);
  152. }
  153. void mutex_destroy(RecursiveMutex *m) {
  154. pthread_mutex_destroy(&m->pthread_mutex);
  155. }
  156. void mutex_lock(RecursiveMutex *m) {
  157. pthread_mutex_lock(&m->pthread_mutex);
  158. }
  159. bool mutex_try_lock(RecursiveMutex *m) {
  160. return pthread_mutex_trylock(&m->pthread_mutex) == 0;
  161. }
  162. void mutex_unlock(RecursiveMutex *m) {
  163. pthread_mutex_unlock(&m->pthread_mutex);
  164. }
  165. #if defined(GB_SYSTEM_OSX)
  166. struct Semaphore {
  167. semaphore_t osx_handle;
  168. };
  169. void semaphore_init (Semaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); }
  170. void semaphore_destroy(Semaphore *s) { semaphore_destroy(mach_task_self(), s->osx_handle); }
  171. void semaphore_post (Semaphore *s, i32 count) { while (count --> 0) semaphore_signal(s->osx_handle); }
  172. void semaphore_wait (Semaphore *s) { semaphore_wait(s->osx_handle); }
  173. #elif defined(GB_SYSTEM_UNIX)
  174. struct Semaphore {
  175. sem_t unix_handle;
  176. };
  177. void semaphore_init (Semaphore *s) { sem_init(&s->unix_handle, 0, 0); }
  178. void semaphore_destroy(Semaphore *s) { sem_destroy(&s->unix_handle); }
  179. void semaphore_post (Semaphore *s, i32 count) { while (count --> 0) sem_post(&s->unix_handle); }
  180. void semaphore_wait (Semaphore *s) { int i; do { i = sem_wait(&s->unix_handle); } while (i == -1 && errno == EINTR); }
  181. #else
  182. #error Implement Semaphore for this platform
  183. #endif
  184. struct Condition {
  185. pthread_cond_t pthread_cond;
  186. };
  187. void condition_init(Condition *c) {
  188. pthread_cond_init(&c->pthread_cond, NULL);
  189. }
  190. void condition_destroy(Condition *c) {
  191. pthread_cond_destroy(&c->pthread_cond);
  192. }
  193. void condition_broadcast(Condition *c) {
  194. pthread_cond_broadcast(&c->pthread_cond);
  195. }
  196. void condition_signal(Condition *c) {
  197. pthread_cond_signal(&c->pthread_cond);
  198. }
  199. void condition_wait(Condition *c, BlockingMutex *m) {
  200. pthread_cond_wait(&c->pthread_cond, &m->pthread_mutex);
  201. }
  202. void condition_wait_with_timeout(Condition *c, BlockingMutex *m, u32 timeout_in_ms) {
  203. struct timespec abstime = {};
  204. abstime.tv_sec = timeout_in_ms/1000;
  205. abstime.tv_nsec = cast(long)(timeout_in_ms%1000)*1e6;
  206. pthread_cond_timedwait(&c->pthread_cond, &m->pthread_mutex, &abstime);
  207. }
  208. #endif
  209. struct Barrier {
  210. BlockingMutex mutex;
  211. Condition cond;
  212. isize index;
  213. isize generation_id;
  214. isize thread_count;
  215. };
  216. void barrier_init(Barrier *b, isize thread_count) {
  217. mutex_init(&b->mutex);
  218. condition_init(&b->cond);
  219. b->index = 0;
  220. b->generation_id = 0;
  221. b->thread_count = 0;
  222. }
  223. void barrier_destroy(Barrier *b) {
  224. condition_destroy(&b->cond);
  225. mutex_destroy(&b->mutex);
  226. }
  227. // Returns true if it is the leader
  228. bool barrier_wait(Barrier *b) {
  229. mutex_lock(&b->mutex);
  230. defer (mutex_unlock(&b->mutex));
  231. isize local_gen = b->generation_id;
  232. b->index += 1;
  233. if (b->index < b->thread_count) {
  234. while (local_gen == b->generation_id && b->index < b->thread_count) {
  235. condition_wait(&b->cond, &b->mutex);
  236. }
  237. return false;
  238. }
  239. b->index = 0;
  240. b->generation_id += 1;
  241. condition_broadcast(&b->cond);
  242. return true;
  243. }
  244. u32 thread_current_id(void) {
  245. u32 thread_id;
  246. #if defined(GB_SYSTEM_WINDOWS)
  247. #if defined(GB_ARCH_32_BIT) && defined(GB_CPU_X86)
  248. thread_id = (cast(u32 *)__readfsdword(24))[9];
  249. #elif defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86)
  250. thread_id = (cast(u32 *)__readgsqword(48))[18];
  251. #else
  252. thread_id = GetCurrentThreadId();
  253. #endif
  254. #elif defined(GB_SYSTEM_OSX) && defined(GB_ARCH_64_BIT)
  255. thread_id = pthread_mach_thread_np(pthread_self());
  256. #elif defined(GB_ARCH_32_BIT) && defined(GB_CPU_X86)
  257. __asm__("mov %%gs:0x08,%0" : "=r"(thread_id));
  258. #elif defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86)
  259. __asm__("mov %%fs:0x10,%0" : "=r"(thread_id));
  260. #elif defined(GB_SYSTEM_LINUX)
  261. thread_id = gettid();
  262. #else
  263. #error Unsupported architecture for thread_current_id()
  264. #endif
  265. return thread_id;
  266. }
  267. gb_inline void yield_thread(void) {
  268. #if defined(GB_SYSTEM_WINDOWS)
  269. _mm_pause();
  270. #elif defined(GB_SYSTEM_OSX)
  271. #if defined(GB_CPU_X86)
  272. __asm__ volatile ("" : : : "memory");
  273. #elif defined(GB_CPU_ARM)
  274. __asm__ volatile ("yield" : : : "memory");
  275. #endif
  276. #elif defined(GB_CPU_X86)
  277. _mm_pause();
  278. #elif defined(GB_CPU_ARM)
  279. __asm__ volatile ("yield" : : : "memory");
  280. #else
  281. #error Unknown architecture
  282. #endif
  283. }
  284. gb_inline void yield(void) {
  285. #if defined(GB_SYSTEM_WINDOWS)
  286. YieldProcessor();
  287. #else
  288. sched_yield();
  289. #endif
  290. }
  291. void thread_init(Thread *t) {
  292. gb_zero_item(t);
  293. #if defined(GB_SYSTEM_WINDOWS)
  294. t->win32_handle = INVALID_HANDLE_VALUE;
  295. #else
  296. t->posix_handle = 0;
  297. #endif
  298. t->semaphore = gb_alloc_item(heap_allocator(), Semaphore);
  299. semaphore_init(t->semaphore);
  300. }
  301. void thread_destroy(Thread *t) {
  302. thread_join(t);
  303. semaphore_destroy(t->semaphore);
  304. gb_free(heap_allocator(), t->semaphore);
  305. }
  306. void gb__thread_run(Thread *t) {
  307. semaphore_release(t->semaphore);
  308. t->return_value = t->proc(t);
  309. }
  310. #if defined(GB_SYSTEM_WINDOWS)
  311. DWORD __stdcall internal_thread_proc(void *arg) {
  312. Thread *t = cast(Thread *)arg;
  313. t->is_running.store(true);
  314. gb__thread_run(t);
  315. return 0;
  316. }
  317. #else
  318. void *internal_thread_proc(void *arg) {
  319. #if (GB_SYSTEM_LINUX)
  320. // NOTE: Don't permit any signal delivery to threads on Linux.
  321. sigset_t mask = {};
  322. sigfillset(&mask);
  323. GB_ASSERT_MSG(pthread_sigmask(SIG_BLOCK, &mask, nullptr) == 0, "failed to block signals");
  324. #endif
  325. Thread *t = cast(Thread *)arg;
  326. t->is_running.store(true);
  327. gb__thread_run(t);
  328. return NULL;
  329. }
  330. #endif
  331. void thread_start(Thread *t, ThreadProc *proc, void *user_data) { thread_start_with_stack(t, proc, user_data, 0); }
  332. void thread_start_with_stack(Thread *t, ThreadProc *proc, void *user_data, isize stack_size) {
  333. GB_ASSERT(!t->is_running.load());
  334. GB_ASSERT(proc != NULL);
  335. t->proc = proc;
  336. t->user_data = user_data;
  337. t->stack_size = stack_size;
  338. #if defined(GB_SYSTEM_WINDOWS)
  339. t->win32_handle = CreateThread(NULL, stack_size, internal_thread_proc, t, 0, NULL);
  340. GB_ASSERT_MSG(t->win32_handle != NULL, "CreateThread: GetLastError");
  341. #else
  342. {
  343. pthread_attr_t attr;
  344. pthread_attr_init(&attr);
  345. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  346. if (stack_size != 0) {
  347. pthread_attr_setstacksize(&attr, stack_size);
  348. }
  349. pthread_create(&t->posix_handle, &attr, internal_thread_proc, t);
  350. pthread_attr_destroy(&attr);
  351. }
  352. #endif
  353. semaphore_wait(t->semaphore);
  354. }
  355. void thread_join(Thread *t) {
  356. if (!t->is_running.load()) {
  357. return;
  358. }
  359. #if defined(GB_SYSTEM_WINDOWS)
  360. WaitForSingleObject(t->win32_handle, INFINITE);
  361. CloseHandle(t->win32_handle);
  362. t->win32_handle = INVALID_HANDLE_VALUE;
  363. #else
  364. pthread_join(t->posix_handle, NULL);
  365. t->posix_handle = 0;
  366. #endif
  367. t->is_running.store(false);
  368. }
  369. bool thread_is_running(Thread const *t) { return t->is_running.load(); }
  370. void thread_set_name(Thread *t, char const *name) {
  371. #if defined(GB_COMPILER_MSVC)
  372. #pragma pack(push, 8)
  373. typedef struct {
  374. DWORD type;
  375. char const *name;
  376. DWORD id;
  377. DWORD flags;
  378. } gbprivThreadName;
  379. #pragma pack(pop)
  380. gbprivThreadName tn;
  381. tn.type = 0x1000;
  382. tn.name = name;
  383. tn.id = GetThreadId(cast(HANDLE)t->win32_handle);
  384. tn.flags = 0;
  385. __try {
  386. RaiseException(0x406d1388, 0, gb_size_of(tn)/4, cast(ULONG_PTR *)&tn);
  387. } __except(1 /*EXCEPTION_EXECUTE_HANDLER*/) {
  388. }
  389. #elif defined(GB_SYSTEM_WINDOWS) && !defined(GB_COMPILER_MSVC)
  390. // IMPORTANT TODO(bill): Set thread name for GCC/Clang on windows
  391. return;
  392. #elif defined(GB_SYSTEM_OSX)
  393. // TODO(bill): Test if this works
  394. pthread_setname_np(name);
  395. #elif defined(GB_SYSTEM_FREEBSD)
  396. pthread_set_name_np(t->posix_handle, name);
  397. #else
  398. // TODO(bill): Test if this works
  399. pthread_setname_np(t->posix_handle, name);
  400. #endif
  401. }