From 0a3f73077e1630da7bd122b4fc341136f37d0336 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Mon, 14 Jul 2025 17:23:36 +0700 Subject: [PATCH 01/38] Get/Set Thread names --- core/sys/posix/pthread.odin | 2 +- core/thread/thread.odin | 22 +++++++++++ core/thread/thread_name_darwin.odin | 13 +++++++ core/thread/thread_name_freebsd.odin | 13 +++++++ core/thread/thread_name_linux.odin | 13 +++++++ core/thread/thread_name_netbsd.odin | 13 +++++++ core/thread/thread_name_openbsd.odin | 13 +++++++ core/thread/thread_other.odin | 5 +++ core/thread/thread_unix.odin | 56 +++++++++++++++++++++++++++- core/thread/thread_windows.odin | 33 ++++++++++++++++ 10 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 core/thread/thread_name_darwin.odin create mode 100644 core/thread/thread_name_freebsd.odin create mode 100644 core/thread/thread_name_linux.odin create mode 100644 core/thread/thread_name_netbsd.odin create mode 100644 core/thread/thread_name_openbsd.odin diff --git a/core/sys/posix/pthread.odin b/core/sys/posix/pthread.odin index 36a3cd7b3..44b0c91d7 100644 --- a/core/sys/posix/pthread.odin +++ b/core/sys/posix/pthread.odin @@ -5,7 +5,7 @@ import "core:c" when ODIN_OS == .Darwin { foreign import lib "system:System.framework" -} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .Linux { +} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .Linux || ODIN_OS == .OpenBSD { foreign import lib "system:pthread" } else { foreign import lib "system:c" diff --git a/core/thread/thread.odin b/core/thread/thread.odin index 194c7bfef..d4fb48862 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -155,6 +155,28 @@ yield :: proc() { _yield() } +/* +Get thread's name/description. + +If thread is nil the procedure will get the name of the calling thread. + +allocates memory for the returned string using provided allocator. +*/ +get_name :: proc(thread: ^Thread, allocator := context.allocator, loc := #caller_location) -> (string, runtime.Allocator_Error) #optional_allocator_error { + 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. + +MacOS: only support 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. diff --git a/core/thread/thread_name_darwin.odin b/core/thread/thread_name_darwin.odin new file mode 100644 index 000000000..866f608a3 --- /dev/null +++ b/core/thread/thread_name_darwin.odin @@ -0,0 +1,13 @@ +#+build darwin +#+private +package thread + +import "core:sys/posix" +import "core:c" + +foreign import pthread "system:System.framework" + +foreign pthread { + pthread_getname_np :: proc(thread: posix.pthread_t, name: [^]u8, len: c.size_t) -> posix.Errno --- + pthread_setname_np :: proc(name: [^]u8) -> posix.Errno --- +} diff --git a/core/thread/thread_name_freebsd.odin b/core/thread/thread_name_freebsd.odin new file mode 100644 index 000000000..9a36a54d2 --- /dev/null +++ b/core/thread/thread_name_freebsd.odin @@ -0,0 +1,13 @@ +#+build freebsd +#+private +package thread + +import "core:sys/posix" +import "core:c" + +foreign import pthread "system:pthread" + +foreign pthread { + pthread_getname_np :: proc(thread: posix.pthread_t, name: [^]u8, len: c.size_t) -> posix.Errno --- + pthread_setname_np :: proc(thread: posix.pthread_t, name: [^]u8) -> posix.Errno --- +} diff --git a/core/thread/thread_name_linux.odin b/core/thread/thread_name_linux.odin new file mode 100644 index 000000000..67d72e5c9 --- /dev/null +++ b/core/thread/thread_name_linux.odin @@ -0,0 +1,13 @@ +#+build linux +#+private +package thread + +import "core:sys/posix" +import "core:c" + +foreign import pthread "system:pthread" + +foreign pthread { + pthread_getname_np :: proc(thread: posix.pthread_t, name: [^]u8, len: c.size_t) -> posix.Errno --- + pthread_setname_np :: proc(thread: posix.pthread_t, name: [^]u8) -> posix.Errno --- +} diff --git a/core/thread/thread_name_netbsd.odin b/core/thread/thread_name_netbsd.odin new file mode 100644 index 000000000..ce350e5a4 --- /dev/null +++ b/core/thread/thread_name_netbsd.odin @@ -0,0 +1,13 @@ +#+build netbsd +#+private +package thread + +import "core:sys/posix" +import "core:c" + +foreign import pthread "system:pthread" + +foreign pthread { + pthread_getname_np :: proc(thread: posix.pthread_t, name: [^]u8, len: c.size_t) -> posix.Errno --- + pthread_setname_np :: proc(thread: posix.pthread_t, name: [^]u8, arg: rawptr) -> posix.Errno --- +} diff --git a/core/thread/thread_name_openbsd.odin b/core/thread/thread_name_openbsd.odin new file mode 100644 index 000000000..e91970649 --- /dev/null +++ b/core/thread/thread_name_openbsd.odin @@ -0,0 +1,13 @@ +#+build openbsd +#+private +package thread + +import "core:sys/posix" +import "core:c" + +foreign import pthread "system:pthread" + +foreign pthread { + pthread_get_name_np :: proc(thread: posix.pthread_t, name: [^]u8, len: c.size_t) --- + pthread_set_name_np :: proc(thread: posix.pthread_t, name: [^]u8) --- +} diff --git a/core/thread/thread_other.odin b/core/thread/thread_other.odin index dde2a8e48..d9fd9305e 100644 --- a/core/thread/thread_other.odin +++ b/core/thread/thread_other.odin @@ -2,6 +2,7 @@ package thread import "base:intrinsics" +import "base:runtime" _IS_SUPPORTED :: false @@ -45,3 +46,7 @@ _yield :: proc() { unimplemented("core:thread procedure not supported on target") } +_get_name :: proc(thread: Thread, allocator : runtime.Allocator, loc : runtime.Source_Code_Location) -> (string, runtime.Allocator_Error) { + unimplemented("core:thread procedure not supported on target") +} + diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 1431442a9..5c935bbe6 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -7,7 +7,7 @@ import "core:sync" import "core:sys/posix" _IS_SUPPORTED :: true - +_MAX_PTHREAD_NAME_LENGTH :: 16 // NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t. // Also see core/sys/darwin/mach_darwin.odin/semaphore_t. Thread_Os_Specific :: struct #align(16) { @@ -182,3 +182,57 @@ _terminate :: proc(t: ^Thread, exit_code: int) { _yield :: proc() { posix.sched_yield() } + +_get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.Source_Code_Location) -> (name:string, err:runtime.Allocator_Error) { + // Haiku doesn't have pthread_getname yet + when ODIN_OS == .Haiku { + unimplemented("core:thread get_name for haiku is not yet supported") + } + + tid : posix.pthread_t + if thread == nil do tid = transmute(posix.pthread_t)sync.current_thread_id() + else do tid = thread.unix_thread + + buf := make([]u8, _MAX_PTHREAD_NAME_LENGTH, allocator, loc) or_return + + when ODIN_OS == .Darwin || ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD { + pthread_getname_np(tid, raw_data(buf), len(buf)) + } else when ODIN_OS == .OpenBSD { + pthread_get_name_np(tid, raw_data(buf), len(buf)) + } + + name = transmute(string)buf + + 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 do return + } else { + tid: posix.pthread_t + if thread == nil do tid = transmute(posix.pthread_t)sync.current_thread_id + else do tid = t.unix_thread + } + + buf : [_MAX_PTHREAD_NAME_LENGTH]u8 + copy_from_string(buf[:], name) + + // _MAX_PTHREAD_NAME_LENGTH includes terminating null + buf[len(buf) - 1] = 0 + + when ODIN_OS == .Darwin { + pthread_setname_np(raw_data(buf[:])) + } else when ODIN_OS == .OpenBSD { + pthread_set_name_np(tid, raw_data(buf[:])) + } else when ODIN_OS == .NetBSD { + format := []u8{'%','s', 0} + pthread_setname_np(tid, raw_data(format), raw_data(buf[:])) + } else { + pthread_setname_np(tid, raw_data(buf[:])) + } + +} \ No newline at end of file diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 358e3e7f1..1609043dd 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -6,8 +6,11 @@ import "base:intrinsics" import "base:runtime" import "core:sync" import win32 "core:sys/windows" +import "core:unicode/utf16" _IS_SUPPORTED :: true +//NOTE(peperronii): not sure about the exact length but there must be a limit +_THREAD_DESCRIPTION_LENGTH :: 64 Thread_Os_Specific :: struct { win32_thread: win32.HANDLE, @@ -152,3 +155,33 @@ _yield :: proc() { win32.SwitchToThread() } +_get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc : runtime.Source_Code_Location) -> (name:string, err:runtime.Allocator_Error) { + t_handle : win32.HANDLE + if thread == nil do t_handle = win32.GetCurrentThread() + else do t_handle = t.win32_thread + + buf_8 : [_THREAD_DESCRIPTION_LENGTH * 2]u8 + buf_16 : [_THREAD_DESCRIPTION_LENGTH]u16 + win32.GetThreadDescription(t_handle, raw_data(buf_16[:])) + n := utf16.decode_to_utf(buf_8[:], buf_16[:]) + buf := make([]u8, n, allocator, loc) + + copy(buf, buf_8[:]) + + name = transmute(string)buf + + return +} + +_set_name :: proc(thread: ^Thread, name: string) { + t_handle : win32.HANDLE + if thread == nil do t_handle = win32.GetCurrentThread() + else do t_handle = t.win32_thread + + buf : [_THREAD_DESCRIPTION_LENGTH]u16 + utf16.encode_string(buf_16[:], name) + // _THREAD_DESCRIPTION_LENGTH includes terminating null + buf[len(buf) - 1] = 0 + win32.SetThreadDescription(t_handle, raw_data(buf[:])) +} + From b87b5431b1e59a465f98748a3816a056bfac35aa Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Mon, 14 Jul 2025 18:10:35 +0700 Subject: [PATCH 02/38] substitute 'do' --- core/thread/thread_unix.odin | 14 ++++++++++---- core/thread/thread_windows.odin | 14 ++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 5c935bbe6..285b1fee9 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -190,8 +190,11 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So } tid : posix.pthread_t - if thread == nil do tid = transmute(posix.pthread_t)sync.current_thread_id() - else do tid = thread.unix_thread + if thread == nil { + tid = transmute(posix.pthread_t)sync.current_thread_id() + } else { + tid = thread.unix_thread + } buf := make([]u8, _MAX_PTHREAD_NAME_LENGTH, allocator, loc) or_return @@ -214,8 +217,11 @@ _set_name :: proc(thread: ^Thread, name:string) { if thread != nil do return } else { tid: posix.pthread_t - if thread == nil do tid = transmute(posix.pthread_t)sync.current_thread_id - else do tid = t.unix_thread + if thread == nil { + tid = transmute(posix.pthread_t)sync.current_thread_id + } else { + tid = t.unix_thread + } } buf : [_MAX_PTHREAD_NAME_LENGTH]u8 diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 1609043dd..e73bb30c7 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -157,8 +157,11 @@ _yield :: proc() { _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc : runtime.Source_Code_Location) -> (name:string, err:runtime.Allocator_Error) { t_handle : win32.HANDLE - if thread == nil do t_handle = win32.GetCurrentThread() - else do t_handle = t.win32_thread + if thread == nil { + t_handle = win32.GetCurrentThread() + } else { + t_handle = t.win32_thread + } buf_8 : [_THREAD_DESCRIPTION_LENGTH * 2]u8 buf_16 : [_THREAD_DESCRIPTION_LENGTH]u16 @@ -175,8 +178,11 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc : runtime.S _set_name :: proc(thread: ^Thread, name: string) { t_handle : win32.HANDLE - if thread == nil do t_handle = win32.GetCurrentThread() - else do t_handle = t.win32_thread + if thread == nil { + t_handle = win32.GetCurrentThread() + } else { + t_handle = t.win32_thread + } buf : [_THREAD_DESCRIPTION_LENGTH]u16 utf16.encode_string(buf_16[:], name) From 6f3cc3168275a6797a6872894aa89acd02754709 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Mon, 14 Jul 2025 18:17:19 +0700 Subject: [PATCH 03/38] substitute sync.current_thread_id with posix.pthread_self for unix --- core/thread/thread_unix.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 285b1fee9..cadf7ba9a 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -191,7 +191,7 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So tid : posix.pthread_t if thread == nil { - tid = transmute(posix.pthread_t)sync.current_thread_id() + tid = posix.pthread_self() } else { tid = thread.unix_thread } @@ -218,7 +218,7 @@ _set_name :: proc(thread: ^Thread, name:string) { } else { tid: posix.pthread_t if thread == nil { - tid = transmute(posix.pthread_t)sync.current_thread_id + tid = posix.pthread_self() } else { tid = t.unix_thread } From 7265782ddcadc29aa0ad94a45a6e0c15d4731396 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Mon, 14 Jul 2025 20:39:52 +0700 Subject: [PATCH 04/38] remove unnecessary spaces, fix t -> thread, added more description --- core/thread/thread.odin | 7 +++++-- core/thread/thread_unix.odin | 6 +++--- core/thread/thread_windows.odin | 14 +++++++------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/core/thread/thread.odin b/core/thread/thread.odin index d4fb48862..ef207a015 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -167,11 +167,14 @@ get_name :: proc(thread: ^Thread, allocator := context.allocator, loc := #caller } /* -Set thread's name/description. +Set thread's name/description. If thread is nil the procedure will set the name of the calling thread. -MacOS: only support changing 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) { diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index cadf7ba9a..cc10c45d6 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -189,7 +189,7 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So unimplemented("core:thread get_name for haiku is not yet supported") } - tid : posix.pthread_t + tid: posix.pthread_t if thread == nil { tid = posix.pthread_self() } else { @@ -220,11 +220,11 @@ _set_name :: proc(thread: ^Thread, name:string) { if thread == nil { tid = posix.pthread_self() } else { - tid = t.unix_thread + tid = thread.unix_thread } } - buf : [_MAX_PTHREAD_NAME_LENGTH]u8 + buf: [_MAX_PTHREAD_NAME_LENGTH]u8 copy_from_string(buf[:], name) // _MAX_PTHREAD_NAME_LENGTH includes terminating null diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index e73bb30c7..f0e324f3e 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -156,15 +156,15 @@ _yield :: proc() { } _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc : runtime.Source_Code_Location) -> (name:string, err:runtime.Allocator_Error) { - t_handle : win32.HANDLE + t_handle: win32.HANDLE if thread == nil { t_handle = win32.GetCurrentThread() } else { - t_handle = t.win32_thread + t_handle = thread.win32_thread } - buf_8 : [_THREAD_DESCRIPTION_LENGTH * 2]u8 - buf_16 : [_THREAD_DESCRIPTION_LENGTH]u16 + buf_8: [_THREAD_DESCRIPTION_LENGTH * 2]u8 + buf_16: [_THREAD_DESCRIPTION_LENGTH]u16 win32.GetThreadDescription(t_handle, raw_data(buf_16[:])) n := utf16.decode_to_utf(buf_8[:], buf_16[:]) buf := make([]u8, n, allocator, loc) @@ -177,14 +177,14 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc : runtime.S } _set_name :: proc(thread: ^Thread, name: string) { - t_handle : win32.HANDLE + t_handle: win32.HANDLE if thread == nil { t_handle = win32.GetCurrentThread() } else { - t_handle = t.win32_thread + t_handle = thread.win32_thread } - buf : [_THREAD_DESCRIPTION_LENGTH]u16 + buf: [_THREAD_DESCRIPTION_LENGTH]u16 utf16.encode_string(buf_16[:], name) // _THREAD_DESCRIPTION_LENGTH includes terminating null buf[len(buf) - 1] = 0 From 8bc1ffd0dfc507cb22b326ecfcf215fb13a6ca04 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Mon, 14 Jul 2025 20:58:22 +0700 Subject: [PATCH 05/38] remove 'do' --- core/thread/thread_unix.odin | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index cc10c45d6..37df05046 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -214,7 +214,9 @@ _set_name :: proc(thread: ^Thread, name:string) { when ODIN_OS == .Haiku { unimplemented("core:thread set_name for haiku is not yet supported") } else when ODIN_OS == .Darwin { - if thread != nil do return + if thread != nil { + return + } } else { tid: posix.pthread_t if thread == nil { From c07830035e13a475022a900ab067e3f586af0cc5 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Mon, 14 Jul 2025 21:23:28 +0700 Subject: [PATCH 06/38] fix proc and variable typos --- core/thread/thread_windows.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index f0e324f3e..653a21e14 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -166,10 +166,10 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc : runtime.S buf_8: [_THREAD_DESCRIPTION_LENGTH * 2]u8 buf_16: [_THREAD_DESCRIPTION_LENGTH]u16 win32.GetThreadDescription(t_handle, raw_data(buf_16[:])) - n := utf16.decode_to_utf(buf_8[:], buf_16[:]) + n := utf16.decode_to_utf8(buf_8[:], buf_16[:]) buf := make([]u8, n, allocator, loc) - copy(buf, buf_8[:]) + copy(buf[:], buf_8[:]) name = transmute(string)buf @@ -185,7 +185,7 @@ _set_name :: proc(thread: ^Thread, name: string) { } buf: [_THREAD_DESCRIPTION_LENGTH]u16 - utf16.encode_string(buf_16[:], name) + utf16.encode_string(buf[:], name) // _THREAD_DESCRIPTION_LENGTH includes terminating null buf[len(buf) - 1] = 0 win32.SetThreadDescription(t_handle, raw_data(buf[:])) From 552b4b64fc33cd29124022767dbfbc2ade6a3527 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Mon, 14 Jul 2025 21:31:33 +0700 Subject: [PATCH 07/38] fix GetThreadDescription ^PCWSTR to PWSTR --- core/sys/windows/kernel32.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 76f2897ac..640afda30 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -168,7 +168,7 @@ foreign kernel32 { ResumeThread :: proc(thread: HANDLE) -> DWORD --- GetThreadPriority :: proc(thread: HANDLE) -> c_int --- SetThreadPriority :: proc(thread: HANDLE, priority: c_int) -> BOOL --- - GetThreadDescription :: proc(hThread: HANDLE, ppszThreadDescription: ^PCWSTR) -> HRESULT --- + GetThreadDescription :: proc(hThread: HANDLE, ppszThreadDescription: PWSTR) -> HRESULT --- SetThreadDescription :: proc(hThread: HANDLE, lpThreadDescription: PCWSTR) -> HRESULT --- GetExitCodeThread :: proc(thread: HANDLE, exit_code: ^DWORD) -> BOOL --- TerminateThread :: proc(thread: HANDLE, exit_code: DWORD) -> BOOL --- From d875d2d445307a01a6a25c70ee9bc7bef4d0e7a6 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Mon, 14 Jul 2025 21:43:28 +0700 Subject: [PATCH 08/38] added set_name in thread_other --- core/thread/thread_other.odin | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/thread/thread_other.odin b/core/thread/thread_other.odin index d9fd9305e..ef71fa086 100644 --- a/core/thread/thread_other.odin +++ b/core/thread/thread_other.odin @@ -46,7 +46,10 @@ _yield :: proc() { unimplemented("core:thread procedure not supported on target") } -_get_name :: proc(thread: Thread, allocator : runtime.Allocator, loc : runtime.Source_Code_Location) -> (string, runtime.Allocator_Error) { +_get_name :: proc(thread: ^Thread, allocator : runtime.Allocator, loc : runtime.Source_Code_Location) -> (string, runtime.Allocator_Error) { unimplemented("core:thread procedure not supported on target") } +_set_name :: proc(thread: ^Thread, name:string) { + unimplemented("core:thread procedure not supported on target") +} From 02111e75159c2d106f3364d46e4def614bbeb1fb Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" <145095511+peperronii@users.noreply.github.com> Date: Tue, 15 Jul 2025 09:28:38 +0700 Subject: [PATCH 09/38] no #optional_allocator_error Co-authored-by: Laytan --- core/thread/thread.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread.odin b/core/thread/thread.odin index ef207a015..6a5f78156 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -162,7 +162,7 @@ If thread is nil the procedure will get the name of the calling thread. allocates memory for the returned string using provided allocator. */ -get_name :: proc(thread: ^Thread, allocator := context.allocator, loc := #caller_location) -> (string, runtime.Allocator_Error) #optional_allocator_error { +get_name :: proc(thread: ^Thread, allocator := context.allocator, loc := #caller_location) -> (string, runtime.Allocator_Error) { return _get_name(thread, allocator, loc) } From 08c298808b13c3b513ddf6d87fefc48421715889 Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" <145095511+peperronii@users.noreply.github.com> Date: Tue, 15 Jul 2025 09:29:10 +0700 Subject: [PATCH 10/38] spacing Co-authored-by: Laytan --- core/thread/thread_unix.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 37df05046..bda59482d 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -183,7 +183,7 @@ _yield :: proc() { posix.sched_yield() } -_get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.Source_Code_Location) -> (name:string, err:runtime.Allocator_Error) { +_get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.Source_Code_Location) -> (name: string, err: runtime.Allocator_Error) { // Haiku doesn't have pthread_getname yet when ODIN_OS == .Haiku { unimplemented("core:thread get_name for haiku is not yet supported") From 05b769734b7534eed36138271d969f8477385b8d Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" <145095511+peperronii@users.noreply.github.com> Date: Tue, 15 Jul 2025 09:29:39 +0700 Subject: [PATCH 11/38] more spacing Co-authored-by: Laytan --- core/thread/thread_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 653a21e14..9281635e5 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -155,7 +155,7 @@ _yield :: proc() { win32.SwitchToThread() } -_get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc : runtime.Source_Code_Location) -> (name:string, err:runtime.Allocator_Error) { +_get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.Source_Code_Location) -> (name: string, err: runtime.Allocator_Error) { t_handle: win32.HANDLE if thread == nil { t_handle = win32.GetCurrentThread() From 5ffba9b222984dbb93282c3bdb54324eabad5f6f Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" <145095511+peperronii@users.noreply.github.com> Date: Tue, 15 Jul 2025 09:30:49 +0700 Subject: [PATCH 12/38] use copy proc group instead of copy_from_string Co-authored-by: Laytan --- core/thread/thread_unix.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index bda59482d..a9c07cf77 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -227,7 +227,7 @@ _set_name :: proc(thread: ^Thread, name:string) { } buf: [_MAX_PTHREAD_NAME_LENGTH]u8 - copy_from_string(buf[:], name) + copy(buf[:], name) // _MAX_PTHREAD_NAME_LENGTH includes terminating null buf[len(buf) - 1] = 0 From 805c3228b8a9e2714f26dbea235f05341d5c6566 Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" <145095511+peperronii@users.noreply.github.com> Date: Tue, 15 Jul 2025 09:32:02 +0700 Subject: [PATCH 13/38] Update core/thread/thread_unix.odin Co-authored-by: Laytan --- core/thread/thread_unix.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index a9c07cf77..46c58f6eb 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -209,7 +209,7 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So return } -_set_name :: proc(thread: ^Thread, name:string) { +_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") From 9aa4afe58533f2d7d0c1880fbab62c4f87db0509 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Tue, 15 Jul 2025 10:41:57 +0700 Subject: [PATCH 14/38] GetThreadDescription ^PWSTR --- core/sys/windows/kernel32.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 640afda30..dc7de26cd 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -168,7 +168,7 @@ foreign kernel32 { ResumeThread :: proc(thread: HANDLE) -> DWORD --- GetThreadPriority :: proc(thread: HANDLE) -> c_int --- SetThreadPriority :: proc(thread: HANDLE, priority: c_int) -> BOOL --- - GetThreadDescription :: proc(hThread: HANDLE, ppszThreadDescription: PWSTR) -> HRESULT --- + GetThreadDescription :: proc(hThread: HANDLE, ppszThreadDescription: ^PWSTR) -> HRESULT --- SetThreadDescription :: proc(hThread: HANDLE, lpThreadDescription: PCWSTR) -> HRESULT --- GetExitCodeThread :: proc(thread: HANDLE, exit_code: ^DWORD) -> BOOL --- TerminateThread :: proc(thread: HANDLE, exit_code: DWORD) -> BOOL --- From 8f81b8761a4a36bc0ef6ef57267b6636974ad752 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Tue, 15 Jul 2025 10:55:54 +0700 Subject: [PATCH 15/38] changed [^]u8 to cstring for netbsd, added truncate_to_byte(name,0) on name return --- core/thread/thread_name_netbsd.odin | 2 +- core/thread/thread_unix.odin | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/thread/thread_name_netbsd.odin b/core/thread/thread_name_netbsd.odin index ce350e5a4..12f31f760 100644 --- a/core/thread/thread_name_netbsd.odin +++ b/core/thread/thread_name_netbsd.odin @@ -9,5 +9,5 @@ foreign import pthread "system:pthread" foreign pthread { pthread_getname_np :: proc(thread: posix.pthread_t, name: [^]u8, len: c.size_t) -> posix.Errno --- - pthread_setname_np :: proc(thread: posix.pthread_t, name: [^]u8, arg: rawptr) -> posix.Errno --- + pthread_setname_np :: proc(thread: posix.pthread_t, name: cstring, arg: rawptr) -> posix.Errno --- } diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 46c58f6eb..80766fad6 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -5,6 +5,7 @@ package thread import "base:runtime" import "core:sync" import "core:sys/posix" +import "core:strings" _IS_SUPPORTED :: true _MAX_PTHREAD_NAME_LENGTH :: 16 @@ -205,7 +206,8 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So } name = transmute(string)buf - + name = strings.truncate_to_byte(name, 0) + return } @@ -237,8 +239,7 @@ _set_name :: proc(thread: ^Thread, name: string) { } else when ODIN_OS == .OpenBSD { pthread_set_name_np(tid, raw_data(buf[:])) } else when ODIN_OS == .NetBSD { - format := []u8{'%','s', 0} - pthread_setname_np(tid, raw_data(format), raw_data(buf[:])) + pthread_setname_np(tid, "%s", raw_data(buf[:])) } else { pthread_setname_np(tid, raw_data(buf[:])) } From 228e2752a3d04814531472d36917ef3bcf2bfa16 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Tue, 15 Jul 2025 12:29:26 +0700 Subject: [PATCH 16/38] use win32.wstring_to_utf8, default to temp_allocator, guarantees proper null termination --- core/thread/thread.odin | 2 +- core/thread/thread_windows.odin | 15 ++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/core/thread/thread.odin b/core/thread/thread.odin index 6a5f78156..56853a080 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -162,7 +162,7 @@ If thread is nil the procedure will get the name of the calling thread. allocates memory for the returned string using provided allocator. */ -get_name :: proc(thread: ^Thread, allocator := context.allocator, loc := #caller_location) -> (string, runtime.Allocator_Error) { +get_name :: proc(thread: ^Thread, allocator := context.temp_allocator, loc := #caller_location) -> (string, runtime.Allocator_Error) { return _get_name(thread, allocator, loc) } diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 9281635e5..ba1da9aa8 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -163,15 +163,9 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So t_handle = thread.win32_thread } - buf_8: [_THREAD_DESCRIPTION_LENGTH * 2]u8 - buf_16: [_THREAD_DESCRIPTION_LENGTH]u16 - win32.GetThreadDescription(t_handle, raw_data(buf_16[:])) - n := utf16.decode_to_utf8(buf_8[:], buf_16[:]) - buf := make([]u8, n, allocator, loc) - - copy(buf[:], buf_8[:]) - - name = transmute(string)buf + buf_16: win32.PWSTR + win32.GetThreadDescription(t_handle, &buf_16) + name = win32.wstring_to_utf8(buf_16, -1, allocator) or_return return } @@ -185,9 +179,8 @@ _set_name :: proc(thread: ^Thread, name: string) { } buf: [_THREAD_DESCRIPTION_LENGTH]u16 - utf16.encode_string(buf[:], name) // _THREAD_DESCRIPTION_LENGTH includes terminating null - buf[len(buf) - 1] = 0 + utf16.encode_string(buf[:len(buf) - 1], name) win32.SetThreadDescription(t_handle, raw_data(buf[:])) } From 8d278acba5b19cc8a42eebfe1ba38c677a6c5759 Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" <145095511+peperronii@users.noreply.github.com> Date: Tue, 15 Jul 2025 12:51:48 +0700 Subject: [PATCH 17/38] fix system:System.Framework pthread.odin --- core/sys/posix/pthread.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/posix/pthread.odin b/core/sys/posix/pthread.odin index 44b0c91d7..ae4264e49 100644 --- a/core/sys/posix/pthread.odin +++ b/core/sys/posix/pthread.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .Linux || ODIN_OS == .OpenBSD { foreign import lib "system:pthread" } else { From a3571136516c19caf13ccc5f0cb5529ee8fe749b Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Tue, 22 Jul 2025 10:52:29 +0700 Subject: [PATCH 18/38] 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) From 3c9d05a8c62b6d82fec65c4628b058a31646fca4 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Tue, 22 Jul 2025 11:00:49 +0700 Subject: [PATCH 19/38] fix tid/handle bug on macos/win --- core/thread/thread_unix.odin | 4 +++- core/thread/thread_windows.odin | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index c723c434e..7491ec457 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -223,7 +223,9 @@ _set_name :: proc(thread: ^Thread) { return } - tid := thread.unix_thread + when ODIN_OS != .Darwin { + 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 bd586ed49..e535b1adf 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -179,7 +179,7 @@ _set_name :: proc(thread: ^Thread) { return } - t_handle = thread.win32_thread + t_handle := thread.win32_thread buf: [_THREAD_DESCRIPTION_LENGTH]u16 // _THREAD_DESCRIPTION_LENGTH includes terminating null From 2f770ff241303637661af6a621d9f10004d846ed Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Tue, 22 Jul 2025 11:18:45 +0700 Subject: [PATCH 20/38] check for Haiku before calling _set_name --- core/thread/thread_unix.odin | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 7491ec457..6a0a1fcfd 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -58,7 +58,9 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority, name: Maybe(s runtime.run_thread_local_cleaners() } - _set_name(t) + when ODIN_OS != .Haiku { + _set_name(t) + } t.procedure(t) } @@ -214,10 +216,6 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So } _set_name :: proc(thread: ^Thread) { - if ODIN_OS == .Haiku { - return - } - name, ok := thread.name.? if !ok { return From c1643326619d6598467b2fbc06feee86a49f057a Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" Date: Wed, 20 Aug 2025 07:10:19 +0700 Subject: [PATCH 21/38] Apply suggestions from code review Improve code description Co-authored-by: Sunagatov Denis --- core/thread/thread.odin | 4 +++- core/thread/thread_other.odin | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/thread/thread.odin b/core/thread/thread.odin index d4a27de13..c0174636a 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -161,7 +161,9 @@ yield :: proc() { /* Get thread's name/description. -If thread is nil the procedure will get the name of the calling thread. +This procedure returns the name of the given thread. If `thread` is `nil`, this procedure returns the name of the calling thread. + +**Note(linux, bsd)**: Because the thread name is stored in as the `cmdline`, if the thread name was not set, the command that has been used to create the process as the name of the thread. allocates memory for the returned string using provided allocator. */ diff --git a/core/thread/thread_other.odin b/core/thread/thread_other.odin index 83ea31fe1..1bdc11a4e 100644 --- a/core/thread/thread_other.odin +++ b/core/thread/thread_other.odin @@ -47,9 +47,9 @@ _yield :: proc() { } _get_name :: proc(thread: ^Thread, allocator : runtime.Allocator, loc : runtime.Source_Code_Location) -> (string, runtime.Allocator_Error) { - unimplemented("core:thread procedure not supported on target") + unimplemented("core:thread procedure not supported on this target") } _set_name :: proc(thread: ^Thread, name:string) { - unimplemented("core:thread procedure not supported on target") + unimplemented("core:thread procedure not supported on this target") } From 8884ad01f5188b1297ddd7eba0f4a0ff9795ab56 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Wed, 20 Aug 2025 21:00:25 +0700 Subject: [PATCH 22/38] added name argument description --- core/thread/thread.odin | 42 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/core/thread/thread.odin b/core/thread/thread.odin index c0174636a..53f9b3f62 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -104,7 +104,11 @@ 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. + +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. */ + create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal, name: Maybe(string) = nil) -> ^Thread { return _create(procedure, priority, name) } @@ -178,6 +182,9 @@ This procedure runs the given procedure on another thread. The context specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. @@ -193,6 +200,9 @@ This procedure runs the given procedure on another thread. The context specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. @@ -208,6 +218,9 @@ This procedure runs the given procedure on another thread. The context specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. @@ -224,6 +237,9 @@ This procedure runs the given procedure on another thread. The context specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. @@ -240,6 +256,9 @@ This procedure runs the given procedure on another thread. The context specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. @@ -256,6 +275,9 @@ This procedure runs the given procedure on another thread. The context specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. @@ -276,6 +298,9 @@ If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be automatically freed. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -311,6 +336,9 @@ If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be automatically freed. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -350,6 +378,9 @@ If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be automatically freed. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -395,6 +426,9 @@ If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be automatically freed. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -446,6 +480,9 @@ If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be automatically freed. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -499,6 +536,9 @@ If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be automatically freed. +Optionally specify the thread's name/description. +the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. + **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -572,4 +612,4 @@ _maybe_destroy_default_temp_allocator :: proc(init_context: Maybe(runtime.Contex if context.temp_allocator.procedure == runtime.default_temp_allocator_proc { runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data) } -} \ No newline at end of file +} From 5ab3c1794e976914e48c25ad2e1c493db229bb30 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Wed, 20 Aug 2025 21:51:56 +0700 Subject: [PATCH 23/38] fixed windows api and free GetThreadName's allocation --- core/thread/thread_windows.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index e535b1adf..a0320890b 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -169,6 +169,7 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So buf_16: win32.PWSTR win32.GetThreadDescription(t_handle, &buf_16) name = win32.wstring_to_utf8(buf_16, -1, allocator) or_return + win32.LocalFree(rawptr(buf_16)) return } From e4cc58d992959e5844aeff63ce845a8db94ed4a8 Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Thu, 28 Aug 2025 09:50:25 +0700 Subject: [PATCH 24/38] thread.name = name in unix --- core/thread/thread_unix.odin | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index ab7ee9a0e..218535e56 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -58,9 +58,7 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority, name: Maybe(s runtime.run_thread_local_cleaners() } - when ODIN_OS != .Haiku { - _set_name(t) - } + _set_name(t) t.procedure(t) } @@ -130,6 +128,9 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority, name: Maybe(s free(thread, thread.creation_allocator) return nil } + + thread.name = name + return thread } @@ -246,4 +247,4 @@ _set_name :: proc(thread: ^Thread) { pthread_setname_np(tid, raw_data(buf[:])) } -} \ No newline at end of file +} From 704a917355599494eec7cbf9791a5673a890e5a3 Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" Date: Thu, 28 Aug 2025 09:53:53 +0700 Subject: [PATCH 25/38] re-added Haiku os _set_name guard --- core/thread/thread_unix.odin | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 218535e56..8a3aa4152 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -58,7 +58,9 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority, name: Maybe(s runtime.run_thread_local_cleaners() } - _set_name(t) + when ODIN_OS != .Haiku { + _set_name(t) + } t.procedure(t) } From ed75ab49bbbf6e3aa0f7b0aa979c5eaebaf575b3 Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" Date: Sun, 14 Sep 2025 13:57:49 +0700 Subject: [PATCH 26/38] Change windows Thread_Description_Length to 128 --- core/thread/thread_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index a0320890b..2f5d19b2e 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -10,7 +10,7 @@ import "core:unicode/utf16" _IS_SUPPORTED :: true //NOTE(peperronii): not sure about the exact length but there must be a limit -_THREAD_DESCRIPTION_LENGTH :: 64 +_THREAD_DESCRIPTION_LENGTH :: 128 Thread_Os_Specific :: struct { win32_thread: win32.HANDLE, From f873231f2efb85d6f0875792acd67dda78840997 Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" Date: Thu, 20 Nov 2025 19:18:55 +0700 Subject: [PATCH 27/38] Update thread name/description truncation limits --- core/thread/thread.odin | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/core/thread/thread.odin b/core/thread/thread.odin index 53f9b3f62..d32e6ed41 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -106,7 +106,7 @@ To start the thread, call `start()`. Also the `create_and_start()` procedure can be called to create and start the thread immediately. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. */ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal, name: Maybe(string) = nil) -> ^Thread { @@ -183,7 +183,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -201,7 +201,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -219,7 +219,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -238,7 +238,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -257,7 +257,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -276,7 +276,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -299,7 +299,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -337,7 +337,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -379,7 +379,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -427,7 +427,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -481,7 +481,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -537,7 +537,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 63 bytes on Windows. +the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. From f736047df437d6fd38292e66fff8e0904895dc2b Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" Date: Sun, 7 Dec 2025 22:09:49 +0700 Subject: [PATCH 28/38] Make compatible with the new win32.SetThreadDescription The second argument is changed to a cstring16. --- core/thread/thread_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 2f5d19b2e..b8fd2bc48 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -185,6 +185,6 @@ _set_name :: proc(thread: ^Thread) { buf: [_THREAD_DESCRIPTION_LENGTH]u16 // _THREAD_DESCRIPTION_LENGTH includes terminating null utf16.encode_string(buf[:len(buf) - 1], name) - win32.SetThreadDescription(t_handle, raw_data(buf[:])) + win32.SetThreadDescription(t_handle, cstring16(buf)) } From 9529ebf8b7128b961a6bae8fe63edb0d30d79be9 Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" Date: Sun, 7 Dec 2025 22:52:03 +0700 Subject: [PATCH 29/38] forgot to add raw_data --- core/thread/thread_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index b8fd2bc48..b797c059c 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -185,6 +185,6 @@ _set_name :: proc(thread: ^Thread) { buf: [_THREAD_DESCRIPTION_LENGTH]u16 // _THREAD_DESCRIPTION_LENGTH includes terminating null utf16.encode_string(buf[:len(buf) - 1], name) - win32.SetThreadDescription(t_handle, cstring16(buf)) + win32.SetThreadDescription(t_handle, cstring16(raw_data(buf[:]))) } From c9064cf532d3523ca9fa64aca0af0fe1bd362edf Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Mon, 23 Mar 2026 22:51:16 +0700 Subject: [PATCH 30/38] more concise null termination --- core/thread/thread_unix.odin | 4 ++-- core/thread/thread_windows.odin | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 8b08d8c19..dc1d13020 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -231,10 +231,10 @@ _set_name :: proc(thread: ^Thread) { } buf: [_MAX_PTHREAD_NAME_LENGTH]u8 - copy(buf[:], name) // _MAX_PTHREAD_NAME_LENGTH includes terminating null - buf[len(buf) - 1] = 0 + copy(buf[:len(buf) - 1], name) + when ODIN_OS == .Darwin { pthread_setname_np(raw_data(buf[:])) diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index b797c059c..4695a5b84 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -167,9 +167,13 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So } buf_16: win32.PWSTR - win32.GetThreadDescription(t_handle, &buf_16) + + hr := win32.GetThreadDescription(t_handle, buf_16) + defer if win32.SUCCEEDED(hr) { + win32.LocalFree(rawptr(buf_16)) + } + name = win32.wstring_to_utf8(buf_16, -1, allocator) or_return - win32.LocalFree(rawptr(buf_16)) return } From d83d47b19d5bed31d907e630fa1f8a00d1a5937c Mon Sep 17 00:00:00 2001 From: PePerRoNii Date: Wed, 25 Mar 2026 09:10:58 +0700 Subject: [PATCH 31/38] more sensible allocation and fix comment --- core/thread/thread.odin | 3 ++- core/thread/thread_unix.odin | 10 ++++------ core/thread/thread_windows.odin | 13 ++++++------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/core/thread/thread.odin b/core/thread/thread.odin index 859b6597a..e5b4908e7 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -170,8 +170,9 @@ yield :: proc() { Get thread's name/description. This procedure returns the name of the given thread. If `thread` is `nil`, this procedure returns the name of the calling thread. +OS level errors are silently ignored. -**Note(linux, bsd)**: Because the thread name is stored in as the `cmdline`, if the thread name was not set, the command that has been used to create the process as the name of the thread. +**Note(linux, bsd)**: Because the thread name is stored in as the `cmdline`, if the thread name was not set, the command that has been used to create the process will be used as the name of the thread. allocates memory for the returned string using provided allocator. */ diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index dc1d13020..13b6fa264 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -206,17 +206,15 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So tid = thread.unix_thread } - buf := make([]u8, _MAX_PTHREAD_NAME_LENGTH, allocator, loc) or_return + buf : [_MAX_PTHREAD_NAME_LENGTH]u8 when ODIN_OS == .Darwin || ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD { - pthread_getname_np(tid, raw_data(buf), len(buf)) + pthread_getname_np(tid, raw_data(buf[:]), len(buf)) } else when ODIN_OS == .OpenBSD { - pthread_get_name_np(tid, raw_data(buf), len(buf)) + pthread_get_name_np(tid, raw_data(buf[:]), len(buf)) } - name = transmute(string)buf - name = strings.truncate_to_byte(name, 0) - + name, err = strings.clone_from_cstring(cstring(raw_data(buf[:])), allocator, loc) return } diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 4695a5b84..0b5824f64 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -166,15 +166,14 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So t_handle = thread.win32_thread } - buf_16: win32.PWSTR + buf: win32.PWSTR - hr := win32.GetThreadDescription(t_handle, buf_16) - defer if win32.SUCCEEDED(hr) { - win32.LocalFree(rawptr(buf_16)) + hr := win32.GetThreadDescription(t_handle, &buf) + + if win32.SUCCEEDED(hr) { + defer win32.LocalFree(rawptr(buf)) + name, err = win32.wstring_to_utf8(buf, -1, allocator) } - - name = win32.wstring_to_utf8(buf_16, -1, allocator) or_return - return } From 0b5d3b0dd849450f800995fa5c7d2ac0f77ae9f2 Mon Sep 17 00:00:00 2001 From: Wachiraphol Yingamphol Date: Mon, 6 Apr 2026 10:01:34 +0700 Subject: [PATCH 32/38] nil as default thread arg --- core/thread/thread.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/thread/thread.odin b/core/thread/thread.odin index e5b4908e7..a81fb3fba 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -176,7 +176,7 @@ OS level errors are silently ignored. allocates memory for the returned string using provided allocator. */ -get_name :: proc(thread: ^Thread, allocator := context.temp_allocator, loc := #caller_location) -> (string, runtime.Allocator_Error) { +get_name :: proc(thread: ^Thread = nil, allocator := context.temp_allocator, loc := #caller_location) -> (string, runtime.Allocator_Error) { return _get_name(thread, allocator, loc) } From 99442fa39034d5a3b4e10464e0284ac6f169371b Mon Sep 17 00:00:00 2001 From: Wachiraphol Yingamphol Date: Mon, 6 Apr 2026 15:06:02 +0700 Subject: [PATCH 33/38] add proper test for thread names --- tests/core/thread/test_core_thread.odin | 38 ++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/tests/core/thread/test_core_thread.odin b/tests/core/thread/test_core_thread.odin index 0b77ad511..87c3be942 100644 --- a/tests/core/thread/test_core_thread.odin +++ b/tests/core/thread/test_core_thread.odin @@ -49,4 +49,40 @@ poly_data_test :: proc(_t: ^testing.T) { defer free(t4) thread.join_multiple(t1, t2, t3, t4) -} \ No newline at end of file +} + +@(test) +name_test :: proc(_t: ^testing.T) { + @static name_test_t: ^testing.T + @static main_wait := true + @static child_wait := true + name_test_t = _t + + t := thread.create_and_start(name = "test_name", fn = proc() { + main_wait = false + + for (child_wait) {} + + n, err := thread.get_name() + defer if err != nil { + delete(n) + } + testing.expect(name_test_t, err == nil, "thread name allocation failed") + testing.expect(name_test_t, n == "test_name","thread name on self did not match") + + }) + defer free(t) + + for (main_wait) {} + + n, err := thread.get_name(t) + defer if err != nil { + delete(n) + } + testing.expect(name_test_t, err == nil, "thread name allocation failed") + testing.expect(name_test_t, n == "test_name","thread name on main did not match") + + child_wait = false + + thread.join(t) +} From ece54a4d05ba00ec482c1db0a24eb99d622cef4d Mon Sep 17 00:00:00 2001 From: "WP. Yingamphol" Date: Tue, 7 Apr 2026 12:56:42 +0700 Subject: [PATCH 34/38] moved Haiku OS check inside _set_name --- core/thread/thread_unix.odin | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 13b6fa264..2720808fa 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -51,9 +51,7 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority, name: Maybe(s runtime.run_thread_local_cleaners() } - when ODIN_OS != .Haiku { - _set_name(t) - } + _set_name(t) t.procedure(t) } @@ -219,6 +217,10 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So } _set_name :: proc(thread: ^Thread) { + when ODIN_OS == .Haiku { + return + } + name, ok := thread.name.? if !ok { return From ecd8b89daf7a4cf6912cc89327127f7e73896e2f Mon Sep 17 00:00:00 2001 From: Pung Date: Fri, 1 May 2026 13:12:48 +0700 Subject: [PATCH 35/38] better error message --- tests/core/thread/test_core_thread.odin | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/core/thread/test_core_thread.odin b/tests/core/thread/test_core_thread.odin index 87c3be942..0c7d956e4 100644 --- a/tests/core/thread/test_core_thread.odin +++ b/tests/core/thread/test_core_thread.odin @@ -3,6 +3,7 @@ package test_core_thread import "core:testing" import "core:thread" import "base:intrinsics" +import "core:fmt" @(test) poly_data_test :: proc(_t: ^testing.T) { @@ -68,7 +69,7 @@ name_test :: proc(_t: ^testing.T) { delete(n) } testing.expect(name_test_t, err == nil, "thread name allocation failed") - testing.expect(name_test_t, n == "test_name","thread name on self did not match") + testing.expectf(name_test_t, n == "test_name","thread name on self did not match : got %v", n) }) defer free(t) @@ -80,7 +81,7 @@ name_test :: proc(_t: ^testing.T) { delete(n) } testing.expect(name_test_t, err == nil, "thread name allocation failed") - testing.expect(name_test_t, n == "test_name","thread name on main did not match") + testing.expectf(name_test_t, n == "test_name","thread name on main did not match : got %v", n) child_wait = false From 7005cf7cf05a41cd68208ad4829d645f6012f2cc Mon Sep 17 00:00:00 2001 From: Pung Date: Fri, 1 May 2026 13:13:23 +0700 Subject: [PATCH 36/38] update OS limit to its proper value --- core/thread/thread.odin | 27 ++++++++++++++------------- core/thread/thread_name_darwin.odin | 2 ++ core/thread/thread_name_freebsd.odin | 2 ++ core/thread/thread_name_linux.odin | 2 ++ core/thread/thread_name_netbsd.odin | 2 ++ core/thread/thread_name_openbsd.odin | 2 ++ core/thread/thread_unix.odin | 8 +++----- core/thread/thread_windows.odin | 9 ++++++--- 8 files changed, 33 insertions(+), 21 deletions(-) diff --git a/core/thread/thread.odin b/core/thread/thread.odin index a81fb3fba..14e266b20 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -53,6 +53,7 @@ Thread :: struct { // it is started. data: rawptr, // Thread's Name/Description that will get set during thread creation + // it will be set using init_context's allocator to allocate and free a cstring buffer // 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 @@ -110,7 +111,7 @@ To start the thread, call `start()`. Also the `create_and_start()` procedure can be called to create and start the thread immediately. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. */ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal, name: Maybe(string) = nil) -> ^Thread { @@ -188,7 +189,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -206,7 +207,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -224,7 +225,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -243,7 +244,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -262,7 +263,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -281,7 +282,7 @@ specified by `init_context` will be used as the context in which `fn` is going to execute. The thread will have priority specified by the `priority` parameter. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` @@ -304,7 +305,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -342,7 +343,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -384,7 +385,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -432,7 +433,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -486,7 +487,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. @@ -542,7 +543,7 @@ If `self_cleanup` is specified, after the thread finishes the execution of the automatically freed. Optionally specify the thread's name/description. -the name/description will be truncated to 15 bytes on Unix and 127 bytes on Windows. +the name/description will be truncated to fit the OS's limit. **Do not** dereference the `^Thread` pointer, if this flag is specified. That includes calling `join`, which needs to dereference ^Thread`. diff --git a/core/thread/thread_name_darwin.odin b/core/thread/thread_name_darwin.odin index 866f608a3..7a01e0371 100644 --- a/core/thread/thread_name_darwin.odin +++ b/core/thread/thread_name_darwin.odin @@ -5,6 +5,8 @@ package thread import "core:sys/posix" import "core:c" +_MAX_PTHREAD_NAME_LENGTH :: 64 + foreign import pthread "system:System.framework" foreign pthread { diff --git a/core/thread/thread_name_freebsd.odin b/core/thread/thread_name_freebsd.odin index 9a36a54d2..5b79728a2 100644 --- a/core/thread/thread_name_freebsd.odin +++ b/core/thread/thread_name_freebsd.odin @@ -5,6 +5,8 @@ package thread import "core:sys/posix" import "core:c" +_MAX_PTHREAD_NAME_LENGTH :: 20 + foreign import pthread "system:pthread" foreign pthread { diff --git a/core/thread/thread_name_linux.odin b/core/thread/thread_name_linux.odin index 67d72e5c9..b84bf999c 100644 --- a/core/thread/thread_name_linux.odin +++ b/core/thread/thread_name_linux.odin @@ -5,6 +5,8 @@ package thread import "core:sys/posix" import "core:c" +_MAX_PTHREAD_NAME_LENGTH :: 16 + foreign import pthread "system:pthread" foreign pthread { diff --git a/core/thread/thread_name_netbsd.odin b/core/thread/thread_name_netbsd.odin index 12f31f760..c62c8c8f4 100644 --- a/core/thread/thread_name_netbsd.odin +++ b/core/thread/thread_name_netbsd.odin @@ -5,6 +5,8 @@ package thread import "core:sys/posix" import "core:c" +_MAX_PTHREAD_NAME_LENGTH :: 32 + foreign import pthread "system:pthread" foreign pthread { diff --git a/core/thread/thread_name_openbsd.odin b/core/thread/thread_name_openbsd.odin index e91970649..b349c2566 100644 --- a/core/thread/thread_name_openbsd.odin +++ b/core/thread/thread_name_openbsd.odin @@ -7,6 +7,8 @@ import "core:c" foreign import pthread "system:pthread" +_MAX_PTHREAD_NAME_LENGTH :: 20 + foreign pthread { pthread_get_name_np :: proc(thread: posix.pthread_t, name: [^]u8, len: c.size_t) --- pthread_set_name_np :: proc(thread: posix.pthread_t, name: [^]u8) --- diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 2720808fa..0ab54cea2 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -8,7 +8,6 @@ import "core:sys/posix" import "core:strings" _IS_SUPPORTED :: true -_MAX_PTHREAD_NAME_LENGTH :: 16 // NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t. // Also see core/sys/darwin/mach_darwin.odin/semaphore_t. Thread_Os_Specific :: struct #align(16) { @@ -230,12 +229,12 @@ _set_name :: proc(thread: ^Thread) { tid := thread.unix_thread } - buf: [_MAX_PTHREAD_NAME_LENGTH]u8 - // _MAX_PTHREAD_NAME_LENGTH includes terminating null + buflen := len(name) + 1 < _MAX_PTHREAD_NAME_LENGTH ? len(name) + 1 : _MAX_PTHREAD_NAME_LENGTH + buf := make([]u8, buflen) + defer delete(buf) copy(buf[:len(buf) - 1], name) - when ODIN_OS == .Darwin { pthread_setname_np(raw_data(buf[:])) } else when ODIN_OS == .OpenBSD { @@ -245,5 +244,4 @@ _set_name :: proc(thread: ^Thread) { } else { pthread_setname_np(tid, raw_data(buf[:])) } - } diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 0b5824f64..f13d550f7 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -9,8 +9,9 @@ import win32 "core:sys/windows" import "core:unicode/utf16" _IS_SUPPORTED :: true -//NOTE(peperronii): not sure about the exact length but there must be a limit -_THREAD_DESCRIPTION_LENGTH :: 128 + +//NOTE(peperronii): this is the system limit for windows api call, not specific to thread description +_THREAD_DESCRIPTION_LENGTH :: 32_767 Thread_Os_Specific :: struct { win32_thread: win32.HANDLE, @@ -185,8 +186,10 @@ _set_name :: proc(thread: ^Thread) { t_handle := thread.win32_thread - buf: [_THREAD_DESCRIPTION_LENGTH]u16 // _THREAD_DESCRIPTION_LENGTH includes terminating null + buflen := len(name) + 1 < _THREAD_DESCRIPTION_LENGTH ? len(name) + 1 : _THREAD_DESCRIPTION_LENGTH + buf := make([]u16, buflen) + defer delete(buf) utf16.encode_string(buf[:len(buf) - 1], name) win32.SetThreadDescription(t_handle, cstring16(raw_data(buf[:]))) } From 6a01e3fbf97dde95c33ada21b2e04e57b690d533 Mon Sep 17 00:00:00 2001 From: Pung Date: Fri, 1 May 2026 13:41:13 +0700 Subject: [PATCH 37/38] removed unused fmt --- tests/core/thread/test_core_thread.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/core/thread/test_core_thread.odin b/tests/core/thread/test_core_thread.odin index 0c7d956e4..e06fcc3cf 100644 --- a/tests/core/thread/test_core_thread.odin +++ b/tests/core/thread/test_core_thread.odin @@ -3,7 +3,6 @@ package test_core_thread import "core:testing" import "core:thread" import "base:intrinsics" -import "core:fmt" @(test) poly_data_test :: proc(_t: ^testing.T) { From 2e5af1a40c36b559036d631bdeeac7622b337db6 Mon Sep 17 00:00:00 2001 From: peperronii Date: Fri, 17 Jul 2026 23:17:23 +0700 Subject: [PATCH 38/38] Removed Haiku --- core/thread/thread_unix.odin | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 70a534db5..fef0db9f8 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -191,11 +191,6 @@ _yield :: proc() { } _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.Source_Code_Location) -> (name: string, err: runtime.Allocator_Error) { - // Haiku doesn't have pthread_getname yet - when ODIN_OS == .Haiku { - unimplemented("core:thread get_name for haiku is not yet supported") - } - tid: posix.pthread_t if thread == nil { tid = posix.pthread_self() @@ -205,10 +200,10 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So buf : [_MAX_PTHREAD_NAME_LENGTH]u8 - when ODIN_OS == .Darwin || ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD { - pthread_getname_np(tid, raw_data(buf[:]), len(buf)) - } else when ODIN_OS == .OpenBSD { + when ODIN_OS == .OpenBSD { pthread_get_name_np(tid, raw_data(buf[:]), len(buf)) + } else { + pthread_getname_np(tid, raw_data(buf[:]), len(buf)) } name, err = strings.clone_from_cstring(cstring(raw_data(buf[:])), allocator, loc) @@ -216,10 +211,6 @@ _get_name :: proc(thread: ^Thread, allocator: runtime.Allocator, loc: runtime.So } _set_name :: proc(thread: ^Thread) { - when ODIN_OS == .Haiku { - return - } - name, ok := thread.name.? if !ok { return