- /**
- * @file kc_thread.c
- * @brief スレッドモジュール
- * @copyright 2020 - 2024 Nomura Kei
- */
- #include <string.h>
- #include <errno.h>
- #include <stdatomic.h>
-
- #include <kc.h>
- #include <kc_memory.h>
- #include <kc_threads.h>
-
- /**
- * KcThread 管理情報
- */
- typedef struct
- {
- thrd_t tid;
- void *args;
- int (*run)(void *args);
- atomic_bool alive_state;
- } KcThreadInfo;
-
- // =============================================================================
- // プロトタイプ宣言
- // =============================================================================
- static bool KcThread_is_alive(KcThread *thread);
- static bool KcThread_start(KcThread *thread, void *args);
- static bool KcThread_join(KcThread *thread);
- static int KcThread_run(void *thread);
-
- // =============================================================================
- // new
- // =============================================================================
- /**
- * スレッドを生成します。
- *
- * @param run スレッドにて実行する関数へのポインタ
- */
- KcThread *KcThread_new(int (*run)(void *args))
- {
- // KcThread の管理構造
- // +--------------+
- // | KcThread |
- // | ... |
- // | _info -----------+
- // +--------------+ |
- // | <_info> | <---+
- // +--------------+
- KcThread *thread = (KcThread *)malloc(sizeof(KcThread) + sizeof(KcThreadInfo));
- if (thread != NULL)
- {
- thread->is_alive = KcThread_is_alive;
- thread->start = KcThread_start;
- thread->join = KcThread_join;
- thread->_info = (thread + 1);
- KcThreadInfo *info = (KcThreadInfo *)thread->_info;
- // info->tid
- info->run = run;
- atomic_init(&info->alive_state, false);
- }
- return thread;
- }
-
- // =============================================================================
- // delete
- // =============================================================================
- /**
- * Thread を破棄します。
- *
- * @param thread 破棄するスレッド
- */
- void KcThread_delete(KcThread *thread)
- {
- free(thread);
- }
-
- // =============================================================================
- // sleep
- // =============================================================================
- /**
- * 指定された ms 間現在のスレッドをスリープさせます。
- *
- * @param time スリープさせるミリ秒数
- * @param force true の場合、シグナルにより割り込まれた場合でも継続してスリープします。
- * @return true/false (成功/中断された)
- */
- bool KcThread_msleep(long time, bool force)
- {
- long sec = time / 1000;
- long msec = time - (sec * 1000);
- long nsec = msec * 1000 * 1000;
- return KcThread_sleep(sec, nsec, force);
- }
-
- /**
- * 指定された sec 秒 + nsec ナノ秒間現在のスレッドをスリープさせます。
- *
- * @param sec スリープさせる秒数
- * @param nsec スリープさせるナノ秒数
- * @param force true の場合、シグナルにより割り込まれた場合でも継続してスリープします。
- * @return true/false (成功/中断された)
- */
- bool KcThread_sleep(long sec, long nsec, bool force)
- {
- struct timespec remaining = {sec, nsec};
- int ret;
- do
- {
- errno = 0;
- ret = thrd_sleep(&remaining, &remaining);
- } while ((ret == -1) && force && (errno == EINTR));
- return (ret == 0);
- }
-
- // =============================================================================
- // is_alive
- // =============================================================================
- /**
- * 指定されたスレッドが生きているか否かを返します。
- *
- * @param thread 対象スレッド
- * @return true/false (スレッドが生存している/していない)
- */
- static bool KcThread_is_alive(KcThread *thread)
- {
- KcThreadInfo *info = (KcThreadInfo *)thread->_info;
- return atomic_load(&info->alive_state);
- }
-
- // =============================================================================
- // start
- // =============================================================================
- /**
- * スレッドを開始します。
- *
- * @param thread 対象スレッド
- * @param args スレッドに渡す情報
- * @return true/false (スレッド起動成功/失敗)
- */
- static bool KcThread_start(KcThread *thread, void *args)
- {
- int ret = thrd_error;
- KcThreadInfo *info = (KcThreadInfo *)thread->_info;
- if (!atomic_load(&info->alive_state))
- {
- info->args = args;
- ret = thrd_create(&info->tid, KcThread_run, thread);
- }
- return (ret == thrd_success);
- }
-
- // =============================================================================
- // join
- // =============================================================================
- /**
- * スレッドが終了するのを待機します。
- *
- * @param thread 対象スレッド
- * @return true/false (成功/失敗)
- */
- static bool KcThread_join(KcThread *thread)
- {
- int ret = thrd_error;
- KcThreadInfo *info = (KcThreadInfo *)thread->_info;
- ret = thrd_join(info->tid, NULL);
- return (ret == thrd_success);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // 内部関数
- //
-
- // =============================================================================
- // run
- // =============================================================================
- /**
- * スレッドで実行される関数。
- * start にて関数を別スレッドにて実行します。
- *
- * @param args スレッド情報
- * @return
- */
- int KcThread_run(void *args)
- {
- KcThread *thread = (KcThread *)args;
- KcThreadInfo *info = (KcThreadInfo *)thread->_info;
- atomic_store(&info->alive_state, true);
- int ret = info->run(info->args);
- atomic_store(&info->alive_state, false);
- return ret;
- }