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

use "atomic"
use "common"

pkg thread =
	type ftxtag = uint32
	impl atomic ftxtag

	const ftxwait : (uaddr : ftxtag#, val : ftxtag, tmout : std.time -> sys.errno)
	const ftxwake : (uaddr : ftxtag# -> void)
	const ftxwakeall : (uaddr : ftxtag# -> void)
;;

const ftxwait = {uaddr, val, tmout
	var rc

	if tmout < 0
		while (rc = (sys.futex((uaddr : int32#),
				sys.Futexwait | sys.Futexpriv,
				(val : int32),
				Zptr,
				Zptr,
				0) : sys.errno)) == sys.Eintr
		;;
	else
		var t = (tmout : int64)
		var ts
		std.assert(sys.clock_gettime(`sys.Clockmonotonic, &ts) == 0,
			"error: clock_gettime returned -1\n")
		ts.nsec += (t % 1_000_000) * 1000
		ts.sec += (ts.nsec / 1_000_000_000) + (t / 1_000_000)
		ts.nsec %= 1_000_000_000

		/*
		Futexwaitbitset + Futexbitsetmatchany causes the timeout to be
		treated as absolute rather than relative.
		*/
		while (rc = (sys.futex((uaddr : int32#),
				sys.Futexwaitbitset | sys.Futexpriv,
				(val : int32),
				&ts,
				Zptr,
				sys.Futexbitsetmatchany) : sys.errno)) == sys.Eintr
		;;
	;;

	match rc
	| 0: -> 0
	| sys.Eagain: -> sys.Eagain
	| sys.Etimedout: -> sys.Etimedout
	| err:
		std.fput(2, "error: futex returned {}\n", err)
		std.suicide()
	;;
}

const ftxwake = {uaddr
	sys.futex((uaddr : int32#), sys.Futexwake | sys.Futexpriv, 1, Zptr, Zptr, 0)
}

const ftxwakeall = {uaddr
	sys.futex((uaddr : int32#), sys.Futexwake | sys.Futexpriv, 0x7fffffff, Zptr, Zptr, 0)
}

impl atomic ftxtag =
	xget = {p; -> (xget32((p : uint32#)) : ftxtag)}
	xset = {p, v; xset32((p : uint32#), (v : uint32))}
	xadd = {p, v; -> (xadd32((p : uint32#), (v : uint32)) : ftxtag)}
	xcas = {p, old, new; -> (xcas32((p : uint32#), (old : uint32), (new : uint32)) : ftxtag)}
	xchg = {p, v; -> (xchg32((p : uint32#), (v : uint32)) : ftxtag)}
;;