Skip to content

Commit 81fd6ff

Browse files
committed
add preliminary semaphore implementation
Signed-off-by: leongross <[email protected]>
1 parent b01b015 commit 81fd6ff

File tree

1 file changed

+61
-6
lines changed

1 file changed

+61
-6
lines changed

src/runtime/sync.go

+61-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,72 @@
1+
// Copyright 2009 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
15
package runtime
26

7+
import (
8+
"sync/atomic"
9+
"unsafe"
10+
)
11+
312
// This file contains stub implementations for internal/poll.
13+
// The official golang implementation states:
14+
//
15+
// "That is, don't think of these as semaphores.
16+
// Think of them as a way to implement sleep and wakeup
17+
// such that every sleep is paired with a single wakeup,
18+
// even if, due to races, the wakeup happens before the sleep."
19+
//
20+
// This is an experimental and probably incomplete implementation of the
21+
// semaphore system, tailed to the network use case. That means, that it does not
22+
// implement the modularity that the semacquire/semacquire1 implementation model
23+
// offers, which in fact is emitted here entirely.
24+
// This means we assume the following constant settings from the golang standard
25+
// library: lifo=false,profile=semaBlock,skipframe=0,reason=waitReasonSemaquire
26+
27+
type semaRoot struct {
28+
nwait atomic.Uint32
29+
}
30+
31+
var semtable semTable
32+
33+
// Prime to not correlate with any user patterns.
34+
const semTabSize = 251
35+
36+
type semTable [semTabSize]struct {
37+
root semaRoot
38+
pad [64 - unsafe.Sizeof(semaRoot{})]byte // only 64 x86_64, make this variable
39+
}
40+
41+
func (t *semTable) rootFor(addr *uint32) *semaRoot {
42+
return &t[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root
43+
}
444

545
//go:linkname semacquire internal/poll.runtime_Semacquire
646
func semacquire(sema *uint32) {
7-
// TODO the "net" pkg calls this, so panic() isn't an option. Right
8-
// now, just ignore the call.
9-
// panic("todo: semacquire")
47+
if cansemacquire(sema) {
48+
return
49+
}
50+
}
51+
52+
// Copied from src/runtime/sema.go
53+
func cansemacquire(addr *uint32) bool {
54+
for {
55+
v := atomic.LoadUint32(addr)
56+
if v == 0 {
57+
return false
58+
}
59+
if atomic.CompareAndSwapUint32(addr, v, v-1) {
60+
return true
61+
}
62+
}
1063
}
1164

1265
//go:linkname semrelease internal/poll.runtime_Semrelease
1366
func semrelease(sema *uint32) {
14-
// TODO the "net" pkg calls this, so panic() isn't an option. Right
15-
// now, just ignore the call.
16-
// panic("todo: semrelease")
67+
root := semtable.rootFor(sema)
68+
atomic.AddUint32(sema, 1)
69+
if root.nwait.Load() == 0 {
70+
return
71+
}
1772
}

0 commit comments

Comments
 (0)