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[:])) +} +