Commit 9f926e81 authored by Matthew Dempsky's avatar Matthew Dempsky Committed by Joel Sing

runtime: simplify OpenBSD semaphores

OpenBSD's thrsleep system call includes an "abort" parameter, which
specifies a memory address to be tested after being registered on the
sleep channel (i.e., capable of being woken up by thrwakeup).  By
passing a pointer to waitsemacount for this parameter, we avoid race
conditions without needing a lock.  Instead we just need to use
atomicload, cas, and xadd to mutate the semaphore count.

Change-Id: If9f2ab7cfd682da217f9912783cadea7e72283a8
Reviewed-on: https://go-review.googlesource.com/5563Reviewed-by: 's avatarDmitry Vyukov <dvyukov@google.com>
Reviewed-by: 's avatarJoel Sing <jsing@google.com>
parent 1fda57ba
......@@ -62,25 +62,22 @@ func semasleep(ns int64) int32 {
}
for {
// spin-mutex lock
for {
if xchg(&_g_.m.waitsemalock, 1) == 0 {
break
v := atomicload(&_g_.m.waitsemacount)
if v > 0 {
if cas(&_g_.m.waitsemacount, v, v-1) {
return 0 // semaphore acquired
}
osyield()
continue
}
if _g_.m.waitsemacount != 0 {
// semaphore is available.
_g_.m.waitsemacount--
// spin-mutex unlock
atomicstore(&_g_.m.waitsemalock, 0)
return 0 // semaphore acquired
}
// sleep until semaphore != 0 or timeout.
// thrsleep unlocks m.waitsemalock.
ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, uintptr(unsafe.Pointer(&_g_.m.waitsemalock)), (*int32)(unsafe.Pointer(&_g_.m.waitsemacount)))
// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
//
// From OpenBSD's __thrsleep(2) manual:
// "The abort argument, if not NULL, points to an int that will
// be examined [...] immediately before blocking. If that int
// is non-zero then __thrsleep() will immediately return EINTR
// without blocking."
ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
if ret == _EWOULDBLOCK {
return -1
}
......@@ -89,14 +86,7 @@ func semasleep(ns int64) int32 {
//go:nosplit
func semawakeup(mp *m) {
// spin-mutex lock
for {
if xchg(&mp.waitsemalock, 1) == 0 {
break
}
osyield()
}
mp.waitsemacount++
xadd(&mp.waitsemacount, 1)
ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
if ret != 0 && ret != _ESRCH {
// semawakeup can be called on signal stack.
......@@ -104,8 +94,6 @@ func semawakeup(mp *m) {
print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
})
}
// spin-mutex unlock
atomicstore(&mp.waitsemalock, 0)
}
func newosproc(mp *m, stk unsafe.Pointer) {
......
......@@ -26,7 +26,7 @@ func raiseproc(sig int32)
func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
//go:noescape
func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *int32) int32
func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32
//go:noescape
func thrwakeup(ident uintptr, n int32) int32
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment