Add timed thread join

This commit is contained in:
2026-07-17 18:12:21 +10:00
parent e1991685ef
commit b7ecf2439a
9 changed files with 274 additions and 177 deletions
+41 -15
View File
@@ -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) // DN: Single header generator commented out => #if defined(_CLANGD)
// #define DN_WITH_TESTS 1 // #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 // 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 // layer it should have closed any references to the thread so we should just need to cleanup the
// TLS. // 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); 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) 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->user_context = user_context;
thread->thread_exec_wait_for_thread_id_sem = DN_OS_SemaphoreInit(0 /*initial_count*/); 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*/); 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->tc_init_args = init_args.tc_args;
thread->flags = init_args.flags; thread->flags = init_args.flags;
if (lane) { if (lane) {
@@ -12481,9 +12494,13 @@ 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->thread_exec_wait_for_thread_id_sem);
DN_OS_SemaphoreDeinit(&thread->caller_wait_for_thread_init_to_finish_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 = {}; *thread = {};
} }
}
DN_API DN_OSThreadInitArgs DN_OS_ThreadInitArgsDefault() 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)) 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); 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_AtomicSetValue32(&async->join_threads, true);
DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count); DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count);
for (DN_ForItSize(it, DN_OSThread, async->threads, 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) { static bool DN_OS_AsyncQueueTask_(DN_OSAsyncCore *async, DN_OSAsyncTask const *task, DN_U64 wait_time_ms) {
@@ -14490,20 +14507,26 @@ DN_API bool DN_OS_ThreadInitLane(DN_OSThread *thread, DN_OSThreadFunc *func, DN_
return result; 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) { if (thread && thread->handle) {
DN_AssertF(DN_BitIsNotSet(thread->flags, DN_OSThreadFlags_Detached), 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."); "Detached threads should have their handle immediately closed and invalidated so this branch should never hit.");
pthread_t thread_id = {}; pthread_t thread_id = {};
DN_Memcpy(&thread_id, &thread->thread_id, sizeof(thread_id)); DN_Memcpy(&thread_id, &thread->thread_id, sizeof(thread_id));
void *return_val = nullptr; DN_OSSemaphoreWaitResult wait_result = DN_OS_SemaphoreWait(&thread->join_done_sem, timeout_ms);
result = pthread_join(thread_id, &return_val) == 0; if (wait_result == DN_OSSemaphoreWaitResult_Success) {
void *return_val = {};
pthread_join(thread_id, &return_val);
thread->handle = {}; thread->handle = {};
thread->thread_id = {}; thread->thread_id = {};
DN_TCDeinit(&thread->context, deinit_arenas); DN_TCDeinit(&thread->context, deinit_arenas);
DN_OS_SemaphoreDeinit(&thread->join_done_sem);
} else {
result = false;
}
} }
return result; return result;
} }
@@ -15917,18 +15940,21 @@ DN_API bool DN_OS_ThreadInitLane(DN_OSThread *thread, DN_OSThreadFunc *func, DN_
return result; 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) { if (thread && thread->handle && thread->handle != INVALID_HANDLE_VALUE) {
DN_AssertF(DN_BitIsNotSet(thread->flags, DN_OSThreadFlags_Detached), 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."); "Detached threads should have their handle immediately closed and invalidated so this branch should never hit.");
DWORD wait_result = WaitForSingleObject(thread->handle, INFINITE); DWORD wait_result = WaitForSingleObject(thread->handle, timeout_ms);
result = wait_result == WAIT_OBJECT_0; if (wait_result == WAIT_OBJECT_0) {
CloseHandle(thread->handle); CloseHandle(thread->handle);
thread->handle = INVALID_HANDLE_VALUE; thread->handle = INVALID_HANDLE_VALUE;
thread->thread_id = {}; thread->thread_id = {};
DN_TCDeinit(&thread->context, deinit_arenas); DN_TCDeinit(&thread->context, deinit_arenas);
} else {
result = false;
}
} }
return result; return result;
} }
@@ -16939,7 +16965,7 @@ void DN_NET_CurlDeinit(DN_NETCore *net)
DN_NETCurlCore *curl = DN_Cast(DN_NETCurlCore *) net->context; DN_NETCurlCore *curl = DN_Cast(DN_NETCurlCore *) net->context;
curl->kill_thread = true; curl->kill_thread = true;
curl_multi_wakeup(curl->thread_curlm); 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) static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, DN_Str8 method, DN_NETDoHTTPArgs const *args, DN_NETRequestType type)
+10 -3
View File
@@ -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) #if !defined(DN_H)
#define DN_H #define DN_H
@@ -4442,6 +4442,9 @@ struct DN_OSThread
DN_OSThreadFunc *func; DN_OSThreadFunc *func;
DN_OSSemaphore thread_exec_wait_for_thread_id_sem; DN_OSSemaphore thread_exec_wait_for_thread_id_sem;
DN_OSSemaphore caller_wait_for_thread_init_to_finish_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; 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 // 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. // 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_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_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_U32 DN_OS_ThreadID ();
DN_API DN_OSThreadInitArgs DN_OS_ThreadInitArgsDefault (); DN_API DN_OSThreadInitArgs DN_OS_ThreadInitArgsDefault ();
DN_API void DN_OS_ThreadSetNameFmt (char const *fmt, ...); 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_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 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_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 DN_OSThreadLane* DN_OS_TCThreadLane ();
DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share); DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share);
+80 -82
View File
@@ -1,11 +1,13 @@
#include "dn_seshc.h" #include "dn_seshc.h"
struct DN_SHSendDMThreadContext_ struct DN_SHMsgSendAsyncContext_
{ {
DN_Arena arena; bool send_success;
DN_Arena* arena;
DN_SHCLIArgs args; DN_SHCLIArgs args;
DN_Str8 sesh_pkey_hex; DN_SHMsgSendData send;
DN_Str8 msg; DN_Str8 msg;
bool detached;
}; };
DN_SHCLIArgs DN_SH_CLIArgsCopy(DN_SHCLIArgs const *src, DN_Arena *arena) DN_SHCLIArgs DN_SH_CLIArgsCopy(DN_SHCLIArgs const *src, DN_Arena *arena)
@@ -13,10 +15,8 @@ DN_SHCLIArgs DN_SH_CLIArgsCopy(DN_SHCLIArgs const *src, DN_Arena *arena)
DN_SHCLIArgs result = {}; DN_SHCLIArgs result = {};
result = *src; result = *src;
result.exe_path = DN_Str8FromStr8Arena(src->exe_path, arena); result.exe_path = DN_Str8FromStr8Arena(src->exe_path, arena);
result.account_secret = DN_Str8FromStr8Arena(src->account_secret, arena); result.ini_path = DN_Str8FromStr8Arena(src->ini_path, arena);
result.seed_node_url = DN_Str8FromStr8Arena(src->seed_node_url, arena); result.seed_node_url = DN_Str8FromStr8Arena(src->seed_node_url, arena);
result.display_name = DN_Str8FromStr8Arena(src->display_name, arena);
result.recipient_pkey = DN_Str8FromStr8Arena(src->recipient_pkey, arena);
return result; return result;
} }
@@ -25,16 +25,10 @@ DN_Str8 DN_SH_CLIOptionsStr8()
DN_Str8 result = DN_Str8Lit( DN_Str8 result = DN_Str8Lit(
"SESHC OPTIONS (note all options must be set to activate Seshc):\n" "SESHC OPTIONS (note all options must be set to activate Seshc):\n"
" --seshc-exe-path <path> Path to the Seshc EXE file to invoke for sending messages\n" " --seshc-exe-path <path> Path to the Seshc EXE file to invoke for sending messages\n"
" --seshc-ini-path <path> Path to the .ini file to load the secret/recipient public\n" " --seshc-ini-path <path> Path to the .ini file to load Seshc arguments from\n"
" key (only used if you are using `ini:` syntax)\n" " (such as account secrets, display name, recipient...)\n"
" --seshc-account-secret <secret> Specify the secret of the Session account to send a message\n"
" as (see --help on the Seshc EXE for more info)\n"
" --seshc-seed-node <url> URL to the Session seed node for determining the nodes to\n" " --seshc-seed-node <url> URL to the Session seed node for determining the nodes to\n"
" send the message to\n" " send the message to\n"
" --seshc-display-name <name> Display name to send the message as\n"
" --seshc-recipient-pkey <name|ini:..> Recipient to send the message as (must be 0x05 prefixed, 0x\n"
" is optional), or alternatively `ini:` syntax (see --help on\n"
" the Seshc EXE for more info)."
); );
return result; return result;
} }
@@ -75,46 +69,19 @@ DN_SHCLIEatArgResult DN_SH_CLIEatArg(DN_SHCLIArgs *args, char const **arg_ptr, i
} }
} }
if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-account-secret"))) {
(void)DN_ArgShift(result.arg_ptr, result.arg_count);
result.eaten = true;
args->account_secret = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count));
}
if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-seed-node"))) { if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-seed-node"))) {
(void)DN_ArgShift(result.arg_ptr, result.arg_count); (void)DN_ArgShift(result.arg_ptr, result.arg_count);
result.eaten = true; result.eaten = true;
args->seed_node_url = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count)); args->seed_node_url = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count));
} }
if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-display-name"))) {
(void)DN_ArgShift(result.arg_ptr, result.arg_count);
result.eaten = true;
args->display_name = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count));
} }
if (!result.eaten && DN_Str8EqInsensitive(arg, DN_Str8Lit("--seshc-recipient-pkey"))) { if (args->seed_node_url.count && args->exe_path.count && args->ini_path.count)
(void)DN_ArgShift(result.arg_ptr, result.arg_count);
result.eaten = true;
args->recipient_pkey = DN_Str8FromCStr8(DN_ArgShift(result.arg_ptr, result.arg_count));
DN_Str8 check = DN_Str8TrimHexPrefix(args->recipient_pkey);
bool ini_prefixed = DN_Str8StartsWithSensitive(check, DN_Str8Lit("ini:"));
bool sesh_prefixed = !ini_prefixed && (DN_Str8StartsWithSensitive(check, DN_Str8Lit("05")) || DN_Str8StartsWithInsensitive(check, DN_Str8Lit("0x05")));
if (!ini_prefixed && !sesh_prefixed) {
result.error_msg = DN_Str8Lit("Seshc recipient public key does not specify a 05 prefixed public key, or, use `ini:` to specify a public key in the .ini file");
result.error_arg = args->recipient_pkey;
args->recipient_pkey = {};
}
}
}
if (args->seed_node_url.count && args->account_secret.count && args->exe_path.count && args->recipient_pkey.count)
args->valid = true; args->valid = true;
return result; return result;
} }
bool DN_SH_CLIArgsSendDMBlockingFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, char const *fmt, ...) bool DN_SH_MsgSendBlockingFmt(DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, char const *fmt, ...)
{ {
bool result = false; bool result = false;
if (cli_args->valid) { if (cli_args->valid) {
@@ -136,23 +103,21 @@ bool DN_SH_CLIArgsSendDMBlockingFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, c
DN_LArrayAppend(cmds, &cmds_count, cli_args->exe_path); DN_LArrayAppend(cmds, &cmds_count, cli_args->exe_path);
DN_LArrayAppend(cmds, &cmds_count, account_secret_arg); DN_LArrayAppend(cmds, &cmds_count, account_secret_arg);
DN_LArrayAppend(cmds, &cmds_count, cli_args->account_secret); DN_LArrayAppend(cmds, &cmds_count, send.account_secret);
DN_LArrayAppend(cmds, &cmds_count, seed_node_url_arg); DN_LArrayAppend(cmds, &cmds_count, seed_node_url_arg);
DN_LArrayAppend(cmds, &cmds_count, cli_args->seed_node_url); DN_LArrayAppend(cmds, &cmds_count, cli_args->seed_node_url);
if (cli_args->display_name.count) { if (send.display_name.count) {
DN_LArrayAppend(cmds, &cmds_count, display_name_arg); DN_LArrayAppend(cmds, &cmds_count, display_name_arg);
DN_LArrayAppend(cmds, &cmds_count, cli_args->display_name); DN_LArrayAppend(cmds, &cmds_count, send.display_name);
} }
if (cli_args->ini_path.count) {
DN_LArrayAppend(cmds, &cmds_count, ini_path_arg); DN_LArrayAppend(cmds, &cmds_count, ini_path_arg);
DN_LArrayAppend(cmds, &cmds_count, cli_args->ini_path); DN_LArrayAppend(cmds, &cmds_count, cli_args->ini_path);
}
DN_LArrayAppend(cmds, &cmds_count, send_arg); DN_LArrayAppend(cmds, &cmds_count, send_arg);
DN_LArrayAppend(cmds, &cmds_count, sesh_pkey); DN_LArrayAppend(cmds, &cmds_count, send.recipient);
DN_LArrayAppend(cmds, &cmds_count, msg); DN_LArrayAppend(cmds, &cmds_count, msg);
@@ -167,7 +132,7 @@ bool DN_SH_CLIArgsSendDMBlockingFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, c
result = exec.os_error_code == 0 && exec.exit_code == 0; result = exec.os_error_code == 0 && exec.exit_code == 0;
if (!result) { if (!result) {
DN_LogErrorF("Error sending message to %.*s (exit code: %d, os: %d): %.*s", DN_LogErrorF("Error sending message to %.*s (exit code: %d, os: %d): %.*s",
DN_Str8PrintFmt(cli_args->recipient_pkey), DN_Str8PrintFmt(send.recipient),
exec.exit_code, exec.exit_code,
exec.os_error_code, exec.os_error_code,
DN_Str8PrintFmt(exec.stderr_text)); DN_Str8PrintFmt(exec.stderr_text));
@@ -178,59 +143,76 @@ bool DN_SH_CLIArgsSendDMBlockingFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, c
return result; return result;
} }
static int DN_SH_CLIArgsSendDMDetachedFmtThreadFunc_(DN_OSThread *thread) static int DN_SH_MsgSendDetachedFmtThreadFunc_(DN_OSThread *thread)
{ {
DN_SHSendDMThreadContext_ *context = DN_Cast(DN_SHSendDMThreadContext_ *) thread->user_context; DN_SHMsgSendAsyncContext_ *context = DN_Cast(DN_SHMsgSendAsyncContext_ *) thread->user_context;
DN_SH_CLIArgsSendDMBlockingFmt(&context->args, context->sesh_pkey_hex, "%.*s", DN_Str8PrintFmt(context->msg)); context->send_success = DN_SH_MsgSendBlockingFmt(context->send, &context->args, "%.*s", DN_Str8PrintFmt(context->msg));
DN_ArenaDeinit(&context->arena); if (context->detached)
DN_ArenaDeinit(context->arena);
return 0; return 0;
} }
void DN_SH_CLIArgsSendDMDetachedFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, char const *fmt, ...) static DN_SHMsgSendAsyncHandle DN_SH_MsgSendAsyncFmtVMaybeDetached_(DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, DN_Arena *arena, bool detached, char const *fmt, va_list args)
{ {
DN_SHMsgSendAsyncHandle result = {};
if (!cli_args->valid) if (!cli_args->valid)
return; return result;
// NOTE: Setup context // NOTE: Setup context
DN_Arena arena = DN_OS_ArenaFromHeapVirtual(0, 0, DN_MemFlags_Nil); DN_SHMsgSendAsyncContext_ *context = DN_ArenaNewZ(arena, DN_SHMsgSendAsyncContext_);
DN_SHSendDMThreadContext_ *context = DN_ArenaNewZ(&arena, DN_SHSendDMThreadContext_); context->args = DN_SH_CLIArgsCopy(cli_args, arena);
context->args = DN_SH_CLIArgsCopy(cli_args, &arena); context->send = send;
context->sesh_pkey_hex = DN_Str8FromStr8Arena(sesh_pkey, &arena);
va_list args;
va_start(args, fmt);
context->msg = DN_Str8FromFmtVArena(&arena, fmt, args);
va_end(args);
// NOTE: Set the arena last after all allocations
context->arena = arena; context->arena = arena;
context->msg = DN_Str8FromFmtVArena(arena, fmt, args);
// NOTE: Setup thread to be detached context->detached = detached;
DN_OSThread thread = {};
DN_OSThreadInitArgs thread_args = DN_OS_ThreadInitArgsDefault();
thread_args.flags |= DN_OSThreadFlags_Detached;
// NOTE: Execute and forget // NOTE: Execute and forget
DN_OS_ThreadInit(&thread, DN_SH_CLIArgsSendDMDetachedFmtThreadFunc_, thread_args, context); DN_OSThreadInitArgs thread_args = DN_OS_ThreadInitArgsDefault();
if (detached)
thread_args.flags |= DN_OSThreadFlags_Detached;
DN_OS_ThreadInit(&result.thread, DN_SH_MsgSendDetachedFmtThreadFunc_, thread_args, context);
return result;
} }
void DN_SH_LogBroadcastBlockingFmt(DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...) void DN_SH_MsgSendDetachedFmt(DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, char const *fmt, ...)
{ {
DN_Arena arena_stack = DN_OS_ArenaFromHeapVirtual(0, 0, DN_MemFlags_Nil);
DN_Arena *arena = DN_ArenaNewZ(&arena_stack, DN_Arena);
*arena = arena_stack;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
DN_SH_LogBroadcastFmtV(DN_SHLogMode_Blocking, type, cli_args, short_desc, fmt, args); DN_SH_MsgSendAsyncFmtVMaybeDetached_(send, cli_args, arena, /*detached=*/ true, fmt, args);
va_end(args); va_end(args);
} }
void DN_SH_LogBroadcastDetachedFmt(DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...) DN_SHMsgSendAsyncHandle DN_SH_MsgSendAsyncFmt(DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, DN_Arena *arena, char const *fmt, ...)
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
DN_SH_LogBroadcastFmtV(DN_SHLogMode_Detached, type, cli_args, short_desc, fmt, args); DN_SHMsgSendAsyncHandle result = DN_SH_MsgSendAsyncFmtVMaybeDetached_(send, cli_args, arena, /*detached=*/ false, fmt, args);
va_end(args); va_end(args);
return result;
} }
void DN_SH_LogBroadcastFmtV(DN_SHLogMode mode, DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, va_list args) DN_SHMsgSendAsyncStatus DN_SH_MsgSendAsyncWait(DN_SHMsgSendAsyncHandle *handle, DN_U32 timeout_ms)
{
DN_SHMsgSendAsyncStatus result = DN_SHMsgSendAsyncStatus_Success;
if (handle && handle->thread.user_context) {
bool joined = DN_OS_ThreadJoin(&handle->thread, timeout_ms, DN_TCDeinitArenas_Yes);
if (joined) {
DN_SHMsgSendAsyncContext_ *context = DN_Cast(DN_SHMsgSendAsyncContext_ *) handle->thread.user_context;
result = context->send_success ? DN_SHMsgSendAsyncStatus_Success : DN_SHMsgSendAsyncStatus_Failed;
*handle = {};
} else {
result = DN_SHMsgSendAsyncStatus_Timeout;
}
}
return result;
}
void DN_SH_LogBroadcastFmtV(DN_SHLogMode mode, DN_LogType type, DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, va_list args)
{ {
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0); DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
DN_Str8 msg = DN_Str8FromFmtVArena(&scratch.arena, fmt, args); DN_Str8 msg = DN_Str8FromFmtVArena(&scratch.arena, fmt, args);
@@ -266,8 +248,8 @@ void DN_SH_LogBroadcastFmtV(DN_SHLogMode mode, DN_LogType type, DN_SHCLIArgs *cl
time_emoji = DN_Str8Lit("🌑"); time_emoji = DN_Str8Lit("🌑");
if (mode == DN_SHLogMode_Detached) { if (mode == DN_SHLogMode_Detached) {
DN_SH_CLIArgsSendDMDetachedFmt(cli_args, DN_SH_MsgSendDetachedFmt(send,
cli_args->recipient_pkey, cli_args,
"%.*s%.*s\n" "%.*s%.*s\n"
"%.*s %u-%02u-%02u %u:%02u:%02u %s\n" "%.*s %u-%02u-%02u %u:%02u:%02u %s\n"
"%.*s", "%.*s",
@@ -284,8 +266,8 @@ void DN_SH_LogBroadcastFmtV(DN_SHLogMode mode, DN_LogType type, DN_SHCLIArgs *cl
DN_Str8PrintFmt(msg)); DN_Str8PrintFmt(msg));
} else { } else {
DN_Assert(mode == DN_SHLogMode_Blocking); DN_Assert(mode == DN_SHLogMode_Blocking);
DN_SH_CLIArgsSendDMBlockingFmt(cli_args, DN_SH_MsgSendBlockingFmt(send,
cli_args->recipient_pkey, cli_args,
"%.*s %.*s\n" "%.*s %.*s\n"
"%.*s %u-%02u-%02u %u:%02u:%02u %s\n" "%.*s %u-%02u-%02u %u:%02u:%02u %s\n"
"%.*s", "%.*s",
@@ -303,3 +285,19 @@ void DN_SH_LogBroadcastFmtV(DN_SHLogMode mode, DN_LogType type, DN_SHCLIArgs *cl
} }
DN_TCScratchEnd(&scratch); DN_TCScratchEnd(&scratch);
} }
void DN_SH_LogBroadcastBlockingFmt(DN_LogType type, DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
DN_SH_LogBroadcastFmtV(DN_SHLogMode_Blocking, type, send, cli_args, short_desc, fmt, args);
va_end(args);
}
void DN_SH_LogBroadcastDetachedFmt(DN_LogType type, DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
DN_SH_LogBroadcastFmtV(DN_SHLogMode_Detached, type, send, cli_args, short_desc, fmt, args);
va_end(args);
}
+42 -8
View File
@@ -11,10 +11,7 @@ struct DN_SHCLIArgs
bool valid; bool valid;
DN_Str8 exe_path; DN_Str8 exe_path;
DN_Str8 ini_path; DN_Str8 ini_path;
DN_Str8 account_secret;
DN_Str8 seed_node_url; DN_Str8 seed_node_url;
DN_Str8 display_name;
DN_Str8 recipient_pkey;
}; };
struct DN_SHCLIEatArgResult struct DN_SHCLIEatArgResult
@@ -26,23 +23,60 @@ struct DN_SHCLIEatArgResult
DN_USize arg_count; // Next argument count that that the caller should assume DN_USize arg_count; // Next argument count that that the caller should assume
}; };
struct DN_SHMsgSendData
{
DN_Str8 recipient; // Either `ini:<section.key>` or "05-prefix session account ID"
DN_Str8 account_secret; // Seshc EXE --account-secret format
DN_Str8 display_name;
};
struct DN_SHMsgSendAsyncHandle
{
DN_OSThread thread;
};
enum DN_SHLogMode enum DN_SHLogMode
{ {
DN_SHLogMode_Blocking, DN_SHLogMode_Blocking,
DN_SHLogMode_Detached, DN_SHLogMode_Detached,
}; };
enum DN_SHMsgSendAsyncStatus
{
DN_SHMsgSendAsyncStatus_Timeout,
DN_SHMsgSendAsyncStatus_Success,
DN_SHMsgSendAsyncStatus_Failed,
};
// NOTE: Seshc // NOTE: Seshc
// Overview // Overview
// Helper library that provides some useful APIs for programatically calling the Seshc CLI // Helper library that provides some useful APIs for programatically calling the Seshc CLI
// executable to send messages from your C/C++ application. // executable to send messages from your C/C++ application.
// API
// DN_SH_MsgSendDetachedFmt
// Send a 1-on-1 message with a background thread that is spawned on demand and detached. If the
// application exits before this thread has completed sending the message, the message will not
// be sent.
// DN_SH_MsgSendBlockingFmt
// Send a 1-on-1 message using the current executing thread, blocking control-flow until the
// message has been sent. Returns true if the send was successful, false otherwise.
// DN_SH_MsgSendAsyncFmt
// Send a 1-on-1 message with a background thread that is spawned on demand. A handle to the
// thread is returned that can be waited on.
DN_SHCLIArgs DN_SH_CLIArgsCopy (DN_SHCLIArgs const *src, DN_Arena *arena); DN_SHCLIArgs DN_SH_CLIArgsCopy (DN_SHCLIArgs const *src, DN_Arena *arena);
DN_Str8 DN_SH_CLIOptionsStr8 (); DN_Str8 DN_SH_CLIOptionsStr8 ();
DN_SHCLIEatArgResult DN_SH_CLIEatArg (DN_SHCLIArgs *args, char const **arg_ptr, int arg_count); DN_SHCLIEatArgResult DN_SH_CLIEatArg (DN_SHCLIArgs *args, char const **arg_ptr, int arg_count);
bool DN_SH_CLIArgsSendDMBlockingFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, char const *fmt, ...); bool DN_SH_MsgSendBlockingFmt (DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, char const *fmt, ...);
void DN_SH_CLIArgsSendDMDetachedFmt(DN_SHCLIArgs *cli_args, DN_Str8 sesh_pkey, char const *fmt, ...); void DN_SH_MsgSendDetachedFmt (DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, char const *fmt, ...);
void DN_SH_LogBroadcastFmtV (DN_SHLogMode mode, DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, va_list args); DN_SHMsgSendAsyncHandle DN_SH_MsgSendAsyncFmt (DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, DN_Arena *arena, char const *fmt, ...);
void DN_SH_LogBroadcastBlockingFmt (DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...); DN_SHMsgSendAsyncStatus DN_SH_MsgSendAsyncWait (DN_SHMsgSendAsyncHandle *handle, DN_U32 timeout_ms);
void DN_SH_LogBroadcastDetachedFmt (DN_LogType type, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...); void DN_SH_LogBroadcastFmtV (DN_SHLogMode mode, DN_LogType type, DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, va_list args);
void DN_SH_LogBroadcastBlockingFmt (DN_LogType type, DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...);
void DN_SH_LogBroadcastDetachedFmt (DN_LogType type, DN_SHMsgSendData send, DN_SHCLIArgs *cli_args, DN_Str8 short_desc, char const *fmt, ...);
#endif // #if !defined(DN_SESHC_H) #endif // #if !defined(DN_SESHC_H)
+10 -4
View File
@@ -1322,20 +1322,26 @@ DN_API bool DN_OS_ThreadInitLane(DN_OSThread *thread, DN_OSThreadFunc *func, DN_
return result; 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) { if (thread && thread->handle) {
DN_AssertF(DN_BitIsNotSet(thread->flags, DN_OSThreadFlags_Detached), 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."); "Detached threads should have their handle immediately closed and invalidated so this branch should never hit.");
pthread_t thread_id = {}; pthread_t thread_id = {};
DN_Memcpy(&thread_id, &thread->thread_id, sizeof(thread_id)); DN_Memcpy(&thread_id, &thread->thread_id, sizeof(thread_id));
void *return_val = nullptr; DN_OSSemaphoreWaitResult wait_result = DN_OS_SemaphoreWait(&thread->join_done_sem, timeout_ms);
result = pthread_join(thread_id, &return_val) == 0; if (wait_result == DN_OSSemaphoreWaitResult_Success) {
void *return_val = {};
pthread_join(thread_id, &return_val);
thread->handle = {}; thread->handle = {};
thread->thread_id = {}; thread->thread_id = {};
DN_TCDeinit(&thread->context, deinit_arenas); DN_TCDeinit(&thread->context, deinit_arenas);
DN_OS_SemaphoreDeinit(&thread->join_done_sem);
} else {
result = false;
}
} }
return result; return result;
} }
+7 -4
View File
@@ -1307,18 +1307,21 @@ DN_API bool DN_OS_ThreadInitLane(DN_OSThread *thread, DN_OSThreadFunc *func, DN_
return result; 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) { if (thread && thread->handle && thread->handle != INVALID_HANDLE_VALUE) {
DN_AssertF(DN_BitIsNotSet(thread->flags, DN_OSThreadFlags_Detached), 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."); "Detached threads should have their handle immediately closed and invalidated so this branch should never hit.");
DWORD wait_result = WaitForSingleObject(thread->handle, INFINITE); DWORD wait_result = WaitForSingleObject(thread->handle, timeout_ms);
result = wait_result == WAIT_OBJECT_0; if (wait_result == WAIT_OBJECT_0) {
CloseHandle(thread->handle); CloseHandle(thread->handle);
thread->handle = INVALID_HANDLE_VALUE; thread->handle = INVALID_HANDLE_VALUE;
thread->thread_id = {}; thread->thread_id = {};
DN_TCDeinit(&thread->context, deinit_arenas); DN_TCDeinit(&thread->context, deinit_arenas);
} else {
result = false;
}
} }
return result; return result;
} }
-1
View File
@@ -220,7 +220,6 @@ DN_INIToken DN_INI_NextToken(DN_INITokeniser const *tokeniser)
tokeniser->prev_token.type == DN_INITokenType_MultilineValue || tokeniser->prev_token.type == DN_INITokenType_MultilineValue ||
tokeniser->prev_token.type == DN_INITokenType_Section) { tokeniser->prev_token.type == DN_INITokenType_Section) {
result.type = DN_INITokenType_EndOfStream; result.type = DN_INITokenType_EndOfStream;
break;
} else { } else {
result.type = DN_INITokenType_Error; result.type = DN_INITokenType_Error;
result.error = DN_INIStr8Lit("Premature end of stream encountered malforming the last key-value pair"); result.error = DN_INIStr8Lit("Premature end of stream encountered malforming the last key-value pair");
+23 -6
View File
@@ -12443,8 +12443,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 // 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 // layer it should have closed any references to the thread so we should just need to cleanup the
// TLS. // 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); 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) static void DN_OS_ThreadPreInit_(DN_OSThread *thread, DN_OSThreadFunc *func, DN_OSThreadLane *lane, DN_OSThreadInitArgs init_args, void *user_context)
@@ -12454,6 +12464,9 @@ static void DN_OS_ThreadPreInit_(DN_OSThread *thread, DN_OSThreadFunc *func, DN_
thread->user_context = user_context; thread->user_context = user_context;
thread->thread_exec_wait_for_thread_id_sem = DN_OS_SemaphoreInit(0 /*initial_count*/); 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*/); 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->tc_init_args = init_args.tc_args;
thread->flags = init_args.flags; thread->flags = init_args.flags;
if (lane) { if (lane) {
@@ -12479,9 +12492,13 @@ 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->thread_exec_wait_for_thread_id_sem);
DN_OS_SemaphoreDeinit(&thread->caller_wait_for_thread_init_to_finish_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 = {}; *thread = {};
} }
}
DN_API DN_OSThreadInitArgs DN_OS_ThreadInitArgsDefault() DN_API DN_OSThreadInitArgs DN_OS_ThreadInitArgsDefault()
{ {
@@ -12598,10 +12615,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)) 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); DN_OS_BarrierDeinit(&laneway->barrier);
} }
@@ -12685,7 +12702,7 @@ DN_API void DN_OS_AsyncDeinit(DN_OSAsyncCore *async)
DN_AtomicSetValue32(&async->join_threads, true); DN_AtomicSetValue32(&async->join_threads, true);
DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count); DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count);
for (DN_ForItSize(it, DN_OSThread, async->threads, 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) { static bool DN_OS_AsyncQueueTask_(DN_OSAsyncCore *async, DN_OSAsyncTask const *task, DN_U64 wait_time_ms) {
@@ -13772,7 +13789,7 @@ void DN_NET_CurlDeinit(DN_NETCore *net)
DN_NETCurlCore *curl = DN_Cast(DN_NETCurlCore *) net->context; DN_NETCurlCore *curl = DN_Cast(DN_NETCurlCore *) net->context;
curl->kill_thread = true; curl->kill_thread = true;
curl_multi_wakeup(curl->thread_curlm); 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) static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, DN_Str8 method, DN_NETDoHTTPArgs const *args, DN_NETRequestType type)
+9 -2
View File
@@ -2512,6 +2512,9 @@ struct DN_OSThread
DN_OSThreadFunc *func; DN_OSThreadFunc *func;
DN_OSSemaphore thread_exec_wait_for_thread_id_sem; DN_OSSemaphore thread_exec_wait_for_thread_id_sem;
DN_OSSemaphore caller_wait_for_thread_init_to_finish_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; DN_TCInitArgs tc_init_args;
}; };
@@ -4771,9 +4774,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 // 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. // 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_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_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_U32 DN_OS_ThreadID ();
DN_API DN_OSThreadInitArgs DN_OS_ThreadInitArgsDefault (); DN_API DN_OSThreadInitArgs DN_OS_ThreadInitArgsDefault ();
DN_API void DN_OS_ThreadSetNameFmt (char const *fmt, ...); DN_API void DN_OS_ThreadSetNameFmt (char const *fmt, ...);
@@ -4847,7 +4854,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_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 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_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 DN_OSThreadLane* DN_OS_TCThreadLane ();
DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share); DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share);