Skip to content

Commit 52be3d8

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

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

builder/musl.go

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ var libMusl = Library{
116116
"env/*.c",
117117
"errno/*.c",
118118
"exit/*.c",
119+
"fcntl/*.c",
119120
"internal/defsysinfo.c",
120121
"internal/libc.c",
121122
"internal/syscall_ret.c",

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)