github.com/icexin/eggos@v0.4.2-0.20220216025428-78b167e4f349/kernel/lock.go (about) 1 package kernel 2 3 import ( 4 "unsafe" 5 6 "gvisor.dev/gvisor/pkg/abi/linux" 7 ) 8 9 const ( 10 _FUTEX_WAIT = 0 11 _FUTEX_WAKE = 1 12 _FUTEX_PRIVATE_FLAG = 128 13 _FUTEX_WAIT_PRIVATE = _FUTEX_WAIT | _FUTEX_PRIVATE_FLAG 14 _FUTEX_WAKE_PRIVATE = _FUTEX_WAKE | _FUTEX_PRIVATE_FLAG 15 ) 16 17 //go:nosplit 18 func futex(addr *uintptr, op, val uintptr, ts *linux.Timespec) { 19 switch op { 20 case _FUTEX_WAIT, _FUTEX_WAIT_PRIVATE: 21 if ts != nil { 22 sleeptimeout(addr, val, ts) 23 return 24 } 25 for *addr == val { 26 sleepon(addr) 27 } 28 return 29 case _FUTEX_WAKE, _FUTEX_WAKE_PRIVATE: 30 wakeup(addr, int(val)) 31 default: 32 panic("futex: invalid op") 33 } 34 } 35 36 //go:nosplit 37 func sleeptimeout(addr *uintptr, val uintptr, ts *linux.Timespec) { 38 if ts == nil { 39 panic("sleeptimeout: nil ts") 40 } 41 deadline := nanosecond() + int64(ts.Nsec) + int64(ts.Sec)*second 42 // check on every timer intr 43 now := nanosecond() 44 t := Mythread() 45 for now < deadline && *addr == val { 46 t.timerKey = uintptr(unsafe.Pointer(&sleeplock)) 47 t.sleepKey = uintptr(unsafe.Pointer(addr)) 48 t.state = SLEEPING 49 Sched() 50 t.timerKey = 0 51 t.sleepKey = 0 52 now = nanosecond() 53 } 54 } 55 56 //go:nosplit 57 func sleepon(lock *uintptr) { 58 t := Mythread() 59 t.sleepKey = uintptr(unsafe.Pointer(lock)) 60 t.state = SLEEPING 61 Sched() 62 t.sleepKey = 0 63 } 64 65 // wakeup thread sleep on lock, n == -1 means all threads 66 //go:nosplit 67 func wakeup(lock *uintptr, n int) { 68 limit := uint(n) 69 cnt := uint(0) 70 lockKey := uintptr(unsafe.Pointer(lock)) 71 for i := 0; i < _NTHREDS; i++ { 72 t := &threads[i] 73 if (t.sleepKey == lockKey || t.timerKey == lockKey) && cnt < limit { 74 cnt++ 75 t.state = RUNNABLE 76 } 77 } 78 } 79 80 type note uintptr 81 82 //go:nosplit 83 func (n *note) sleep(ts *linux.Timespec) { 84 futex((*uintptr)(unsafe.Pointer(n)), _FUTEX_WAIT, 0, ts) 85 } 86 87 //go:nosplit 88 func (n *note) wakeup() { 89 *n = 1 90 futex((*uintptr)(unsafe.Pointer(n)), _FUTEX_WAKE, 1, nil) 91 } 92 93 //go:nosplit 94 func (n *note) clear() { 95 *n = 0 96 }