Skip to content

Commit

Permalink
add preliminary semaphore implementation
Browse files Browse the repository at this point in the history
Signed-off-by: leongross <leon.gross@9elements.com>
  • Loading branch information
leongross committed Nov 4, 2024
1 parent b01b015 commit 81fd6ff
Showing 1 changed file with 61 additions and 6 deletions.
67 changes: 61 additions & 6 deletions src/runtime/sync.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,72 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import (
"sync/atomic"
"unsafe"
)

// This file contains stub implementations for internal/poll.
// The official golang implementation states:
//
// "That is, don't think of these as semaphores.
// Think of them as a way to implement sleep and wakeup
// such that every sleep is paired with a single wakeup,
// even if, due to races, the wakeup happens before the sleep."
//
// This is an experimental and probably incomplete implementation of the
// semaphore system, tailed to the network use case. That means, that it does not
// implement the modularity that the semacquire/semacquire1 implementation model
// offers, which in fact is emitted here entirely.
// This means we assume the following constant settings from the golang standard
// library: lifo=false,profile=semaBlock,skipframe=0,reason=waitReasonSemaquire

type semaRoot struct {
nwait atomic.Uint32
}

var semtable semTable

// Prime to not correlate with any user patterns.
const semTabSize = 251

type semTable [semTabSize]struct {
root semaRoot
pad [64 - unsafe.Sizeof(semaRoot{})]byte // only 64 x86_64, make this variable
}

func (t *semTable) rootFor(addr *uint32) *semaRoot {
return &t[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root
}

//go:linkname semacquire internal/poll.runtime_Semacquire
func semacquire(sema *uint32) {
// TODO the "net" pkg calls this, so panic() isn't an option. Right
// now, just ignore the call.
// panic("todo: semacquire")
if cansemacquire(sema) {
return
}
}

// Copied from src/runtime/sema.go
func cansemacquire(addr *uint32) bool {
for {
v := atomic.LoadUint32(addr)
if v == 0 {
return false
}
if atomic.CompareAndSwapUint32(addr, v, v-1) {
return true
}
}
}

//go:linkname semrelease internal/poll.runtime_Semrelease
func semrelease(sema *uint32) {
// TODO the "net" pkg calls this, so panic() isn't an option. Right
// now, just ignore the call.
// panic("todo: semrelease")
root := semtable.rootFor(sema)
atomic.AddUint32(sema, 1)
if root.nwait.Load() == 0 {
return
}
}

0 comments on commit 81fd6ff

Please sign in to comment.