From a3571136516c19caf13ccc5f0cb5529ee8fe749b Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Tue, 22 Jul 2025 10:52:29 +0700 Subject: [PATCH] thread.create et al with name parameter --- core/thread/thread.odin | 69 ++++++++++++++------------------- core/thread/thread_other.odin | 2 +- core/thread/thread_unix.odin | 29 +++++++------- core/thread/thread_windows.odin | 17 ++++---- 4 files changed, 53 insertions(+), 64 deletions(-) diff --git a/core/thread/thread.odin b/core/thread/thread.odin index 56853a080..d4a27de13 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -48,6 +48,9 @@ Thread :: struct { // started. Should be set after the thread has been created, but before // it is started. data: rawptr, + // Thread's Name/Description that will get set during thread creation + // for thread's creation only : do not refer to it, use thread.get_name instead + name: Maybe(string), // User-supplied integer, that will be available to the thread once it is // started. Should be set after the thread has been created, but before // it is started. @@ -102,8 +105,8 @@ thread will be in a suspended state, until `start()` procedure is called. To start the thread, call `start()`. Also the `create_and_start()` procedure can be called to create and start the thread immediately. */ -create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread { - return _create(procedure, priority) +create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal, name: Maybe(string) = nil) -> ^Thread { + return _create(procedure, priority, name) } /* @@ -166,20 +169,6 @@ get_name :: proc(thread: ^Thread, allocator := context.temp_allocator, loc := #c return _get_name(thread, allocator, loc) } -/* -Set thread's name/description. - -If thread is nil the procedure will set the name of the calling thread. - -the provided string must be available until this procedure ends -and will be truncated to fit their platform's limit. - -MacOS: only supports changing the name of the calling thread. -if thread is not nil the procedure will do nothing. -*/ -set_name :: proc(thread: ^Thread, name: string) { - _set_name(thread, name) -} /* Run a procedure on a different thread. @@ -191,8 +180,8 @@ to execute. The thread will have priority specified by the `priority` parameter. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -run :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) { - create_and_start(fn, init_context, priority, true) +run :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, name: Maybe(string) = nil) { + create_and_start(fn, init_context, priority, true, name) } /* @@ -206,8 +195,8 @@ to execute. The thread will have priority specified by the `priority` parameter. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -run_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) { - create_and_start_with_data(data, fn, init_context, priority, true) +run_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, name: Maybe(string) = nil) { + create_and_start_with_data(data, fn, init_context, priority, true, name) } /* @@ -221,9 +210,9 @@ to execute. The thread will have priority specified by the `priority` parameter. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -run_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) +run_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, name: Maybe(string) = nil) where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { - create_and_start_with_poly_data(data, fn, init_context, priority, true) + create_and_start_with_poly_data(data, fn, init_context, priority, true, name) } /* @@ -237,9 +226,9 @@ to execute. The thread will have priority specified by the `priority` parameter. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -run_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) +run_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, name: Maybe(string) = nil) where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { - create_and_start_with_poly_data2(arg1, arg2, fn, init_context, priority, true) + create_and_start_with_poly_data2(arg1, arg2, fn, init_context, priority, true, name) } /* @@ -253,9 +242,9 @@ to execute. The thread will have priority specified by the `priority` parameter. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -run_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) +run_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, name: Maybe(string) = nil) where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { - create_and_start_with_poly_data3(arg1, arg2, arg3, fn, init_context, priority, true) + create_and_start_with_poly_data3(arg1, arg2, arg3, fn, init_context, priority, true, name) } /* @@ -269,9 +258,9 @@ to execute. The thread will have priority specified by the `priority` parameter. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -run_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) +run_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, name: Maybe(string) = nil) where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS { - create_and_start_with_poly_data4(arg1, arg2, arg3, arg4, fn, init_context, priority, true) + create_and_start_with_poly_data4(arg1, arg2, arg3, arg4, fn, init_context, priority, true, name) } /* @@ -292,12 +281,12 @@ That includes calling `join`, which needs to dereference ^Thread`. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) { +create_and_start :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false, name: Maybe(string) = nil) -> (t: ^Thread) { thread_proc :: proc(t: ^Thread) { fn := cast(proc())t.data fn() } - if t = create(thread_proc, priority); t == nil { + if t = create(thread_proc, priority, name); t == nil { return } t.data = rawptr(fn) @@ -327,14 +316,14 @@ That includes calling `join`, which needs to dereference ^Thread`. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) { +create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false, name: Maybe(string) = nil) -> (t: ^Thread) { thread_proc :: proc(t: ^Thread) { fn := cast(proc(rawptr))t.data assert(t.user_index >= 1) data := t.user_args[0] fn(data) } - if t = create(thread_proc, priority); t == nil { + if t = create(thread_proc, priority, name); t == nil { return } t.data = rawptr(fn) @@ -366,7 +355,7 @@ That includes calling `join`, which needs to dereference ^Thread`. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) +create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false, name: Maybe(string) = nil) -> (t: ^Thread) where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T))t.data @@ -374,7 +363,7 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex data := (^T)(&t.user_args[0])^ fn(data) } - if t = create(thread_proc, priority); t == nil { + if t = create(thread_proc, priority, name); t == nil { return } t.data = rawptr(fn) @@ -411,7 +400,7 @@ That includes calling `join`, which needs to dereference ^Thread`. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) +create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false, name: Maybe(string) = nil) -> (t: ^Thread) where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T1, T2))t.data @@ -423,7 +412,7 @@ create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), fn(arg1, arg2) } - if t = create(thread_proc, priority); t == nil { + if t = create(thread_proc, priority, name); t == nil { return } t.data = rawptr(fn) @@ -462,7 +451,7 @@ That includes calling `join`, which needs to dereference ^Thread`. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) +create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false, name: Maybe(string) = nil) -> (t: ^Thread) where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T1, T2, T3))t.data @@ -475,7 +464,7 @@ create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: pr fn(arg1, arg2, arg3) } - if t = create(thread_proc, priority); t == nil { + if t = create(thread_proc, priority, name); t == nil { return } t.data = rawptr(fn) @@ -515,7 +504,7 @@ That includes calling `join`, which needs to dereference ^Thread`. is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) +create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false, name: Maybe(string) = nil) -> (t: ^Thread) where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T1, T2, T3, T4))t.data @@ -529,7 +518,7 @@ create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: fn(arg1, arg2, arg3, arg4) } - if t = create(thread_proc, priority); t == nil { + if t = create(thread_proc, priority, name); t == nil { return } t.data = rawptr(fn) diff --git a/core/thread/thread_other.odin b/core/thread/thread_other.odin index ef71fa086..83ea31fe1 100644 --- a/core/thread/thread_other.odin +++ b/core/thread/thread_other.odin @@ -14,7 +14,7 @@ _thread_priority_map := [Thread_Priority]i32{ .High = +2, } -_create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread { +_create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal, name: Maybe(string) = nil) -> ^Thread { unimplemented("core:thread procedure not supported on target") } diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 80766fad6..c723c434e 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -19,7 +19,7 @@ Thread_Os_Specific :: struct #align(16) { // Creates a thread which will run the given procedure. // It then waits for `start` to be called. // -_create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { +_create :: proc(procedure: Thread_Proc, priority: Thread_Priority, name: Maybe(string)) -> ^Thread { __unix_thread_entry_proc :: proc "c" (t: rawptr) -> rawptr { t := (^Thread)(t) @@ -58,6 +58,8 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { runtime.run_thread_local_cleaners() } + _set_name(t) + t.procedure(t) } @@ -211,23 +213,18 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So return } -_set_name :: proc(thread: ^Thread, name: string) { - // Haiku doesn't have pthread_getname yet - when ODIN_OS == .Haiku { - unimplemented("core:thread set_name for haiku is not yet supported") - } else when ODIN_OS == .Darwin { - if thread != nil { - return - } - } else { - tid: posix.pthread_t - if thread == nil { - tid = posix.pthread_self() - } else { - tid = thread.unix_thread - } +_set_name :: proc(thread: ^Thread) { + if ODIN_OS == .Haiku { + return } + name, ok := thread.name.? + if !ok { + return + } + + tid := thread.unix_thread + buf: [_MAX_PTHREAD_NAME_LENGTH]u8 copy(buf[:], name) diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index ba1da9aa8..bd586ed49 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -25,7 +25,7 @@ _thread_priority_map := [Thread_Priority]i32{ .High = +2, } -_create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { +_create :: proc(procedure: Thread_Proc, priority: Thread_Priority, name: Maybe(string)) -> ^Thread { win32_thread_id: win32.DWORD __windows_thread_entry_proc :: proc "system" (t_: rawptr) -> win32.DWORD { @@ -47,6 +47,8 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { runtime.run_thread_local_cleaners() } + _set_name(t) + t.procedure(t) } @@ -79,6 +81,7 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { thread.win32_thread = win32_thread thread.win32_thread_id = win32_thread_id thread.id = int(win32_thread_id) + thread.name = name ok := win32.SetThreadPriority(win32_thread, _thread_priority_map[priority]) assert(ok == true) @@ -170,14 +173,14 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So return } -_set_name :: proc(thread: ^Thread, name: string) { - t_handle: win32.HANDLE - if thread == nil { - t_handle = win32.GetCurrentThread() - } else { - t_handle = thread.win32_thread +_set_name :: proc(thread: ^Thread) { + name, ok := thread.name.? + if !ok { + return } + t_handle = thread.win32_thread + buf: [_THREAD_DESCRIPTION_LENGTH]u16 // _THREAD_DESCRIPTION_LENGTH includes terminating null utf16.encode_string(buf[:len(buf) - 1], name)