main.mx raw

   1  // The ring index word is the parking word (L21). Two properties are owed by
   2  // any parking scheme, and both are asserted here:
   3  //
   4  //   - no lost wakeup: a receiver parked on the write index is woken by the
   5  //     publish, so a ping-pong over a spawn channel completes every round;
   6  //   - no hang on peer death: a parent parked on a ring whose child died
   7  //     unpacks (bounded wait, then a liveness recheck) and reports the closed
   8  //     channel rather than sleeping forever.
   9  package main
  10  
  11  import (
  12  	"fmt"
  13  	"runtime"
  14  	"time"
  15  )
  16  
  17  // echoWorker receives each value and answers with twice it, so the parent can
  18  // tell that the parked receive actually woke. It parks on `in` between
  19  // messages: that park is the wakeup the test is about.
  20  func echoWorker(in chan int32, out chan int32) {
  21  	for {
  22  		v, ok := <-in
  23  		if !ok {
  24  			return
  25  		}
  26  		out <- v * 2
  27  	}
  28  }
  29  
  30  // deadWorker returns without ever writing out, so its parent parks on out and
  31  // then has to notice the peer died.
  32  func deadWorker(in chan int32, out chan int32) {
  33  	time.Sleep(50 * time.Millisecond)
  34  }
  35  
  36  func main() {
  37  	// Chan memory must outlive this frame: the forked child reads the same
  38  	// channel memory, so allocate it in the root arena.
  39  	runtime.SovereignSetArena(runtime.RootArena())
  40  	in := chan int32{}
  41  	out := chan int32{}
  42  	done := spawn(echoWorker, in, out)
  43  
  44  	// 200 rounds: each one parks the worker on `in`, publishes, and requires
  45  	// the reply. If a wake were lost the round would stall until the bounded
  46  	// park timed out and the test would eventually fail on the value.
  47  	for i := int32(0); i < 200; i++ {
  48  		in <- i
  49  		v := <-out
  50  		if v != i*2 {
  51  			panic("echo value mismatch")
  52  		}
  53  	}
  54  	close(in)
  55  	<-done
  56  	fmt.Println("wake ok")
  57  
  58  	runtime.SovereignSetArena(runtime.RootArena())
  59  	in2 := chan int32{}
  60  	out2 := chan int32{}
  61  	done2 := spawn(deadWorker, in2, out2)
  62  
  63  	start := time.Now()
  64  	dv, ok := <-out2
  65  	elapsed := time.Since(start)
  66  	_ = dv
  67  	if ok {
  68  		panic("recv reported a value after the peer died")
  69  	}
  70  	if elapsed > 3*time.Second {
  71  		panic("recv did not unpark promptly after the peer died")
  72  	}
  73  	<-done2
  74  	fmt.Println("dead ok")
  75  }
  76