From 73cba2cf13cb2440c481fe8a6753ac613ddb2582 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 11 Oct 2021 12:55:25 +0100 Subject: [PATCH] Add `cond_wait_with_timeout` --- core/sync/sync2/futex_linux.odin | 14 ++++++++---- core/sync/sync2/futex_windows.odin | 27 ++++++++++++++++-------- core/sync/sync2/primitives.odin | 7 ++++++ core/sync/sync2/primitives_darwin.odin | 7 ++++++ core/sync/sync2/primitives_pthreads.odin | 10 +++++++++ core/sync/sync2/primitives_windows.odin | 8 +++++++ 6 files changed, 60 insertions(+), 13 deletions(-) diff --git a/core/sync/sync2/futex_linux.odin b/core/sync/sync2/futex_linux.odin index 44162172a..9fadd4c06 100644 --- a/core/sync/sync2/futex_linux.odin +++ b/core/sync/sync2/futex_linux.odin @@ -33,7 +33,7 @@ get_errno :: proc(r: int) -> int { return 0 } -internal_futex :: proc(f: ^Futex, op: uintptr, val: u32, timeout: rawptr) -> int { +internal_futex :: proc(f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int { code := int(intrinsics.syscall(202, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0)) return get_errno(code) } @@ -55,13 +55,19 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> Futex_Error { } _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> Futex_Error { - timeout: struct { + timespec_t :: struct { tv_sec: c.long, tv_nsec: c.long, } - timeout.tv_sec = (c.long)(duration/1e9) - timeout.tv_nsec = (c.long)(duration%1e9) + timeout: timespec_t + timeout_ptr: ^timespec_t = nil + + if duration > 0 { + timeout.tv_sec = (c.long)(duration/1e9) + timeout.tv_nsec = (c.long)(duration%1e9) + timeout_ptr = &timeout + } err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, &timeout) switch err { diff --git a/core/sync/sync2/futex_windows.odin b/core/sync/sync2/futex_windows.odin index da9e7c134..361c2bc3f 100644 --- a/core/sync/sync2/futex_windows.odin +++ b/core/sync/sync2/futex_windows.odin @@ -5,30 +5,39 @@ package sync2 import "core:time" foreign import Synchronization "system:Synchronization.lib" +foreign import NtDll "system:NtDll.lib" -@(default_calling_convention="c") +@(default_calling_convention="stdcall") +foreign NtDll { + RtlWaitOnAddress :: proc(Address: rawptr, CompareAddress: rawptr, AddressSize: uint, Timeout: ^i64) -> b32 --- +} + +@(default_calling_convention="stdcall") foreign Synchronization { - WaitOnAddress :: proc(Address: rawptr, CompareAddress: rawptr, AddressSize: uint, dwMilliseconds: u32) -> b32 --- WakeByAddressSingle :: proc(Address: rawptr) --- WakeByAddressAll :: proc(Address: rawptr) --- } + + _futex_wait :: proc(f: ^Futex, expect: u32) -> Futex_Error { expect := expect - ms :: ~u32(0) // infinite - ok := WaitOnAddress(f, &expect, size_of(expect), ms) + ok := RtlWaitOnAddress(f, &expect, size_of(expect), nil) return nil if ok else .Timed_Out } _futex_wait_with_timeout :: proc(f: ^Futex, expect: u32, duration: time.Duration) -> Futex_Error { expect := expect - ms: u32 = 0 - if duration >= 0 { - ms = u32(u64(duration)/1e6) + timeout: i64 + timeout_ptr: ^i64 + if duration > 0 { + // In 100 ns units + timeout = i64(timeout)/100 + timeout_ptr = &timeout } - - ok := WaitOnAddress(f, &expect, size_of(expect), ms) + \ + ok := RtlWaitOnAddress(f, &expect, size_of(expect), timeout_ptr) return nil if ok else .Timed_Out } diff --git a/core/sync/sync2/primitives.odin b/core/sync/sync2/primitives.odin index 5ea17af6b..230a8b0d4 100644 --- a/core/sync/sync2/primitives.odin +++ b/core/sync/sync2/primitives.odin @@ -153,6 +153,10 @@ cond_wait :: proc(c: ^Cond, m: ^Mutex) { _cond_wait(c, m) } +cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { + return _cond_wait_with_timeout(c, m, duration) +} + cond_signal :: proc(c: ^Cond) { _cond_signal(c) } @@ -215,6 +219,9 @@ futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duratio if u32(atomic_load(f)) != expected { return nil } + if duration == 0 { + return .Timed_Out + } return _futex_wait_with_timeout(f, expected, duration) } diff --git a/core/sync/sync2/primitives_darwin.odin b/core/sync/sync2/primitives_darwin.odin index 4fbe1d62a..bd9b0e267 100644 --- a/core/sync/sync2/primitives_darwin.odin +++ b/core/sync/sync2/primitives_darwin.odin @@ -3,6 +3,7 @@ package sync2 import "core:c" +import "core:time" import "core:intrinsics" foreign import pthread "System.framework" @@ -43,6 +44,12 @@ _cond_wait :: proc(c: ^Cond, m: ^Mutex) { atomic_cond_wait(&c.impl.cond, &m.impl.mutex) } +_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { + // TODO(bill): _cond_wait_with_timeout for Darwin + atomic_cond_wait(&c.impl.cond, &m.impl.mutex) + return true +} + _cond_signal :: proc(c: ^Cond) { atomic_cond_signal(&c.impl.cond) } diff --git a/core/sync/sync2/primitives_pthreads.odin b/core/sync/sync2/primitives_pthreads.odin index 436555a66..8d2c3986d 100644 --- a/core/sync/sync2/primitives_pthreads.odin +++ b/core/sync/sync2/primitives_pthreads.odin @@ -2,6 +2,7 @@ //+private package sync2 +import "core:time" import "core:sys/unix" _Mutex_State :: enum i32 { @@ -37,6 +38,15 @@ _cond_wait :: proc(c: ^Cond, m: ^Mutex) { assert(err == 0) } + +_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { + tv_sec := i64(duration/1e9) + tv_nsec := i64(duration%1e9) + err := unix.pthread_cond_timedwait(&c.impl.pthread_cond, &m.impl.pthread_mutex, &{tv_sec, tv_nsec}) + return err == 0 +} + + _cond_signal :: proc(c: ^Cond) { err := unix.pthread_cond_signal(&c.impl.pthread_cond) assert(err == 0) diff --git a/core/sync/sync2/primitives_windows.odin b/core/sync/sync2/primitives_windows.odin index 2a4626eab..ca7a5c9ee 100644 --- a/core/sync/sync2/primitives_windows.odin +++ b/core/sync/sync2/primitives_windows.odin @@ -2,6 +2,7 @@ //+private package sync2 +import "core:time" import win32 "core:sys/windows" _current_thread_id :: proc "contextless" () -> int { @@ -61,6 +62,13 @@ _cond_wait :: proc(c: ^Cond, m: ^Mutex) { _ = win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, win32.INFINITE, 0) } +_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool { + duration := u32(duration / time.Millisecond) + ok := win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, duration, 0) + return bool(ok) +} + + _cond_signal :: proc(c: ^Cond) { win32.WakeConditionVariable(&c.impl.cond) }