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
83
84
85
86
87
88
89
90
91
92
|
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 : uint32#),
sys.Futexwait,
(val : int),
Zptr,
Zptr) : sys.errno)) == sys.Eintr
;;
else
var t = (tmout : int64)
var start
std.assert(sys.clock_gettime(`sys.Clockmonotonic, &start) == 0,
"error: clock_gettime returned -1\n")
var ts = [
.sec = t / 1_000_000,
.nsec = (t % 1_000_000) * 1000,
]
while (rc = (sys.futex((uaddr : uint32#),
sys.Futexwait,
(val : int),
&ts,
Zptr) : sys.errno)) == sys.Eintr
var now
std.assert(sys.clock_gettime(`sys.Clockmonotonic, &now) == 0,
"error: clock_gettime returned -1\n")
var t1 = t - ((now.sec - start.sec) * 1_000_000)
var nsec = now.nsec - start.nsec
if nsec >= 0
t1 -= nsec / 1000
else
t1 -= (1_000_000_000 + nsec) / 1000
;;
if t1 > t
-> sys.Etimedout
;;
ts.sec = t1 / 1_000_000
ts.nsec = (t1 % 1_000_000) * 1000
t = t1
;;
;;
/*
* Since Myrddin uses the convention that negative
* values flag an error, but futexes just return a
* positive, non-errno value, we need to match against
* the positive value.
*/
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 : uint32#), sys.Futexwake, 1, Zptr, Zptr)
}
const ftxwakeall = {uaddr
sys.futex((uaddr : uint32#), sys.Futexwake, 0x7fffffff, Zptr, Zptr)
}
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)}
;;
|