From 1620b10166a7e6447dd660cd381d48fd7f3e81e0 Mon Sep 17 00:00:00 2001 From: leongross Date: Sun, 17 Nov 2024 10:04:03 +0100 Subject: [PATCH] wip Signed-off-by: leongross --- src/runtime/sync.go | 73 +++++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/src/runtime/sync.go b/src/runtime/sync.go index 3d302ec7d2..83ddcab064 100644 --- a/src/runtime/sync.go +++ b/src/runtime/sync.go @@ -5,8 +5,9 @@ package runtime import ( + "internal/task" + "sync" "sync/atomic" - "unsafe" ) // This file contains stub implementations for internal/poll. @@ -24,22 +25,35 @@ import ( // 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 +// The global state of the semaphore table. +// Semaphores are identified by their address. +// The table maps the address to the task that is currently holding the semaphore. +// The table is protected by a mutex. +// When a task acquires a semaphore, the mapping is added to the map. +// When a task releases a semaphore, the mapping is removed from the map. +// +// The table is used to implement the cansemacquire function. +// The cansemacquire function is called by the semacquire function. +// The cansemacquire function checks if the semaphore is available. +// If the semaphore is available, the function returns true. +// If the semaphore is not available, the function returns false. +type semTable struct { + table map[*uint32]*task.Task + lock sync.Mutex } var semtable semTable -// Prime to not correlate with any user patterns. -const semTabSize = 251 +func init() { + semtable.table = make(map[*uint32]*task.Task) +} -type semTable [semTabSize]struct { - root semaRoot - pad [64 - unsafe.Sizeof(semaRoot{})]byte // only 64 x86_64, make this variable +func (s *semTable) Lock() { + s.lock.Lock() } -func (t *semTable) rootFor(addr *uint32) *semaRoot { - return &t[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root +func (s *semTable) Unlock() { + s.lock.Unlock() } //go:linkname semacquire internal/poll.runtime_Semacquire @@ -51,22 +65,37 @@ func semacquire(sema *uint32) { // 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 - } + // Busy Looping until a lookup to the global semaphore table can be made + semtable.Lock() + + if _, ok := semtable.table[addr]; !ok { + semtable.table[addr] = task.Current() + semtable.Unlock() + return true + } + + v := atomic.LoadUint32(addr) + if v == 0 { + semtable.Unlock() + return false + } + if atomic.CompareAndSwapUint32(addr, v, v-1) { + semtable.Unlock() + return true } + return true } //go:linkname semrelease internal/poll.runtime_Semrelease func semrelease(sema *uint32) { - root := semtable.rootFor(sema) - atomic.AddUint32(sema, 1) - if root.nwait.Load() == 0 { - return + // Check if the semaphore is in the table + semtable.Lock() + if _, ok := semtable.table[sema]; !ok { + panic("invalid semaphore") } + + atomic.AddUint32(sema, 1) + semtable.Unlock() + + Gosched() }