Add timed thread join
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Generated by the DN single header generator 2026-07-16 23:31:53
|
||||
// Generated by the DN single header generator 2026-07-17 17:54:43
|
||||
|
||||
// DN: Single header generator commented out => #if defined(_CLANGD)
|
||||
// #define DN_WITH_TESTS 1
|
||||
@@ -12445,8 +12445,18 @@ static void DN_OS_ThreadExecute_(void *user_context)
|
||||
// NOTE: If we're detached, it's this thread's responsibility to cleanup itself. In the platform
|
||||
// layer it should have closed any references to the thread so we should just need to cleanup the
|
||||
// TLS.
|
||||
if (thread->flags & DN_OSThreadFlags_Detached)
|
||||
if (thread->flags & DN_OSThreadFlags_Detached) {
|
||||
#if !defined(DN_PLATFORM_WIN32)
|
||||
// NOTE: Cleanup the semaphore since we're detached, all left-over resources need to be cleaned
|
||||
// up ourselves.
|
||||
DN_OS_SemaphoreDeinit(&thread->join_done_sem);
|
||||
#endif
|
||||
DN_TCDeinit(&thread->context, DN_TCDeinitArenas_Yes);
|
||||
} else {
|
||||
#if !defined(DN_PLATFORM_WIN32)
|
||||
DN_OS_SemaphoreIncrement(&thread->join_done_sem, 1); // NOTE: Signal for DN_OS_ThreadJoin waits on this.
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void DN_OS_ThreadPreInit_(DN_OSThread *thread, DN_OSThreadFunc *func, DN_OSThreadLane *lane, DN_OSThreadInitArgs init_args, void *user_context)
|
||||
@@ -12456,6 +12466,9 @@ static void DN_OS_ThreadPreInit_(DN_OSThread *thread, DN_OSThreadFunc *func, DN_
|
||||
thread->user_context = user_context;
|
||||
thread->thread_exec_wait_for_thread_id_sem = DN_OS_SemaphoreInit(0 /*initial_count*/);
|
||||
thread->caller_wait_for_thread_init_to_finish_sem = DN_OS_SemaphoreInit(0 /*initial_count*/);
|
||||
#if !defined(DN_PLATFORM_WIN32)
|
||||
thread->join_done_sem = DN_OS_SemaphoreInit(0 /*initial_count*/);
|
||||
#endif
|
||||
thread->tc_init_args = init_args.tc_args;
|
||||
thread->flags = init_args.flags;
|
||||
if (lane) {
|
||||
@@ -12481,8 +12494,12 @@ static void DN_OS_ThreadPostInit_(DN_OSThread *thread, bool result)
|
||||
DN_OS_SemaphoreDeinit(&thread->thread_exec_wait_for_thread_id_sem);
|
||||
DN_OS_SemaphoreDeinit(&thread->caller_wait_for_thread_init_to_finish_sem);
|
||||
|
||||
if (!result)
|
||||
if (!result) {
|
||||
#if !defined(DN_PLATFORM_WIN32)
|
||||
DN_OS_SemaphoreDeinit(&thread->join_done_sem);
|
||||
#endif
|
||||
*thread = {};
|
||||
}
|
||||
}
|
||||
|
||||
DN_API DN_OSThreadInitArgs DN_OS_ThreadInitArgsDefault()
|
||||
@@ -12600,10 +12617,10 @@ DN_API void DN_OS_ThreadLanewayDispatch(DN_OSThreadLaneway *laneway, DN_OSThread
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_OS_ThreadLanewayJoin(DN_OSThreadLaneway *laneway, DN_TCDeinitArenas deinit_arenas)
|
||||
DN_API void DN_OS_ThreadLanewayJoin(DN_OSThreadLaneway *laneway, DN_U32 timeout_ms, DN_TCDeinitArenas deinit_arenas)
|
||||
{
|
||||
for (DN_ForItSize(it, DN_OSThread, laneway->threads, laneway->threads_count))
|
||||
DN_OS_ThreadJoin(it.data, deinit_arenas);
|
||||
DN_OS_ThreadJoin(it.data, timeout_ms, deinit_arenas);
|
||||
DN_OS_BarrierDeinit(&laneway->barrier);
|
||||
}
|
||||
|
||||
@@ -12687,7 +12704,7 @@ DN_API void DN_OS_AsyncDeinit(DN_OSAsyncCore *async)
|
||||
DN_AtomicSetValue32(&async->join_threads, true);
|
||||
DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count);
|
||||
for (DN_ForItSize(it, DN_OSThread, async->threads, async->thread_count))
|
||||
DN_OS_ThreadJoin(it.data, DN_TCDeinitArenas_Yes);
|
||||
DN_OS_ThreadJoin(it.data, UINT32_MAX, DN_TCDeinitArenas_Yes);
|
||||
}
|
||||
|
||||
static bool DN_OS_AsyncQueueTask_(DN_OSAsyncCore *async, DN_OSAsyncTask const *task, DN_U64 wait_time_ms) {
|
||||
@@ -12729,7 +12746,7 @@ DN_API DN_OSAsyncTask DN_OS_AsyncQueueTask(DN_OSAsyncCore *async, DN_OSAsyncWork
|
||||
result.completion_sem = DN_OS_SemaphoreInit(0);
|
||||
result.queued = DN_OS_AsyncQueueTask_(async, &result, wait_time_ms);
|
||||
if (!result.queued)
|
||||
DN_OS_SemaphoreDeinit(&result.completion_sem);
|
||||
DN_OS_SemaphoreDeinit(&result.completion_sem);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -14490,20 +14507,26 @@ DN_API bool DN_OS_ThreadInitLane(DN_OSThread *thread, DN_OSThreadFunc *func, DN_
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread, DN_TCDeinitArenas deinit_arenas)
|
||||
DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread, DN_U32 timeout_ms, DN_TCDeinitArenas deinit_arenas)
|
||||
{
|
||||
bool result = false;
|
||||
bool result = true;
|
||||
if (thread && thread->handle) {
|
||||
DN_AssertF(DN_BitIsNotSet(thread->flags, DN_OSThreadFlags_Detached),
|
||||
"Detached threads should have their handle immediately closed and invalidated so this branch should never hit.");
|
||||
pthread_t thread_id = {};
|
||||
DN_Memcpy(&thread_id, &thread->thread_id, sizeof(thread_id));
|
||||
|
||||
void *return_val = nullptr;
|
||||
result = pthread_join(thread_id, &return_val) == 0;
|
||||
thread->handle = {};
|
||||
thread->thread_id = {};
|
||||
DN_TCDeinit(&thread->context, deinit_arenas);
|
||||
DN_OSSemaphoreWaitResult wait_result = DN_OS_SemaphoreWait(&thread->join_done_sem, timeout_ms);
|
||||
if (wait_result == DN_OSSemaphoreWaitResult_Success) {
|
||||
void *return_val = {};
|
||||
pthread_join(thread_id, &return_val);
|
||||
thread->handle = {};
|
||||
thread->thread_id = {};
|
||||
DN_TCDeinit(&thread->context, deinit_arenas);
|
||||
DN_OS_SemaphoreDeinit(&thread->join_done_sem);
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -15917,18 +15940,21 @@ DN_API bool DN_OS_ThreadInitLane(DN_OSThread *thread, DN_OSThreadFunc *func, DN_
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread, DN_TCDeinitArenas deinit_arenas)
|
||||
DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread, DN_U32 timeout_ms, DN_TCDeinitArenas deinit_arenas)
|
||||
{
|
||||
bool result = false;
|
||||
bool result = true;
|
||||
if (thread && thread->handle && thread->handle != INVALID_HANDLE_VALUE) {
|
||||
DN_AssertF(DN_BitIsNotSet(thread->flags, DN_OSThreadFlags_Detached),
|
||||
"Detached threads should have their handle immediately closed and invalidated so this branch should never hit.");
|
||||
DWORD wait_result = WaitForSingleObject(thread->handle, INFINITE);
|
||||
result = wait_result == WAIT_OBJECT_0;
|
||||
CloseHandle(thread->handle);
|
||||
thread->handle = INVALID_HANDLE_VALUE;
|
||||
thread->thread_id = {};
|
||||
DN_TCDeinit(&thread->context, deinit_arenas);
|
||||
DWORD wait_result = WaitForSingleObject(thread->handle, timeout_ms);
|
||||
if (wait_result == WAIT_OBJECT_0) {
|
||||
CloseHandle(thread->handle);
|
||||
thread->handle = INVALID_HANDLE_VALUE;
|
||||
thread->thread_id = {};
|
||||
DN_TCDeinit(&thread->context, deinit_arenas);
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -16939,7 +16965,7 @@ void DN_NET_CurlDeinit(DN_NETCore *net)
|
||||
DN_NETCurlCore *curl = DN_Cast(DN_NETCurlCore *) net->context;
|
||||
curl->kill_thread = true;
|
||||
curl_multi_wakeup(curl->thread_curlm);
|
||||
DN_OS_ThreadJoin(&curl->thread, DN_TCDeinitArenas_Yes);
|
||||
DN_OS_ThreadJoin(&curl->thread, UINT32_MAX, DN_TCDeinitArenas_Yes);
|
||||
}
|
||||
|
||||
static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, DN_Str8 method, DN_NETDoHTTPArgs const *args, DN_NETRequestType type)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated by the DN single header generator 2026-07-16 23:31:53
|
||||
// Generated by the DN single header generator 2026-07-17 17:54:42
|
||||
|
||||
#if !defined(DN_H)
|
||||
#define DN_H
|
||||
@@ -4442,6 +4442,9 @@ struct DN_OSThread
|
||||
DN_OSThreadFunc *func;
|
||||
DN_OSSemaphore thread_exec_wait_for_thread_id_sem;
|
||||
DN_OSSemaphore caller_wait_for_thread_init_to_finish_sem;
|
||||
#if !defined(DN_PLATFORM_WIN32)
|
||||
DN_OSSemaphore join_done_sem;
|
||||
#endif
|
||||
DN_TCInitArgs tc_init_args;
|
||||
};
|
||||
|
||||
@@ -6701,9 +6704,13 @@ DN_API void DN_OS_ConditionVariableBroadcast (D
|
||||
//
|
||||
// For the general use-case if you wish to use lanes then prefer the `DN_OS_ThreadLane` APIs
|
||||
// below which create the threads with the lane information setup accordingly.
|
||||
|
||||
// DN_OS_ThreadJoin
|
||||
// Returns true if the thread joined successfully or it is already joined. False if timed out
|
||||
// waiting for the thread to join.
|
||||
DN_API bool DN_OS_ThreadInitLane (DN_OSThread *thread, DN_OSThreadFunc *func, DN_OSThreadLane *lane, DN_OSThreadInitArgs init_args, void *user_context);
|
||||
DN_API bool DN_OS_ThreadInit (DN_OSThread *thread, DN_OSThreadFunc *func, DN_OSThreadInitArgs init_args, void *user_context);
|
||||
DN_API bool DN_OS_ThreadJoin (DN_OSThread *thread, DN_TCDeinitArenas deinit_arenas);
|
||||
DN_API bool DN_OS_ThreadJoin (DN_OSThread *thread, DN_U32 timeout_ms, DN_TCDeinitArenas deinit_arenas);
|
||||
DN_API DN_U32 DN_OS_ThreadID ();
|
||||
DN_API DN_OSThreadInitArgs DN_OS_ThreadInitArgsDefault ();
|
||||
DN_API void DN_OS_ThreadSetNameFmt (char const *fmt, ...);
|
||||
@@ -6777,7 +6784,7 @@ DN_API DN_V2USize DN_OS_ThreadLaneRange (D
|
||||
DN_API DN_OSThreadLaneway DN_OS_ThreadLanewayFromArgs (DN_OSThread* threads, DN_USize threads_count, DN_UPtr* shared_mem);
|
||||
DN_API DN_OSThreadLaneway DN_OS_ThreadLanewayFromArena (DN_USize threads_count, DN_Arena* arena);
|
||||
DN_API void DN_OS_ThreadLanewayDispatch (DN_OSThreadLaneway *laneway, DN_OSThreadFunc *entry_point, DN_OSThreadInitArgs init_args, void *user_context);
|
||||
DN_API void DN_OS_ThreadLanewayJoin (DN_OSThreadLaneway *laneway, DN_TCDeinitArenas deinit_arenas);
|
||||
DN_API void DN_OS_ThreadLanewayJoin (DN_OSThreadLaneway *laneway, DN_U32 timeout_ms, DN_TCDeinitArenas deinit_arenas);
|
||||
|
||||
DN_API DN_OSThreadLane* DN_OS_TCThreadLane ();
|
||||
DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share);
|
||||
|
||||
Reference in New Issue
Block a user