5
5
package runtime
6
6
7
7
import (
8
- "internal/task"
9
- "sync"
10
- "sync/atomic"
8
+ "internal/futex"
11
9
)
12
10
13
11
// This file contains stub implementations for internal/poll.
@@ -25,77 +23,30 @@ import (
25
23
// This means we assume the following constant settings from the golang standard
26
24
// library: lifo=false,profile=semaBlock,skipframe=0,reason=waitReasonSemaquire
27
25
28
- // The global state of the semaphore table.
29
- // Semaphores are identified by their address.
30
- // The table maps the address to the task that is currently holding the semaphore.
31
- // The table is protected by a mutex.
32
- // When a task acquires a semaphore, the mapping is added to the map.
33
- // When a task releases a semaphore, the mapping is removed from the map.
34
- //
35
- // The table is used to implement the cansemacquire function.
36
- // The cansemacquire function is called by the semacquire function.
37
- // The cansemacquire function checks if the semaphore is available.
38
- // If the semaphore is available, the function returns true.
39
- // If the semaphore is not available, the function returns false.
40
- type semTable struct {
41
- table map [* uint32 ]* task.Task
42
- lock sync.Mutex
43
- }
44
-
45
- var semtable semTable
46
-
47
- func init () {
48
- semtable .table = make (map [* uint32 ]* task.Task )
49
- }
50
-
51
- func (s * semTable ) Lock () {
52
- s .lock .Lock ()
53
- }
54
-
55
- func (s * semTable ) Unlock () {
56
- s .lock .Unlock ()
57
- }
58
-
59
26
//go:linkname semacquire internal/poll.runtime_Semacquire
60
27
func semacquire (sema * uint32 ) {
61
- if cansemacquire (sema ) {
62
- return
63
- }
64
- }
65
-
66
- // Copied from src/runtime/sema.go
67
- func cansemacquire (addr * uint32 ) bool {
68
- // Busy Looping until a lookup to the global semaphore table can be made
69
- semtable .Lock ()
28
+ var semaBlock futex.Futex
29
+ semaBlock .Store (* sema )
70
30
71
- if _ , ok := semtable .table [addr ]; ! ok {
72
- semtable .table [addr ] = task .Current ()
73
- semtable .Unlock ()
74
- return true
75
- }
31
+ // 1. check if we can acquire the semaphore
32
+ semaBlock .Wait (0 )
76
33
77
- v := atomic .LoadUint32 (addr )
78
- if v == 0 {
79
- semtable .Unlock ()
80
- return false
81
- }
82
- if atomic .CompareAndSwapUint32 (addr , v , v - 1 ) {
83
- semtable .Unlock ()
84
- return true
34
+ // the semaphore is free to use so we can acquire it
35
+ if semaBlock .Swap (1 ) != 0 {
36
+ panic ("semaphore is already acquired, racy" )
85
37
}
86
- return true
87
38
}
88
39
89
40
//go:linkname semrelease internal/poll.runtime_Semrelease
90
41
func semrelease (sema * uint32 ) {
91
- // Check if the semaphore is in the table
92
- semtable .Lock ()
93
- if _ , ok := semtable .table [sema ]; ! ok {
94
- panic ("invalid semaphore" )
95
- }
42
+ var semaBlock futex.Futex
43
+ semaBlock .Store (* sema )
96
44
97
- atomic .AddUint32 (sema , 1 )
98
- semtable .Unlock ()
45
+ // check if we can release the semaphore
46
+ if semaBlock .Swap (0 ) != 1 {
47
+ panic ("semaphore is not acquired, racy" )
48
+ }
99
49
100
- Gosched ()
50
+ // wake up the next waiter
51
+ semaBlock .Wake ()
101
52
}
0 commit comments