github.com/hs0210/hashicorp-terraform@v0.11.12-beta1/helper/shadow/value.go (about) 1 package shadow 2 3 import ( 4 "errors" 5 "sync" 6 ) 7 8 // ErrClosed is returned by any closed values. 9 // 10 // A "closed value" is when the shadow has been notified that the real 11 // side is complete and any blocking values will _never_ be satisfied 12 // in the future. In this case, this error is returned. If a value is already 13 // available, that is still returned. 14 var ErrClosed = errors.New("shadow closed") 15 16 // Value is a struct that coordinates a value between two 17 // parallel routines. It is similar to atomic.Value except that when 18 // Value is called if it isn't set it will wait for it. 19 // 20 // The Value can be closed with Close, which will cause any future 21 // blocking operations to return immediately with ErrClosed. 22 type Value struct { 23 lock sync.Mutex 24 cond *sync.Cond 25 value interface{} 26 valueSet bool 27 } 28 29 func (v *Value) Lock() { 30 v.lock.Lock() 31 } 32 33 func (v *Value) Unlock() { 34 v.lock.Unlock() 35 } 36 37 // Close closes the value. This can never fail. For a definition of 38 // "close" see the struct docs. 39 func (w *Value) Close() error { 40 w.lock.Lock() 41 set := w.valueSet 42 w.lock.Unlock() 43 44 // If we haven't set the value, set it 45 if !set { 46 w.SetValue(ErrClosed) 47 } 48 49 // Done 50 return nil 51 } 52 53 // Value returns the value that was set. 54 func (w *Value) Value() interface{} { 55 w.lock.Lock() 56 defer w.lock.Unlock() 57 58 // If we already have a value just return 59 for !w.valueSet { 60 // No value, setup the condition variable if we have to 61 if w.cond == nil { 62 w.cond = sync.NewCond(&w.lock) 63 } 64 65 // Wait on it 66 w.cond.Wait() 67 } 68 69 // Return the value 70 return w.value 71 } 72 73 // SetValue sets the value. 74 func (w *Value) SetValue(v interface{}) { 75 w.lock.Lock() 76 defer w.lock.Unlock() 77 78 // Set the value 79 w.valueSet = true 80 w.value = v 81 82 // If we have a condition, clear it 83 if w.cond != nil { 84 w.cond.Broadcast() 85 w.cond = nil 86 } 87 }