mirror of
https://github.com/golang/go
synced 2024-11-18 03:44:46 -07:00
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/5563 Reviewed-by: Dmitry Vyukov <dvyukov@google.com> Reviewed-by: Joel Sing <jsing@google.com>
This commit is contained in:
parent
1fda57ba72
commit
9f926e81c2
@ -62,25 +62,22 @@ func semasleep(ns int64) int32 {
|
||||
}
|
||||
|
||||
for {
|
||||
// spin-mutex lock
|
||||
for {
|
||||
if xchg(&_g_.m.waitsemalock, 1) == 0 {
|
||||
break
|
||||
}
|
||||
osyield()
|
||||
}
|
||||
|
||||
if _g_.m.waitsemacount != 0 {
|
||||
// semaphore is available.
|
||||
_g_.m.waitsemacount--
|
||||
// spin-mutex unlock
|
||||
atomicstore(&_g_.m.waitsemalock, 0)
|
||||
v := atomicload(&_g_.m.waitsemacount)
|
||||
if v > 0 {
|
||||
if cas(&_g_.m.waitsemacount, v, v-1) {
|
||||
return 0 // semaphore acquired
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// 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
|
||||
|
Loading…
Reference in New Issue
Block a user