]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: simplify OpenBSD semaphores
authorMatthew Dempsky <mdempsky@google.com>
Mon, 23 Feb 2015 08:05:30 +0000 (17:05 +0900)
committerJoel Sing <jsing@google.com>
Wed, 25 Feb 2015 02:30:11 +0000 (02:30 +0000)
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>
src/runtime/os1_openbsd.go
src/runtime/os_openbsd.go

index dcf205b84120cc5f4f86400b019307a338bb3c03..d23d812aced29efd88ccff8d9f8d854d1c545cdd 100644 (file)
@@ -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) {
index c1a55d64775e165ee06c957a8bbc0fe29f7ae6b6..8a97a738f770ece34a450391e7a5af36609bd519 100644 (file)
@@ -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