github.com/jmigpin/editor@v1.6.0/util/syncutil/waitforset.go (about) 1 package syncutil 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 ) 8 9 // Continously usable, instantiated once for many wait()/set() calls. Fails if wait() is not ready when set() is called. 10 // Usage: 11 // w:=NewWaitForSet() 12 // w.Start(5*time.Second) 13 // ... 14 // // sync/async call to w.Set() 15 // ... 16 // v,err := w.WaitForSet() 17 // if err!=nil { 18 // } 19 type WaitForSet struct { 20 d struct { 21 sync.Mutex 22 get struct { 23 timer *time.Timer 24 waiting bool 25 } 26 set struct { 27 gotV bool 28 v interface{} 29 } 30 } 31 cond *sync.Cond // signals from set() or timeout() 32 } 33 34 func NewWaitForSet() *WaitForSet { 35 w := &WaitForSet{} 36 w.cond = sync.NewCond(&w.d) 37 return w 38 } 39 40 //---------- 41 42 func (w *WaitForSet) Start(timeout time.Duration) { 43 w.d.Lock() 44 defer w.d.Unlock() 45 if w.d.get.timer != nil { 46 panic("waitforset: timer!=nil") 47 } 48 w.d.get.timer = time.AfterFunc(timeout, w.cond.Signal) 49 } 50 51 func (w *WaitForSet) WaitForSet() (interface{}, error) { 52 w.d.Lock() 53 defer w.d.Unlock() 54 defer w.clearTimer() 55 if w.d.get.timer == nil { 56 panic("waitforset: not started") 57 } 58 if w.d.get.waiting { 59 panic("waitforset: already waiting") 60 } 61 w.d.get.waiting = true 62 defer func() { w.d.get.waiting = false }() 63 64 // wait for signal if the value was not set yet 65 if !w.d.set.gotV { 66 w.cond.Wait() // wait for signal from set() or timeout start() 67 } 68 69 if w.d.set.gotV { 70 defer func() { w.d.set.gotV = false }() // reset for next run 71 return w.d.set.v, nil 72 } 73 return nil, fmt.Errorf("waitforset: timeout") 74 } 75 76 //---------- 77 78 // In case waitforset() is not going to be called. 79 func (w *WaitForSet) Cancel() { 80 w.d.Lock() 81 defer w.d.Unlock() 82 w.clearTimer() 83 } 84 85 func (w *WaitForSet) clearTimer() { 86 w.d.get.timer.Stop() 87 w.d.get.timer = nil 88 } 89 90 //---------- 91 92 // Fails if not able to set while get() is ready. 93 func (w *WaitForSet) Set(v interface{}) error { 94 w.d.Lock() 95 defer w.d.Unlock() 96 if w.d.get.timer == nil { 97 return fmt.Errorf("waitforset: not waiting for set") 98 } 99 w.d.set.gotV = true 100 w.d.set.v = v 101 w.cond.Signal() 102 return nil 103 }