Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0a3f730
Get/Set Thread names
peperronii Jul 14, 2025
b87b543
substitute 'do'
peperronii Jul 14, 2025
6f3cc31
substitute sync.current_thread_id with posix.pthread_self for unix
peperronii Jul 14, 2025
7265782
remove unnecessary spaces, fix t -> thread, added more description
peperronii Jul 14, 2025
8bc1ffd
remove 'do'
peperronii Jul 14, 2025
c078300
fix proc and variable typos
peperronii Jul 14, 2025
552b4b6
fix GetThreadDescription ^PCWSTR to PWSTR
peperronii Jul 14, 2025
d875d2d
added set_name in thread_other
peperronii Jul 14, 2025
02111e7
no #optional_allocator_error
peperronii Jul 15, 2025
08c2988
spacing
peperronii Jul 15, 2025
05b7697
more spacing
peperronii Jul 15, 2025
5ffba9b
use copy proc group instead of copy_from_string
peperronii Jul 15, 2025
805c322
Update core/thread/thread_unix.odin
peperronii Jul 15, 2025
9aa4afe
GetThreadDescription ^PWSTR
peperronii Jul 15, 2025
8f81b87
changed [^]u8 to cstring for netbsd, added truncate_to_byte(name,0) o…
peperronii Jul 15, 2025
228e275
use win32.wstring_to_utf8, default to temp_allocator, guarantees prop…
peperronii Jul 15, 2025
ea20383
Merge branch 'master' into master
peperronii Jul 15, 2025
8d278ac
fix system:System.Framework pthread.odin
peperronii Jul 15, 2025
a357113
thread.create et al with name parameter
peperronii Jul 22, 2025
3c9d05a
fix tid/handle bug on macos/win
peperronii Jul 22, 2025
2f770ff
check for Haiku before calling _set_name
peperronii Jul 22, 2025
c164332
Apply suggestions from code review
peperronii Aug 20, 2025
155c03a
Merge branch 'odin-lang:master' into master
peperronii Aug 20, 2025
8884ad0
added name argument description
peperronii Aug 20, 2025
5ab3c17
fixed windows api and free GetThreadName's allocation
peperronii Aug 20, 2025
e4cc58d
thread.name = name in unix
peperronii Aug 28, 2025
704a917
re-added Haiku os _set_name guard
peperronii Aug 28, 2025
ed75ab4
Change windows Thread_Description_Length to 128
peperronii Sep 14, 2025
f873231
Update thread name/description truncation limits
peperronii Nov 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/sys/posix/pthread.odin
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "core:c"

when ODIN_OS == .Darwin {
foreign import lib "system:System"
} 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"
Expand Down
2 changes: 1 addition & 1 deletion core/sys/windows/kernel32.odin
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I’m not sure about this API call. per documentation it might be ^PWSTR but that doesn’t make sense cause it’s a pointer to a pointer.

Copy link
Contributor

@blob1807 blob1807 Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a pointer to a pointer because it's writing the buffer's pointer at the one we give it. It doesn't copy the whole buffer back to you. It just returns a pointer to it.

Copy link
Contributor Author

@peperronii peperronii Jul 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to still manually allocate a buffer for the entire string or we’ll be fine just using the pointer?
edit:I forgot that we’d have to allocate for the returned string anyway, but I’m still curious how it will manage the buffer after the call.

Original file line number Diff line number Diff line change
Expand Up @@ -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 ---
Expand Down
110 changes: 83 additions & 27 deletions core/thread/thread.odin

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions core/thread/thread_name_darwin.odin
Original file line number Diff line number Diff line change
@@ -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 ---
}
13 changes: 13 additions & 0 deletions core/thread/thread_name_freebsd.odin
Original file line number Diff line number Diff line change
@@ -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 ---
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating 5 files for each of the platforms, I think you should just add these bindings to sys/posix/pthread.odin. They don't seem to be platform specific and there's no point in duplicating the files when you can bind these procedures in one place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. it is actually platform specific, the input arguments for the foreign functions are not the same. I actually wanted to put it in the same file but I’m not sure if we can do something like a WHEN ODIN_OS == .smth inside a foreign block though, so I went with this.

  2. These functions are not listed in the POSIX standard. I’ve been informed that the core:sys/posix adheres to it very strictly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, then it's good. I'm not familiar with posix much, I assumed it would have been part of pthreads

pthread_setname_np :: proc(thread: posix.pthread_t, name: [^]u8) -> posix.Errno ---
}
13 changes: 13 additions & 0 deletions core/thread/thread_name_linux.odin
Original file line number Diff line number Diff line change
@@ -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 ---
}
13 changes: 13 additions & 0 deletions core/thread/thread_name_netbsd.odin
Original file line number Diff line number Diff line change
@@ -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: cstring, arg: rawptr) -> posix.Errno ---
}
13 changes: 13 additions & 0 deletions core/thread/thread_name_openbsd.odin
Original file line number Diff line number Diff line change
@@ -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) ---
}
10 changes: 9 additions & 1 deletion core/thread/thread_other.odin
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package thread

import "base:intrinsics"
import "base:runtime"

_IS_SUPPORTED :: false

Expand All @@ -13,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")
}

Expand Down Expand Up @@ -45,3 +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) {
unimplemented("core:thread procedure not supported on this target")
}

_set_name :: proc(thread: ^Thread, name:string) {
unimplemented("core:thread procedure not supported on this target")
}
67 changes: 65 additions & 2 deletions core/thread/thread_unix.odin
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ package thread
import "base:runtime"
import "core:sync"
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) {
Expand All @@ -18,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)

Expand Down Expand Up @@ -57,6 +58,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
runtime.run_thread_local_cleaners()
}

when ODIN_OS != .Haiku {
_set_name(t)
}

t.procedure(t)
}

Expand Down Expand Up @@ -125,6 +130,9 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
free(thread, thread.creation_allocator)
return nil
}

thread.name = name

return thread
}

Expand Down Expand Up @@ -187,3 +195,58 @@ _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 {
tid = posix.pthread_self()
} else {
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
name = strings.truncate_to_byte(name, 0)

return
}

_set_name :: proc(thread: ^Thread) {
name, ok := thread.name.?
if !ok {
return
}

when ODIN_OS != .Darwin {
tid := thread.unix_thread
}

buf: [_MAX_PTHREAD_NAME_LENGTH]u8
copy(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 {
pthread_setname_np(tid, "%s", raw_data(buf[:]))
} else {
pthread_setname_np(tid, raw_data(buf[:]))
}

}
38 changes: 37 additions & 1 deletion core/thread/thread_windows.odin
Original file line number Diff line number Diff line change
Expand Up @@ -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 :: 128

Thread_Os_Specific :: struct {
win32_thread: win32.HANDLE,
Expand All @@ -22,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 {
Expand All @@ -44,6 +47,8 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
runtime.run_thread_local_cleaners()
}

_set_name(t)

t.procedure(t)
}

Expand Down Expand Up @@ -76,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)
Expand Down Expand Up @@ -152,3 +158,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 {
t_handle = win32.GetCurrentThread()
} else {
t_handle = thread.win32_thread
}

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
}

_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)
win32.SetThreadDescription(t_handle, raw_data(buf[:]))
}

Loading