github.com/jspc/eggos@v0.5.1-0.20221028160421-556c75c878a5/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  }