55package runtime
66
77import (
8- "internal/task"
9- "sync"
10- "sync/atomic"
8+ "internal/futex"
119)
1210
1311// This file contains stub implementations for internal/poll.
@@ -25,77 +23,30 @@ import (
2523// This means we assume the following constant settings from the golang standard
2624// library: lifo=false,profile=semaBlock,skipframe=0,reason=waitReasonSemaquire
2725
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-
5926//go:linkname semacquire internal/poll.runtime_Semacquire
6027func 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 )
7030
71- if _ , ok := semtable .table [addr ]; ! ok {
72- semtable .table [addr ] = task .Current ()
73- semtable .Unlock ()
74- return true
75- }
31+ // check if we can acquire the semaphore
32+ semaBlock .Wait (1 )
7633
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 (0 ) != 1 {
36+ panic ("semaphore is already acquired, racy" )
8537 }
86- return true
8738}
8839
8940//go:linkname semrelease internal/poll.runtime_Semrelease
9041func 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 )
9644
97- atomic .AddUint32 (sema , 1 )
98- semtable .Unlock ()
45+ // check if we can release the semaphore
46+ if semaBlock .Swap (1 ) != 0 {
47+ panic ("semaphore is not acquired, racy" )
48+ }
9949
100- Gosched ()
50+ // wake up the next waiter
51+ semaBlock .Wake ()
10152}
0 commit comments