1// Copyright 2011 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package runtime 6 7import ( 8 "runtime/internal/atomic" 9 "unsafe" 10) 11 12type mOS struct { 13 waitsemacount uint32 14} 15 16//go:noescape 17//extern thrsleep 18func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 19 20//go:noescape 21//extern thrwakeup 22func thrwakeup(ident uintptr, n int32) int32 23 24//go:nosplit 25func semacreate(mp *m) { 26} 27 28//go:nosplit 29func semasleep(ns int64) int32 { 30 _g_ := getg() 31 32 // Compute sleep deadline. 33 var tsp *timespec 34 if ns >= 0 { 35 var ts timespec 36 var nsec int32 37 ns += nanotime() 38 ts.set_sec(int64(timediv(ns, 1000000000, &nsec))) 39 ts.set_nsec(nsec) 40 tsp = &ts 41 } 42 43 for { 44 v := atomic.Load(&_g_.m.mos.waitsemacount) 45 if v > 0 { 46 if atomic.Cas(&_g_.m.mos.waitsemacount, v, v-1) { 47 return 0 // semaphore acquired 48 } 49 continue 50 } 51 52 // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0. 53 // 54 // From OpenBSD's __thrsleep(2) manual: 55 // "The abort argument, if not NULL, points to an int that will 56 // be examined [...] immediately before blocking. If that int 57 // is non-zero then __thrsleep() will immediately return EINTR 58 // without blocking." 59 ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.mos.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.mos.waitsemacount) 60 if ret == _EWOULDBLOCK { 61 return -1 62 } 63 } 64} 65 66//go:nosplit 67func semawakeup(mp *m) { 68 atomic.Xadd(&mp.mos.waitsemacount, 1) 69 ret := thrwakeup(uintptr(unsafe.Pointer(&mp.mos.waitsemacount)), 1) 70 if ret != 0 && ret != _ESRCH { 71 // semawakeup can be called on signal stack. 72 systemstack(func() { 73 print("thrwakeup addr=", &mp.mos.waitsemacount, " sem=", mp.mos.waitsemacount, " ret=", ret, "\n") 74 }) 75 } 76} 77