aboutsummaryrefslogtreecommitdiff
path: root/core/sync/sync2/futex_darwin.odin
blob: 9dad8d375510ed0591fd16ce4739e4c8574c3020 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//+private
//+build darwin
package sync2

import "core:c"
import "core:time"

foreign import System "System.framework"

foreign System {
	__ulock_wait  :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_ms: u32) -> c.int ---
	__ulock_wait2 :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_ns: u64, value2: u64) -> c.int ---
	__ulock_wake  :: proc "c" (operation: u32, addr: rawptr, wake_value: u64) -> c.int ---
}


UL_COMPARE_AND_WAIT :: 1
ULF_WAKE_ALL        :: 0x00000100
ULF_NO_ERRNO        :: 0x01000000

ENOENT    :: -2
EINTR     :: -4
EFAULT    :: -14
ETIMEDOUT :: -60

_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
	return _futex_wait_with_timeout(f, expected, 0)
}

_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
	timeout_ns := u64(duration)
	
	s := __ulock_wait2(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns, 0)
	if s >= 0 {
		return true
	}
	switch s {
	case EINTR, EFAULT:
		return true
	case ETIMEDOUT:
		return false
	case:
		panic("futex_wait failure")
	}
	return true

}

_futex_signal :: proc(f: ^Futex) {
	loop: for {
		s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
		if s >= 0 {
			return
		}
		switch s {
		case EINTR, EFAULT: 
			continue loop
		case ENOENT:
			return
		case:
			panic("futex_wake_single failure")
		}
	}
}

_futex_broadcast :: proc(f: ^Futex) {
	loop: for {
		s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
		if s >= 0 {
			return
		}
		switch s {
		case EINTR, EFAULT: 
			continue loop
		case ENOENT:
			return
		case:
			panic("futex_wake_all failure")
		}
	}
}