From 4558f3992a47b4597563152baf26f1d2b5684b4d Mon Sep 17 00:00:00 2001 From: Andreas T Jonsson Date: Tue, 16 Apr 2024 14:27:29 +0200 Subject: Initial commit of NetBSD port --- src/threading.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/threading.cpp') diff --git a/src/threading.cpp b/src/threading.cpp index fbe8997d1..77aa8edf7 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -627,8 +627,12 @@ gb_internal void thread_set_name(Thread *t, char const *name) { #elif defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) pthread_set_name_np(t->posix_handle, name); #else - // TODO(bill): Test if this works - pthread_setname_np(t->posix_handle, name); + #ifdef GB_SYSTEM_NETBSD + // TODO(phix): Could be that libs are to old on NetBSD? Just ignore for now. + #else + // TODO(bill): Test if this works + pthread_setname_np(t->posix_handle, name); + #endif #endif } @@ -901,10 +905,11 @@ gb_internal void futex_wait(Futex *f, Footex val) { } while (f->load() == val); } -#elif defined(GB_SYSTEM_HAIKU) +#elif defined(GB_SYSTEM_HAIKU) || defined(GB_SYSTEM_NETBSD) // Futex implementation taken from https://tavianator.com/2023/futex.html +#include #include #include -- cgit v1.2.3 From 80067a959b51d4bda4aaf96677ca1d2e4831323d Mon Sep 17 00:00:00 2001 From: Andreas T Jonsson Date: Wed, 17 Apr 2024 09:42:41 +0200 Subject: Added thread name Call pthread_setname_np with the correct number of arguments on NetBSD. --- src/threading.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/threading.cpp') diff --git a/src/threading.cpp b/src/threading.cpp index 77aa8edf7..79ed8e8a4 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -626,13 +626,11 @@ gb_internal void thread_set_name(Thread *t, char const *name) { pthread_setname_np(name); #elif defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) pthread_set_name_np(t->posix_handle, name); +#elif defined(GB_SYSTEM_NETBSD) + pthread_setname_np(t->posix_handle, "%s", (void*)name); #else - #ifdef GB_SYSTEM_NETBSD - // TODO(phix): Could be that libs are to old on NetBSD? Just ignore for now. - #else - // TODO(bill): Test if this works - pthread_setname_np(t->posix_handle, name); - #endif + // TODO(bill): Test if this works + pthread_setname_np(t->posix_handle, name); #endif } -- cgit v1.2.3 From 3000508c027c9d30c168266d0ae276cc14de3982 Mon Sep 17 00:00:00 2001 From: Andreas T Jonsson Date: Thu, 25 Apr 2024 21:50:34 +0200 Subject: Switched to native futex on NetBSD --- core/sync/futex_netbsd.odin | 183 ++++++++++--------------------------- core/sys/unix/signal_netbsd.odin | 30 ------ core/sys/unix/syscalls_netbsd.odin | 3 + src/threading.cpp | 13 ++- 4 files changed, 58 insertions(+), 171 deletions(-) delete mode 100644 core/sys/unix/signal_netbsd.odin create mode 100644 core/sys/unix/syscalls_netbsd.odin (limited to 'src/threading.cpp') diff --git a/core/sync/futex_netbsd.odin b/core/sync/futex_netbsd.odin index 4f52e952f..06ff00a98 100644 --- a/core/sync/futex_netbsd.odin +++ b/core/sync/futex_netbsd.odin @@ -1,165 +1,74 @@ //+private package sync -import "core:c" +import "base:intrinsics" import "core:time" +import "core:c" import "core:sys/unix" -@(private="file") -Wait_Node :: struct { - thread: unix.pthread_t, - futex: ^Futex, - prev, next: ^Wait_Node, -} -@(private="file") -atomic_flag :: distinct bool -@(private="file") -Wait_Queue :: struct { - lock: atomic_flag, - list: Wait_Node, -} -@(private="file") -waitq_lock :: proc "contextless" (waitq: ^Wait_Queue) { - for cast(bool)atomic_exchange_explicit(&waitq.lock, atomic_flag(true), .Acquire) { - cpu_relax() // spin... - } -} -@(private="file") -waitq_unlock :: proc "contextless" (waitq: ^Wait_Queue) { - atomic_store_explicit(&waitq.lock, atomic_flag(false), .Release) -} +foreign import libc "system:c" -// FIXME: This approach may scale badly in the future, -// possible solution - hash map (leads to deadlocks now). -@(private="file") -g_waitq: Wait_Queue +FUTEX_PRIVATE_FLAG :: 128 -@(init, private="file") -g_waitq_init :: proc() { - g_waitq = { - list = { - prev = &g_waitq.list, - next = &g_waitq.list, - }, - } -} +FUTEX_WAIT_PRIVATE :: 0 | FUTEX_PRIVATE_FLAG +FUTEX_WAKE_PRIVATE :: 1 | FUTEX_PRIVATE_FLAG -@(private="file") -get_waitq :: #force_inline proc "contextless" (f: ^Futex) -> ^Wait_Queue { - _ = f - return &g_waitq -} +EINTR :: 4 /* Interrupted system call */ +EAGAIN :: 35 /* Resource temporarily unavailable */ +ETIMEDOUT :: 60 /* Operation timed out */ -_futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> (ok: bool) { - waitq := get_waitq(f) - waitq_lock(waitq) - defer waitq_unlock(waitq) +Time_Spec :: struct { + time_sec: uint, + time_nsec: uint, +} - head := &waitq.list - waiter := Wait_Node{ - thread = unix.pthread_self(), - futex = f, - prev = head, - next = head.next, +get_last_error :: proc "contextless" () -> int { + foreign libc { + __errno :: proc() -> ^c.int --- } + return int(__errno()^) +} - waiter.prev.next = &waiter - waiter.next.prev = &waiter - - old_mask, mask: unix.sigset_t - unix.sigemptyset(&mask) - unix.sigaddset(&mask, unix.SIGCONT) - unix.pthread_sigmask(unix.SIG_BLOCK, &mask, &old_mask) - - if u32(atomic_load_explicit(f, .Acquire)) == expect { - waitq_unlock(waitq) - defer waitq_lock(waitq) - - sig: c.int - unix.sigwait(&mask, &sig) - errno := unix.errno() - ok = errno == unix.ERROR_NONE +_futex_wait :: proc "contextless" (futex: ^Futex, expected: u32) -> bool { + if cast(int) intrinsics.syscall(unix.SYS___futex, uintptr(futex), FUTEX_WAIT_PRIVATE, uintptr(expected), 0) == -1 { + switch get_last_error() { + case EINTR, EAGAIN: + return true + case: + _panic("futex_wait failure") + } } - - waiter.prev.next = waiter.next - waiter.next.prev = waiter.prev - - unix.pthread_sigmask(unix.SIG_SETMASK, &old_mask, nil) - - // FIXME: Add error handling! - return + return true } -_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration: time.Duration) -> (ok: bool) { +_futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, duration: time.Duration) -> bool { if duration <= 0 { return false } - waitq := get_waitq(f) - waitq_lock(waitq) - defer waitq_unlock(waitq) - - head := &waitq.list - waiter := Wait_Node{ - thread = unix.pthread_self(), - futex = f, - prev = head, - next = head.next, - } - - waiter.prev.next = &waiter - waiter.next.prev = &waiter - - old_mask, mask: unix.sigset_t - unix.sigemptyset(&mask) - unix.sigaddset(&mask, unix.SIGCONT) - unix.pthread_sigmask(unix.SIG_BLOCK, &mask, &old_mask) - - if u32(atomic_load_explicit(f, .Acquire)) == expect { - waitq_unlock(waitq) - defer waitq_lock(waitq) - - info: unix.siginfo_t - ts := unix.timespec{ - tv_sec = i64(duration / 1e9), - tv_nsec = i64(duration % 1e9), + if cast(int) intrinsics.syscall(unix.SYS___futex, uintptr(futex), FUTEX_WAIT_PRIVATE, uintptr(expected), cast(uintptr) &Time_Spec{ + time_sec = cast(uint)(duration / 1e9), + time_nsec = cast(uint)(duration % 1e9), + }) == -1 { + switch get_last_error() { + case EINTR, EAGAIN: + return true + case ETIMEDOUT: + return false + case: + _panic("futex_wait_with_timeout failure") } - unix.sigtimedwait(&mask, &info, &ts) - errno := unix.errno() - ok = errno == unix.EAGAIN || errno == unix.ERROR_NONE } - - waiter.prev.next = waiter.next - waiter.next.prev = waiter.prev - - unix.pthread_sigmask(unix.SIG_SETMASK, &old_mask, nil) - - // FIXME: Add error handling! - return + return true } -_futex_signal :: proc "contextless" (f: ^Futex) { - waitq := get_waitq(f) - waitq_lock(waitq) - defer waitq_unlock(waitq) - - head := &waitq.list - for waiter := head.next; waiter != head; waiter = waiter.next { - if waiter.futex == f { - unix.pthread_kill(waiter.thread, unix.SIGCONT) - break - } +_futex_signal :: proc "contextless" (futex: ^Futex) { + if cast(int) intrinsics.syscall(unix.SYS___futex, uintptr(futex), FUTEX_WAKE_PRIVATE, 1) == -1 { + _panic("futex_wake_single failure") } } -_futex_broadcast :: proc "contextless" (f: ^Futex) { - waitq := get_waitq(f) - waitq_lock(waitq) - defer waitq_unlock(waitq) - - head := &waitq.list - for waiter := head.next; waiter != head; waiter = waiter.next { - if waiter.futex == f { - unix.pthread_kill(waiter.thread, unix.SIGCONT) - } +_futex_broadcast :: proc "contextless" (futex: ^Futex) { + if cast(int) intrinsics.syscall(unix.SYS___futex, uintptr(futex), FUTEX_WAKE_PRIVATE, uintptr(max(i32))) == -1 { + _panic("_futex_wake_all failure") } } diff --git a/core/sys/unix/signal_netbsd.odin b/core/sys/unix/signal_netbsd.odin deleted file mode 100644 index c32f0bfbe..000000000 --- a/core/sys/unix/signal_netbsd.odin +++ /dev/null @@ -1,30 +0,0 @@ -package unix - -import "core:c" - -foreign import libc "system:c" - -ERROR_NONE :: 0 -EAGAIN :: 35 - -SIGCONT :: 19 - -SIG_BLOCK :: 1 -SIG_UNBLOCK :: 2 -SIG_SETMASK :: 3 - -siginfo_t :: struct { _: [128]u8 } -sigset_t :: struct { _: [4]u32 } - -foreign libc { - @(link_name="__sigemptyset14") sigemptyset :: proc(set: ^sigset_t) -> c.int --- - @(link_name="__sigaddset14") sigaddset :: proc(set: ^sigset_t, _signal: c.int) -> c.int --- - @(link_name="__sigtimedwait50") sigtimedwait :: proc(set: ^sigset_t, info: ^siginfo_t, timeout: ^timespec) -> c.int --- - @(link_name="sigwait") sigwait :: proc(set: ^sigset_t, _signal: ^c.int) -> c.int --- - - @(private="file", link_name="__errno") get_error_location :: proc() -> ^c.int --- -} - -errno :: #force_inline proc "contextless" () -> int { - return int(get_error_location()^) -} diff --git a/core/sys/unix/syscalls_netbsd.odin b/core/sys/unix/syscalls_netbsd.odin new file mode 100644 index 000000000..e92dc6d92 --- /dev/null +++ b/core/sys/unix/syscalls_netbsd.odin @@ -0,0 +1,3 @@ +package unix + +SYS___futex : uintptr : 166 diff --git a/src/threading.cpp b/src/threading.cpp index 79ed8e8a4..b2cfa6d8e 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -634,9 +634,15 @@ gb_internal void thread_set_name(Thread *t, char const *name) { #endif } -#if defined(GB_SYSTEM_LINUX) -#include +#if defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_NETBSD) + #include +#ifdef GB_SYSTEM_LINUX + #include +#else + #include + #define SYS_futex SYS___futex +#endif gb_internal void futex_signal(Futex *addr) { int ret = syscall(SYS_futex, addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1, NULL, NULL, 0); @@ -903,11 +909,10 @@ gb_internal void futex_wait(Futex *f, Footex val) { } while (f->load() == val); } -#elif defined(GB_SYSTEM_HAIKU) || defined(GB_SYSTEM_NETBSD) +#elif defined(GB_SYSTEM_HAIKU) // Futex implementation taken from https://tavianator.com/2023/futex.html -#include #include #include -- cgit v1.2.3