/**
* @file kc_thread.c
* @brief スレッドモジュール
* @copyright 2020 - 2024 Nomura Kei
*/
#include <stdio.h>
#include <kc_threads.h>
#include <kc_threads_win.h>
#if (KC_IS_WINDOWS)
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
{
if ((thr == NULL) || (func == NULL))
{
return thrd_error;
}
thr->handle = CreateThread(
NULL, // セキュリティ属性
0, // スタックサイズ
(LPTHREAD_START_ROUTINE)func, // スレッド関数
arg, // 引数
0, // 作成フラグ
&(thr->thread_id) // スレッドID
);
if (thr->handle == NULL)
{
return thrd_error;
}
return thrd_success;
}
int thrd_join(thrd_t thr, int *res)
{
if (WaitForSingleObject(thr.handle, INFINITE) != WAIT_OBJECT_0)
{
return thrd_error;
}
if (res != NULL)
{
DWORD retcode;
if (GetExitCodeThread(thr.handle, &retcode) == 0)
{
return thrd_error;
}
*res = (int)retcode;
}
CloseHandle(thr.handle);
return thrd_success;
}
int thrd_detach(thrd_t thr)
{
if (thr.handle == NULL)
{
return thrd_error;
}
if (CloseHandle(thr.handle) == 0)
{
return thrd_error;
}
return thrd_success;
}
thrd_t thrd_current(void)
{
thrd_t current;
current.handle = GetCurrentThread();
current.thread_id = GetThreadId(current.handle);
return current;
}
int thrd_equal(thrd_t lhs, thrd_t rhs)
{
return (lhs.thread_id == rhs.thread_id);
}
void thrd_yield(void)
{
SwitchToThread();
}
int thrd_sleep(const struct timespec *duration, struct timespec *remaining)
{
if (duration == NULL)
{
return thrd_error;
}
// Windows の Sleep は、ms 単位
DWORD msec = (DWORD)(duration->tv_sec * 1000 + duration->tv_nsec / 1000000);
Sleep(msec);
// 常に成功したものとして、remaining は 0 に設定する。
if (remaining != NULL)
{
remaining->tv_sec = 0;
remaining->tv_nsec = 0;
}
return thrd_success;
}
/**
* 指定されたミューテックスを初期化します。
* Windows の場合、常に mtx_recursive が有効となります。
*
* @param mtx 初期化するミューテックスの識別子
* @param type タイプ (mtx_plain, mtx_timed, mtx_plain|mtx_recursive, mtx_timed|mtx_recursive)
* @return thrd_success/thrd_error (成功/失敗)
*/
int mtx_init(mtx_t *mtx, int type)
{
if (mtx == NULL)
{
return thrd_error;
}
mtx->type = type;
InitializeCriticalSection(&mtx->cs);
return thrd_success;
}
/**
* ミューテックスを破棄します。
*
* @param mtx 破棄するミューテックス識別子
*/
void mtx_destroy(mtx_t *mtx)
{
printf("mtx_destroy: mtx->cs:%p\n", &mtx->cs);
DeleteCriticalSection(&mtx->cs);
}
/**
* 指定されたミューテックスがロックされるまで現在のスレッドをロックします。
*
* @param mtx ミューテックス識別子
* @return thrd_success/thrd_error (成功/失敗)
*/
int mtx_lock(mtx_t *mtx)
{
EnterCriticalSection(&mtx->cs);
return thrd_success;
}
/**
*
*/
int mtx_unlock(mtx_t *mtx)
{
LeaveCriticalSection(&mtx->cs);
return thrd_success;
}
int cnd_init(cnd_t *cond)
{
if (cond == NULL)
{
return thrd_error;
}
InitializeConditionVariable(&cond->cond);
return thrd_success;
}
int cnd_signal(cnd_t *cond)
{
if (cond == NULL)
{
return thrd_error;
}
WakeConditionVariable(&cond->cond);
return thrd_success;
}
int cnd_broadcast(cnd_t *cond)
{
if (cond == NULL)
{
return thrd_error;
}
WakeAllConditionVariable(&cond->cond);
return thrd_success;
}
int cnd_wait(cnd_t *cond, mtx_t *mtx)
{
if ((cond == NULL) || (mtx == NULL))
{
return thrd_error;
}
if (SleepConditionVariableCS(&cond->cond, &mtx->cs, INFINITE))
{
return thrd_success;
}
return thrd_error;
}
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
{
if ((cond == NULL) || (mtx == NULL) || (ts == NULL))
{
return thrd_error;
}
DWORD msec = (DWORD)(ts->tv_sec * 1000 + ts->tv_nsec / 1000000);
if (SleepConditionVariableCS(&cond->cond, &mtx->cs, msec))
{
return thrd_timedout;
}
return thrd_error;
}
void cnd_destroy(cnd_t *cond)
{
// Nothing to do
UNUSED_VARIABLE(cond);
}
#endif