github.com/aclements/go-misc@v0.0.0-20240129233631-2f6ede80790c/go-weave/models/markterm.go (about) 1 // Copyright 2016 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 5 // +build ignore 6 7 // markterm is a model for finding when mark termination can start 8 // before all work is drained in Go 1.7. This model is expected to 9 // fail. 10 package main 11 12 import ( 13 "fmt" 14 15 "github.com/aclements/go-misc/go-weave/amb" 16 "github.com/aclements/go-misc/go-weave/weave" 17 ) 18 19 var sched = weave.Scheduler{Strategy: &amb.StrategyRandom{}} 20 21 type State struct { 22 workers int 23 grey int 24 done bool 25 } 26 27 func main() { 28 sched.Run(func() { 29 var s State 30 s.grey = 3 31 32 for i := 0; i < 2; i++ { 33 sched.Go(s.worker) 34 } 35 }) 36 } 37 38 func (s *State) worker() { 39 // TODO: This has a liveness problem: if a worker takes the 40 // last work and then doesn't get scheduled again, the other 41 // worker will spin. Curiously, duplicate state detection 42 // would cut off that path, which means if we see a duplicate 43 // with an earlier state in the same path (versus a different 44 // path), it's a livelock and perhaps should be reported. 45 for { 46 s.workers++ 47 sched.Tracef("s.workers++ (%d)", s.workers) 48 sched.Sched() 49 50 s.check() 51 52 switch { 53 case s.grey <= 0: 54 // Do nothing 55 case s.grey == 1: 56 // Pull one pointer, put none. 57 s.grey-- 58 sched.Tracef("s.grey-- (%d)", s.grey) 59 sched.Sched() 60 default: 61 // Remove two pointers, then add one to simulate 62 // pulling a buffer off full and then putting one back 63 // one full. 64 s.grey -= 2 65 sched.Tracef("s.grey -= 2 (%d)", s.grey) 66 sched.Sched() 67 s.grey++ 68 sched.Tracef("s.grey++ (%d)", s.grey) 69 s.check() 70 sched.Sched() 71 } 72 73 var grey int 74 if true { // Read full list ("grey") before dec(&workers) 75 grey = s.grey 76 sched.Tracef("grey := s.grey (%d)", s.grey) 77 sched.Sched() 78 } 79 80 s.workers-- 81 n := s.workers 82 sched.Tracef("s.workers-- (%d)", s.workers) 83 sched.Sched() 84 85 if false { 86 grey = s.grey 87 sched.Tracef("grey := s.grey (%d)", s.grey) 88 sched.Sched() 89 } 90 91 if n == 0 && grey == 0 { 92 s.done = true 93 sched.Trace("s.done = true") 94 sched.Sched() 95 s.check() 96 break 97 } 98 } 99 sched.Trace("exit") 100 } 101 102 func (s *State) check() { 103 if s.done && s.grey > 0 { 104 panic(fmt.Sprintf("done, but grey==%d", s.grey)) 105 } 106 }