Newer
Older
libkc / modules / src / kc_threads_win.c
  1. /**
  2. * @file kc_thread.c
  3. * @brief スレッドモジュール
  4. * @copyright 2020 - 2024 Nomura Kei
  5. */
  6. #include <stdio.h>
  7.  
  8. #include <kc_threads.h>
  9. #include <kc_threads_win.h>
  10.  
  11. #if (KC_IS_WINDOWS)
  12.  
  13. int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
  14. {
  15. if ((thr == NULL) || (func == NULL))
  16. {
  17. return thrd_error;
  18. }
  19.  
  20. thr->handle = CreateThread(
  21. NULL, // セキュリティ属性
  22. 0, // スタックサイズ
  23. (LPTHREAD_START_ROUTINE)func, // スレッド関数
  24. arg, // 引数
  25. 0, // 作成フラグ
  26. &(thr->thread_id) // スレッドID
  27. );
  28.  
  29. if (thr->handle == NULL)
  30. {
  31. return thrd_error;
  32. }
  33. return thrd_success;
  34. }
  35. int thrd_join(thrd_t thr, int *res)
  36. {
  37. if (WaitForSingleObject(thr.handle, INFINITE) != WAIT_OBJECT_0)
  38. {
  39. return thrd_error;
  40. }
  41. if (res != NULL)
  42. {
  43. DWORD retcode;
  44. if (GetExitCodeThread(thr.handle, &retcode) == 0)
  45. {
  46. return thrd_error;
  47. }
  48. *res = (int)retcode;
  49. }
  50. CloseHandle(thr.handle);
  51. return thrd_success;
  52. }
  53.  
  54. int thrd_detach(thrd_t thr)
  55. {
  56. if (thr.handle == NULL)
  57. {
  58. return thrd_error;
  59. }
  60. if (CloseHandle(thr.handle) == 0)
  61. {
  62. return thrd_error;
  63. }
  64. return thrd_success;
  65. }
  66.  
  67. thrd_t thrd_current(void)
  68. {
  69. thrd_t current;
  70. current.handle = GetCurrentThread();
  71. current.thread_id = GetThreadId(current.handle);
  72. return current;
  73. }
  74.  
  75. int thrd_equal(thrd_t lhs, thrd_t rhs)
  76. {
  77. return (lhs.thread_id == rhs.thread_id);
  78. }
  79.  
  80. void thrd_yield(void)
  81. {
  82. SwitchToThread();
  83. }
  84.  
  85. int thrd_sleep(const struct timespec *duration, struct timespec *remaining)
  86. {
  87. if (duration == NULL)
  88. {
  89. return thrd_error;
  90. }
  91.  
  92. // Windows の Sleep は、ms 単位
  93. DWORD msec = (DWORD)(duration->tv_sec * 1000 + duration->tv_nsec / 1000000);
  94. Sleep(msec);
  95.  
  96. // 常に成功したものとして、remaining は 0 に設定する。
  97. if (remaining != NULL)
  98. {
  99. remaining->tv_sec = 0;
  100. remaining->tv_nsec = 0;
  101. }
  102. return thrd_success;
  103. }
  104.  
  105. /**
  106. * 指定されたミューテックスを初期化します。
  107. * Windows の場合、常に mtx_recursive が有効となります。
  108. *
  109. * @param mtx 初期化するミューテックスの識別子
  110. * @param type タイプ (mtx_plain, mtx_timed, mtx_plain|mtx_recursive, mtx_timed|mtx_recursive)
  111. * @return thrd_success/thrd_error (成功/失敗)
  112. */
  113. int mtx_init(mtx_t *mtx, int type)
  114. {
  115. if (mtx == NULL)
  116. {
  117. return thrd_error;
  118. }
  119. mtx->type = type;
  120. InitializeCriticalSection(&mtx->cs);
  121. return thrd_success;
  122. }
  123.  
  124. /**
  125. * ミューテックスを破棄します。
  126. *
  127. * @param mtx 破棄するミューテックス識別子
  128. */
  129. void mtx_destroy(mtx_t *mtx)
  130. {
  131. printf("mtx_destroy: mtx->cs:%p\n", &mtx->cs);
  132. DeleteCriticalSection(&mtx->cs);
  133. }
  134.  
  135. /**
  136. * 指定されたミューテックスがロックされるまで現在のスレッドをロックします。
  137. *
  138. * @param mtx ミューテックス識別子
  139. * @return thrd_success/thrd_error (成功/失敗)
  140. */
  141. int mtx_lock(mtx_t *mtx)
  142. {
  143. EnterCriticalSection(&mtx->cs);
  144. return thrd_success;
  145. }
  146.  
  147. /**
  148. *
  149. */
  150. int mtx_unlock(mtx_t *mtx)
  151. {
  152. LeaveCriticalSection(&mtx->cs);
  153. return thrd_success;
  154. }
  155.  
  156. int cnd_init(cnd_t *cond)
  157. {
  158. if (cond == NULL)
  159. {
  160. return thrd_error;
  161. }
  162. InitializeConditionVariable(&cond->cond);
  163. return thrd_success;
  164. }
  165.  
  166. int cnd_signal(cnd_t *cond)
  167. {
  168. if (cond == NULL)
  169. {
  170. return thrd_error;
  171. }
  172. WakeConditionVariable(&cond->cond);
  173. return thrd_success;
  174. }
  175. int cnd_broadcast(cnd_t *cond)
  176. {
  177. if (cond == NULL)
  178. {
  179. return thrd_error;
  180. }
  181. WakeAllConditionVariable(&cond->cond);
  182. return thrd_success;
  183. }
  184. int cnd_wait(cnd_t *cond, mtx_t *mtx)
  185. {
  186. if ((cond == NULL) || (mtx == NULL))
  187. {
  188. return thrd_error;
  189. }
  190. if (SleepConditionVariableCS(&cond->cond, &mtx->cs, INFINITE))
  191. {
  192. return thrd_success;
  193. }
  194. return thrd_error;
  195. }
  196.  
  197. int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
  198. {
  199. if ((cond == NULL) || (mtx == NULL) || (ts == NULL))
  200. {
  201. return thrd_error;
  202. }
  203. DWORD msec = (DWORD)(ts->tv_sec * 1000 + ts->tv_nsec / 1000000);
  204. if (SleepConditionVariableCS(&cond->cond, &mtx->cs, msec))
  205. {
  206. return thrd_timedout;
  207. }
  208. return thrd_error;
  209. }
  210.  
  211. void cnd_destroy(cnd_t *cond)
  212. {
  213. // Nothing to do
  214. UNUSED_VARIABLE(cond);
  215. }
  216.  
  217. #endif