Newer
Older
libkc / modules / src / kc_threads.c
Nomura Kei on 29 May 2024 5 KB update
  1. /**
  2. * @file kc_thread.c
  3. * @brief スレッドモジュール
  4. * @copyright 2020 - 2024 Nomura Kei
  5. */
  6. #include <string.h>
  7. #include <errno.h>
  8. #include <stdatomic.h>
  9.  
  10. #include <kc.h>
  11. #include <kc_memory.h>
  12. #include <kc_threads.h>
  13.  
  14. /**
  15. * KcThread 管理情報
  16. */
  17. typedef struct
  18. {
  19. thrd_t tid;
  20. void *args;
  21. int (*run)(void *args);
  22. atomic_bool alive_state;
  23. } KcThreadInfo;
  24.  
  25. // =============================================================================
  26. // プロトタイプ宣言
  27. // =============================================================================
  28. static bool KcThread_is_alive(KcThread *thread);
  29. static bool KcThread_start(KcThread *thread, void *args);
  30. static bool KcThread_join(KcThread *thread);
  31. static int KcThread_run(void *thread);
  32.  
  33. // =============================================================================
  34. // new
  35. // =============================================================================
  36. /**
  37. * スレッドを生成します。
  38. *
  39. * @param run スレッドにて実行する関数へのポインタ
  40. */
  41. KcThread *KcThread_new(int (*run)(void *args))
  42. {
  43. // KcThread の管理構造
  44. // +--------------+
  45. // | KcThread |
  46. // | ... |
  47. // | _info -----------+
  48. // +--------------+ |
  49. // | <_info> | <---+
  50. // +--------------+
  51. KcThread *thread = (KcThread *)malloc(sizeof(KcThread) + sizeof(KcThreadInfo));
  52. if (thread != NULL)
  53. {
  54. thread->is_alive = KcThread_is_alive;
  55. thread->start = KcThread_start;
  56. thread->join = KcThread_join;
  57. thread->_info = (thread + 1);
  58. KcThreadInfo *info = (KcThreadInfo *)thread->_info;
  59. // info->tid
  60. info->run = run;
  61. atomic_init(&info->alive_state, false);
  62. }
  63. return thread;
  64. }
  65.  
  66. // =============================================================================
  67. // delete
  68. // =============================================================================
  69. /**
  70. * Thread を破棄します。
  71. *
  72. * @param thread 破棄するスレッド
  73. */
  74. void KcThread_delete(KcThread *thread)
  75. {
  76. free(thread);
  77. }
  78.  
  79. // =============================================================================
  80. // sleep
  81. // =============================================================================
  82. /**
  83. * 指定された ms 間現在のスレッドをスリープさせます。
  84. *
  85. * @param time スリープさせるミリ秒数
  86. * @param force true の場合、シグナルにより割り込まれた場合でも継続してスリープします。
  87. * @return true/false (成功/中断された)
  88. */
  89. bool KcThread_msleep(long time, bool force)
  90. {
  91. long sec = time / 1000;
  92. long msec = time - (sec * 1000);
  93. long nsec = msec * 1000 * 1000;
  94. return KcThread_sleep(sec, nsec, force);
  95. }
  96.  
  97. /**
  98. * 指定された sec 秒 + nsec ナノ秒間現在のスレッドをスリープさせます。
  99. *
  100. * @param sec スリープさせる秒数
  101. * @param nsec スリープさせるナノ秒数
  102. * @param force true の場合、シグナルにより割り込まれた場合でも継続してスリープします。
  103. * @return true/false (成功/中断された)
  104. */
  105. bool KcThread_sleep(long sec, long nsec, bool force)
  106. {
  107. struct timespec remaining = {sec, nsec};
  108. int ret;
  109. do
  110. {
  111. errno = 0;
  112. ret = thrd_sleep(&remaining, &remaining);
  113. } while ((ret == -1) && force && (errno == EINTR));
  114. return (ret == 0);
  115. }
  116.  
  117. // =============================================================================
  118. // is_alive
  119. // =============================================================================
  120. /**
  121. * 指定されたスレッドが生きているか否かを返します。
  122. *
  123. * @param thread 対象スレッド
  124. * @return true/false (スレッドが生存している/していない)
  125. */
  126. static bool KcThread_is_alive(KcThread *thread)
  127. {
  128. KcThreadInfo *info = (KcThreadInfo *)thread->_info;
  129. return atomic_load(&info->alive_state);
  130. }
  131.  
  132. // =============================================================================
  133. // start
  134. // =============================================================================
  135. /**
  136. * スレッドを開始します。
  137. *
  138. * @param thread 対象スレッド
  139. * @param args スレッドに渡す情報
  140. * @return true/false (スレッド起動成功/失敗)
  141. */
  142. static bool KcThread_start(KcThread *thread, void *args)
  143. {
  144. int ret = thrd_error;
  145. KcThreadInfo *info = (KcThreadInfo *)thread->_info;
  146. if (!atomic_load(&info->alive_state))
  147. {
  148. info->args = args;
  149. ret = thrd_create(&info->tid, KcThread_run, thread);
  150. }
  151. return (ret == thrd_success);
  152. }
  153.  
  154. // =============================================================================
  155. // join
  156. // =============================================================================
  157. /**
  158. * スレッドが終了するのを待機します。
  159. *
  160. * @param thread 対象スレッド
  161. * @return true/false (成功/失敗)
  162. */
  163. static bool KcThread_join(KcThread *thread)
  164. {
  165. int ret = thrd_error;
  166. KcThreadInfo *info = (KcThreadInfo *)thread->_info;
  167. ret = thrd_join(info->tid, NULL);
  168. return (ret == thrd_success);
  169. }
  170.  
  171. ////////////////////////////////////////////////////////////////////////////////
  172. //
  173. // 内部関数
  174. //
  175.  
  176. // =============================================================================
  177. // run
  178. // =============================================================================
  179. /**
  180. * スレッドで実行される関数。
  181. * start にて関数を別スレッドにて実行します。
  182. *
  183. * @param args スレッド情報
  184. * @return
  185. */
  186. int KcThread_run(void *args)
  187. {
  188. KcThread *thread = (KcThread *)args;
  189. KcThreadInfo *info = (KcThreadInfo *)thread->_info;
  190. atomic_store(&info->alive_state, true);
  191. int ret = info->run(info->args);
  192. atomic_store(&info->alive_state, false);
  193. return ret;
  194. }