@@ -3,16 +3,31 @@ const builtin = @import("builtin");
3
3
const AtomicOrder = builtin .AtomicOrder ;
4
4
const AtomicRmwOp = builtin .AtomicRmwOp ;
5
5
const assert = std .debug .assert ;
6
+ const linux = std .os .linux ;
7
+
8
+ // Reading: Futexes Are Tricky by Ulrich Drepper https://www.akkadia.org/drepper/futex.pdf
9
+
10
+ // TODO robust mutexes https://www.kernel.org/doc/Documentation/robust-futexes.txt
6
11
7
- /// TODO use syscalls instead of a spinlock
8
12
pub const Mutex = struct {
9
- lock : u8 , // TODO use a bool
13
+ // TODO: Windows and OSX with futex equivilents
14
+ // 0: unlocked
15
+ // 1: locked, no waiters
16
+ // 2: locked: one or more waiters
17
+ lock : u32 , // futexs are 32-bits on all architectures
10
18
11
19
pub const Held = struct {
12
20
mutex : * Mutex ,
13
21
14
22
pub fn release (self : Held ) void {
15
- assert (@atomicRmw (u8 , & self .mutex .lock , builtin .AtomicRmwOp .Xchg , 0 , AtomicOrder .SeqCst ) == 1 );
23
+ if (@atomicRmw (u32 , & self .mutex .lock , AtomicRmwOp .Sub , 1 , AtomicOrder .Release ) != 1 ) {
24
+ self .mutex .lock = 0 ;
25
+ if (builtin .os == builtin .Os .linux ) {
26
+ _ = linux .futex_wake (@ptrToInt (& self .mutex .lock ), linux .FUTEX_WAKE | linux .FUTEX_PRIVATE_FLAG , 1 );
27
+ } else {
28
+ @compileError ("not implemented" );
29
+ }
30
+ }
16
31
}
17
32
};
18
33
@@ -21,7 +36,28 @@ pub const Mutex = struct {
21
36
}
22
37
23
38
pub fn acquire (self : * Mutex ) Held {
24
- while (@atomicRmw (u8 , & self .lock , builtin .AtomicRmwOp .Xchg , 1 , AtomicOrder .SeqCst ) != 0 ) {}
39
+ var c : u32 = undefined ;
40
+ // This need not be strong because of the loop that follows.
41
+ // TODO implement mutex3 from https://www.akkadia.org/drepper/futex.pdf in x86 assembly.
42
+ if (@cmpxchgWeak (u32 , & self .lock , 0 , 1 , AtomicOrder .Acquire , AtomicOrder .Monotonic )) | value1 | {
43
+ c = value1 ;
44
+ while (true ) {
45
+ if (c == 2 or
46
+ @cmpxchgWeak (u32 , & self .lock , 1 , 2 , AtomicOrder .Acquire , AtomicOrder .Monotonic ) == null )
47
+ {
48
+ if (builtin .os == builtin .Os .linux ) {
49
+ _ = linux .futex_wait (@ptrToInt (& self .lock ), linux .FUTEX_WAIT | linux .FUTEX_PRIVATE_FLAG , 2 , null );
50
+ } else {
51
+ @compileError ("not implemented" );
52
+ }
53
+ }
54
+ if (@cmpxchgWeak (u32 , & self .lock , 0 , 2 , AtomicOrder .Acquire , AtomicOrder .Monotonic )) | value2 | {
55
+ c = value2 ;
56
+ } else {
57
+ break ;
58
+ }
59
+ }
60
+ }
25
61
return Held { .mutex = self };
26
62
}
27
63
};
0 commit comments