futex-cooperative.mx raw

   1  //go:build moxie.unicore
   2  
   3  package task
   4  
   5  // A futex is a way for userspace to wait with the pointer as the key, and for
   6  // another thread to wake one or all waiting threads keyed on the same pointer.
   7  //
   8  // A futex does not change the underlying value, it only reads it before to prevent
   9  // lost wake-ups.
  10  type Futex struct {
  11  	Uint32
  12  	waiters Stack
  13  }
  14  
  15  // Atomically check for cmp to still be equal to the futex value and if so, go
  16  // to sleep. Return true if we were definitely awoken by a call to Wake or
  17  // WakeAll, and false if we can't be sure of that.
  18  func (f *Futex) Wait(cmp uint32) (awoken bool) {
  19  	if f.Uint32.v != cmp {
  20  		return false
  21  	}
  22  
  23  	// Push the current goroutine onto the waiter stack.
  24  	f.waiters.Push(Current())
  25  
  26  	// Spin on event loop until woken. Wake() pops from stack and
  27  	// sets RunState to RunStateResuming as a signal.
  28  	t := Current()
  29  	t.RunState = RunStatePaused
  30  	for t.RunState == RunStatePaused {
  31  		eventLoopTick()
  32  	}
  33  
  34  	return true
  35  }
  36  
  37  // Wake a single waiter.
  38  func (f *Futex) Wake() {
  39  	if t := f.waiters.Pop(); t != nil {
  40  		t.RunState = RunStateResuming
  41  		scheduleTask(t)
  42  	}
  43  }
  44  
  45  // Wake all waiters.
  46  func (f *Futex) WakeAll() {
  47  	for t := f.waiters.Pop(); t != nil; t = f.waiters.Pop() {
  48  		t.RunState = RunStateResuming
  49  		scheduleTask(t)
  50  	}
  51  }
  52