summaryrefslogtreecommitdiff
path: root/lib/thread/futex+osx.myr
blob: 174787037cd919e4b60b58f168c48df6b04f8032 (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
use std
use sys

use "atomic"
use "common"

pkg thread =
	type ftxtag = uint64
	impl atomic ftxtag

	const ftxwait : (uaddr : ftxtag#, val : ftxtag, timeout : sys.timespec# -> int)
	const ftxwake : (uaddr : ftxtag# -> int)
	const ftxwakeall : (uaddr : ftxtag# -> int)
;;

/*
 * The ulock_ functions are undocumented but the relevant source can be found at
 * https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/kern/sys_ulock.c
 */
const ftxwait = {uaddr, val, timeout
	if timeout == Zptr
		-> sys.ulock_wait(sys.Ulockcompareandwait, (uaddr : uint64#), (val : uint64), 0)
	;;

	var ts
	var err = sys.clock_gettime(`sys.Clockmonotonic, &ts)
	std.assert(err == 0, "error: clock_gettime returned {}\n", err)
	if timeout.sec < ts.sec
		-> (std.Etimedout : int)
	;;

	var usec = 0
	var sec = (timeout.sec - ts.sec) * 1000
	std.assert(sec <= 0xffffffff, "error: maximum futex timeout exceeded\n")
	usec = (sec : uint32)
	if timeout.nsec > ts.nsec
		var nsec = (timeout.nsec - ts.nsec) / 1000
		std.assert(usec + nsec > usec, "error: maximum futex timeout exceeded\n")
		usec += nsec
	;;

	if usec == 0
		-> (std.Etimedout : int)
	;;
	-> sys.ulock_wait(sys.Ulockcompareandwait, (uaddr : uint64#), (val : uint64), usec)
}

const ftxwake = {uaddr
	-> sys.ulock_wake(sys.Ulockcompareandwait, (uaddr : uint64#), 0)
}

const ftxwakeall = {uaddr
	-> sys.ulock_wake(sys.Ulockcompareandwait | sys.Ulockulfwakeall, (uaddr : uint64#), 0)
}

impl atomic ftxtag =
	xget = {p; -> (xget64((p : uint64#)) : ftxtag)}
	xset = {p, v; xset64((p : uint64#), (v : uint64))}
	xadd = {p, v; -> (xadd64((p : uint64#), (v : uint64)) : ftxtag)}
	xcas = {p, old, new; -> (xcas64((p : uint64#), (old : uint64), (new : uint64)) : ftxtag)}
	xchg = {p, v; -> (xchg64((p : uint64#), (v : uint64)) : ftxtag)}
;;