Skip to content

Commit c16ff80

Browse files
committed
implement semrealse and semacquire using futex
Signed-off-by: leongross <[email protected]>
1 parent da0f694 commit c16ff80

File tree

1 file changed

+16
-65
lines changed

1 file changed

+16
-65
lines changed

src/runtime/sync.go

+16-65
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
package runtime
66

77
import (
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
6027
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)
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
9041
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)
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

Comments
 (0)