thread.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. #include "precompile.h"
  2. #include "toolkit.h"
  3. #include "internal.h"
  4. TOOLKIT_API int toolkit_key_create(toolkit_key_t* key)
  5. {
  6. key->tls_index = TlsAlloc();
  7. if (key->tls_index == TLS_OUT_OF_INDEXES)
  8. return TOOLKIT_ENOMEM;
  9. return 0;
  10. }
  11. TOOLKIT_API void toolkit_key_delete(toolkit_key_t* key)
  12. {
  13. if (TlsFree(key->tls_index) == FALSE)
  14. abort();
  15. key->tls_index = TLS_OUT_OF_INDEXES;
  16. }
  17. TOOLKIT_API void* toolkit_key_get(toolkit_key_t* key)
  18. {
  19. void* value;
  20. value = TlsGetValue(key->tls_index);
  21. if (value == NULL)
  22. if (GetLastError() != ERROR_SUCCESS)
  23. abort();
  24. return value;
  25. }
  26. TOOLKIT_API void toolkit_key_set(toolkit_key_t* key, void* value)
  27. {
  28. if (TlsSetValue(key->tls_index, value) == FALSE)
  29. abort();
  30. }
  31. static toolkit_key_t toolkit__current_thread_key;
  32. static toolkit_once_t toolkit__current_thread_init_guard = TOOLKIT_ONCE_INIT;
  33. static void toolkit__init_current_thread_key(void)
  34. {
  35. if (toolkit_key_create(&toolkit__current_thread_key))
  36. abort();
  37. }
  38. struct thread_ctx {
  39. void (*entry)(void* arg);
  40. void* arg;
  41. toolkit_thread_t self;
  42. };
  43. static UINT __stdcall toolkit__thread_start(void* arg)
  44. {
  45. struct thread_ctx* ctx_p;
  46. struct thread_ctx ctx;
  47. ctx_p = arg;
  48. ctx = *ctx_p;
  49. FREE(ctx_p);
  50. toolkit_once(&toolkit__current_thread_init_guard, toolkit__init_current_thread_key);
  51. toolkit_key_set(&toolkit__current_thread_key, (void*)ctx.self);
  52. ctx.entry(ctx.arg);
  53. return 0;
  54. }
  55. TOOLKIT_API int toolkit_thread_create_ex(toolkit_thread_t* tid, const toolkit_thread_option_t* params,
  56. toolkit_thread_cb entry, void* arg)
  57. {
  58. struct thread_ctx* ctx;
  59. int err;
  60. HANDLE thread;
  61. SYSTEM_INFO sysinfo;
  62. size_t stack_size;
  63. size_t pagesize;
  64. stack_size = params->flags & 1 ? params->stack_size : 0;
  65. if (stack_size != 0) {
  66. GetNativeSystemInfo(&sysinfo);
  67. pagesize = (size_t)sysinfo.dwPageSize;
  68. /* Round up to the nearest page boundary. */
  69. stack_size = (stack_size + pagesize - 1) & ~(pagesize - 1);
  70. if ((unsigned)stack_size != stack_size)
  71. return TOOLKIT_EINVAL;
  72. }
  73. ctx = MALLOC_T(struct thread_ctx);
  74. if (ctx == NULL)
  75. return TOOLKIT_ENOMEM;
  76. ctx->entry = entry;
  77. ctx->arg = arg;
  78. /* Create the thread in suspended state so we have a chance to pass
  79. * its own creation handle to it */
  80. thread = (HANDLE)_beginthreadex(NULL,
  81. (unsigned)stack_size,
  82. toolkit__thread_start,
  83. ctx,
  84. CREATE_SUSPENDED,
  85. NULL);
  86. if (thread == NULL) {
  87. err = errno;
  88. FREE(ctx);
  89. }
  90. else {
  91. err = 0;
  92. *tid = thread;
  93. ctx->self = thread;
  94. ResumeThread(thread);
  95. }
  96. switch (err) {
  97. case 0:
  98. return 0;
  99. case EACCES:
  100. return TOOLKIT_EACCES;
  101. case EAGAIN:
  102. return TOOLKIT_EAGAIN;
  103. case EINVAL:
  104. return TOOLKIT_EINVAL;
  105. }
  106. return TOOLKIT_EIO;
  107. }
  108. TOOLKIT_API int toolkit_thread_create(toolkit_thread_t* tid, toolkit_thread_cb entry, void* arg)
  109. {
  110. toolkit_thread_option_t params;
  111. params.flags = 0;
  112. return toolkit_thread_create_ex(tid, &params, entry, arg);
  113. }
  114. TOOLKIT_API int toolkit_thread_join(toolkit_thread_t* tid)
  115. {
  116. if (WaitForSingleObject(*tid, INFINITE))
  117. return -1;
  118. else {
  119. CloseHandle(*tid);
  120. *tid = 0;
  121. MemoryBarrier(); /* For feature parity with pthread_join(). */
  122. return 0;
  123. }
  124. }
  125. TOOLKIT_API int toolkit_thread_equal(const toolkit_thread_t* t1, const toolkit_thread_t* t2)
  126. {
  127. return *t1 == *t2;
  128. }
  129. TOOLKIT_API toolkit_thread_t toolkit_thread_self(void)
  130. {
  131. toolkit_once(&toolkit__current_thread_init_guard, toolkit__init_current_thread_key);
  132. return (toolkit_thread_t)toolkit_key_get(&toolkit__current_thread_key);
  133. }
  134. int toolkit_rwlock_init(toolkit_rwlock_t* rwlock) {
  135. /* Initialize the semaphore that acts as the write lock. */
  136. HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
  137. if (handle == NULL)
  138. return toolkit_translate_sys_error(GetLastError());
  139. rwlock->state_.write_semaphore_ = handle;
  140. /* Initialize the critical section protecting the reader count. */
  141. InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
  142. /* Initialize the reader count. */
  143. rwlock->state_.num_readers_ = 0;
  144. return 0;
  145. }
  146. void toolkit_rwlock_destroy(toolkit_rwlock_t* rwlock) {
  147. DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
  148. CloseHandle(rwlock->state_.write_semaphore_);
  149. }
  150. void toolkit_rwlock_rdlock(toolkit_rwlock_t* rwlock) {
  151. /* Acquire the lock that protects the reader count. */
  152. EnterCriticalSection(&rwlock->state_.num_readers_lock_);
  153. /* Increase the reader count, and lock for write if this is the first
  154. * reader.
  155. */
  156. if (++rwlock->state_.num_readers_ == 1) {
  157. DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
  158. if (r != WAIT_OBJECT_0)
  159. toolkit_fatal_error(GetLastError(), "WaitForSingleObject");
  160. }
  161. /* Release the lock that protects the reader count. */
  162. LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
  163. }
  164. int toolkit_rwlock_tryrdlock(toolkit_rwlock_t* rwlock) {
  165. int err;
  166. if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
  167. return TOOLKIT_EBUSY;
  168. err = 0;
  169. if (rwlock->state_.num_readers_ == 0) {
  170. /* Currently there are no other readers, which means that the write lock
  171. * needs to be acquired.
  172. */
  173. DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
  174. if (r == WAIT_OBJECT_0)
  175. rwlock->state_.num_readers_++;
  176. else if (r == WAIT_TIMEOUT)
  177. err = TOOLKIT_EBUSY;
  178. else if (r == WAIT_FAILED)
  179. toolkit_fatal_error(GetLastError(), "WaitForSingleObject");
  180. }
  181. else {
  182. /* The write lock has already been acquired because there are other
  183. * active readers.
  184. */
  185. rwlock->state_.num_readers_++;
  186. }
  187. LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
  188. return err;
  189. }
  190. void toolkit_rwlock_rdunlock(toolkit_rwlock_t* rwlock) {
  191. EnterCriticalSection(&rwlock->state_.num_readers_lock_);
  192. if (--rwlock->state_.num_readers_ == 0) {
  193. if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
  194. toolkit_fatal_error(GetLastError(), "ReleaseSemaphore");
  195. }
  196. LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
  197. }
  198. void toolkit_rwlock_wrlock(toolkit_rwlock_t* rwlock) {
  199. DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
  200. if (r != WAIT_OBJECT_0)
  201. toolkit_fatal_error(GetLastError(), "WaitForSingleObject");
  202. }
  203. int toolkit_rwlock_trywrlock(toolkit_rwlock_t* rwlock)
  204. {
  205. DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
  206. if (r == WAIT_OBJECT_0)
  207. return 0;
  208. else if (r == WAIT_TIMEOUT)
  209. return TOOLKIT_EBUSY;
  210. else {
  211. toolkit_fatal_error(GetLastError(), "WaitForSingleObject");
  212. return TOOLKIT_UNKNOWN;
  213. }
  214. }
  215. void toolkit_rwlock_wrunlock(toolkit_rwlock_t* rwlock)
  216. {
  217. if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
  218. toolkit_fatal_error(GetLastError(), "ReleaseSemaphore");
  219. }
  220. int toolkit_sem_init(toolkit_sem_t* sem, unsigned int value) {
  221. *sem = CreateSemaphore(NULL, value, INT_MAX, NULL);
  222. if (*sem == NULL)
  223. return toolkit_translate_sys_error(GetLastError());
  224. else
  225. return 0;
  226. }
  227. void toolkit_sem_destroy(toolkit_sem_t* sem)
  228. {
  229. if (!CloseHandle(*sem))
  230. abort();
  231. }
  232. void toolkit_sem_post(toolkit_sem_t* sem)
  233. {
  234. if (!ReleaseSemaphore(*sem, 1, NULL))
  235. abort();
  236. }
  237. void toolkit_sem_wait(toolkit_sem_t* sem)
  238. {
  239. if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0)
  240. abort();
  241. }
  242. int toolkit_sem_trywait(toolkit_sem_t* sem)
  243. {
  244. DWORD r = WaitForSingleObject(*sem, 0);
  245. if (r == WAIT_OBJECT_0)
  246. return 0;
  247. if (r == WAIT_TIMEOUT)
  248. return TOOLKIT_EAGAIN;
  249. abort();
  250. return -1; /* Satisfy the compiler. */
  251. }
  252. int toolkit_cond_init(toolkit_cond_t* cond)
  253. {
  254. InitializeConditionVariable(&cond->cond_var);
  255. return 0;
  256. }
  257. void toolkit_cond_destroy(toolkit_cond_t* cond)
  258. {
  259. /* nothing to do */
  260. (void)&cond;
  261. }
  262. void toolkit_cond_signal(toolkit_cond_t* cond)
  263. {
  264. WakeConditionVariable(&cond->cond_var);
  265. }
  266. void toolkit_cond_broadcast(toolkit_cond_t* cond)
  267. {
  268. WakeAllConditionVariable(&cond->cond_var);
  269. }
  270. void toolkit_cond_wait(toolkit_cond_t* cond, toolkit_mutex_t* mutex)
  271. {
  272. if (!SleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
  273. abort();
  274. }
  275. int toolkit_cond_timedwait(toolkit_cond_t* cond, toolkit_mutex_t* mutex, uint64_t timeout)
  276. {
  277. if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
  278. return 0;
  279. if (GetLastError() != ERROR_TIMEOUT)
  280. abort();
  281. return TOOLKIT_ETIMEDOUT;
  282. }
  283. int toolkit_barrier_init(toolkit_barrier_t* barrier, unsigned int count)
  284. {
  285. int err;
  286. barrier->n = count;
  287. barrier->count = 0;
  288. err = toolkit_mutex_init(&barrier->mutex);
  289. if (err)
  290. return err;
  291. err = toolkit_sem_init(&barrier->turnstile1, 0);
  292. if (err)
  293. goto error2;
  294. err = toolkit_sem_init(&barrier->turnstile2, 1);
  295. if (err)
  296. goto error;
  297. return 0;
  298. error:
  299. toolkit_sem_destroy(&barrier->turnstile1);
  300. error2:
  301. toolkit_mutex_destroy(&barrier->mutex);
  302. return err;
  303. }
  304. void toolkit_barrier_destroy(toolkit_barrier_t* barrier)
  305. {
  306. toolkit_sem_destroy(&barrier->turnstile2);
  307. toolkit_sem_destroy(&barrier->turnstile1);
  308. toolkit_mutex_destroy(&barrier->mutex);
  309. }
  310. int toolkit_barrier_wait(toolkit_barrier_t* barrier)
  311. {
  312. int serial_thread;
  313. toolkit_mutex_lock(&barrier->mutex);
  314. if (++barrier->count == barrier->n) {
  315. toolkit_sem_wait(&barrier->turnstile2);
  316. toolkit_sem_post(&barrier->turnstile1);
  317. }
  318. toolkit_mutex_unlock(&barrier->mutex);
  319. toolkit_sem_wait(&barrier->turnstile1);
  320. toolkit_sem_post(&barrier->turnstile1);
  321. toolkit_mutex_lock(&barrier->mutex);
  322. serial_thread = (--barrier->count == 0);
  323. if (serial_thread) {
  324. toolkit_sem_wait(&barrier->turnstile1);
  325. toolkit_sem_post(&barrier->turnstile2);
  326. }
  327. toolkit_mutex_unlock(&barrier->mutex);
  328. toolkit_sem_wait(&barrier->turnstile2);
  329. toolkit_sem_post(&barrier->turnstile2);
  330. return serial_thread;
  331. }