github.com/candidpartners/terraform@v0.9.5-0.20171005231213-29f5f88820f6/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 // Close closes the value. This can never fail. For a definition of 30 // "close" see the struct docs. 31 func (w *Value) Close() error { 32 w.lock.Lock() 33 set := w.valueSet 34 w.lock.Unlock() 35 36 // If we haven't set the value, set it 37 if !set { 38 w.SetValue(ErrClosed) 39 } 40 41 // Done 42 return nil 43 } 44 45 // Value returns the value that was set. 46 func (w *Value) Value() interface{} { 47 w.lock.Lock() 48 defer w.lock.Unlock() 49 50 // If we already have a value just return 51 for !w.valueSet { 52 // No value, setup the condition variable if we have to 53 if w.cond == nil { 54 w.cond = sync.NewCond(&w.lock) 55 } 56 57 // Wait on it 58 w.cond.Wait() 59 } 60 61 // Return the value 62 return w.value 63 } 64 65 // SetValue sets the value. 66 func (w *Value) SetValue(v interface{}) { 67 w.lock.Lock() 68 defer w.lock.Unlock() 69 70 // Set the value 71 w.valueSet = true 72 w.value = v 73 74 // If we have a condition, clear it 75 if w.cond != nil { 76 w.cond.Broadcast() 77 w.cond = nil 78 } 79 }