github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/utils/voyeur/value.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // Package voyeur implements a concurrency-safe value that can be watched for 5 // changes. 6 package voyeur 7 8 import ( 9 "sync" 10 ) 11 12 // Value represents a shared value that can be watched for changes. Methods on 13 // a Value may be called concurrently. The zero Value is 14 // ok to use, and is equivalent to a NewValue result 15 // with a nil initial value. 16 type Value struct { 17 val interface{} 18 version int 19 mu sync.RWMutex 20 wait sync.Cond 21 closed bool 22 } 23 24 // NewValue creates a new Value holding the given initial value. If initial is 25 // nil, any watchers will wait until a value is set. 26 func NewValue(initial interface{}) *Value { 27 v := new(Value) 28 v.init() 29 if initial != nil { 30 v.val = initial 31 v.version++ 32 } 33 return v 34 } 35 36 func (v *Value) needsInit() bool { 37 return v.wait.L == nil 38 } 39 40 func (v *Value) init() { 41 if v.needsInit() { 42 v.wait.L = v.mu.RLocker() 43 } 44 } 45 46 // Set sets the shared value to val. 47 func (v *Value) Set(val interface{}) { 48 v.mu.Lock() 49 v.init() 50 v.val = val 51 v.version++ 52 v.mu.Unlock() 53 v.wait.Broadcast() 54 } 55 56 // Close closes the Value, unblocking any outstanding watchers. Close always 57 // returns nil. 58 func (v *Value) Close() error { 59 v.mu.Lock() 60 v.init() 61 v.closed = true 62 v.mu.Unlock() 63 v.wait.Broadcast() 64 return nil 65 } 66 67 // Closed reports whether the value has been closed. 68 func (v *Value) Closed() bool { 69 v.mu.RLock() 70 defer v.mu.RUnlock() 71 return v.closed 72 } 73 74 // Get returns the current value. 75 func (v *Value) Get() interface{} { 76 v.mu.RLock() 77 defer v.mu.RUnlock() 78 return v.val 79 } 80 81 // Watch returns a Watcher that can be used to watch for changes to the value. 82 func (v *Value) Watch() *Watcher { 83 return &Watcher{value: v} 84 } 85 86 // Watcher represents a single watcher of a shared value. 87 type Watcher struct { 88 value *Value 89 version int 90 current interface{} 91 closed bool 92 } 93 94 // Next blocks until there is a new value to be retrieved from the value that is 95 // being watched. It also unblocks when the value or the Watcher itself is 96 // closed. Next returns false if the value or the Watcher itself have been 97 // closed. 98 func (w *Watcher) Next() bool { 99 val := w.value 100 val.mu.RLock() 101 defer val.mu.RUnlock() 102 if val.needsInit() { 103 val.mu.RUnlock() 104 val.mu.Lock() 105 val.init() 106 val.mu.Unlock() 107 val.mu.RLock() 108 } 109 110 // We can go around this loop a maximum of two times, 111 // because the only thing that can cause a Wait to 112 // return is for the condition to be triggered, 113 // which can only happen if the value is set (causing 114 // the version to increment) or it is closed 115 // causing the closed flag to be set. 116 // Both these cases will cause Next to return. 117 for { 118 if w.version != val.version { 119 w.version = val.version 120 w.current = val.val 121 return true 122 } 123 if val.closed || w.closed { 124 return false 125 } 126 127 // Wait releases the lock until triggered and then reacquires the lock, 128 // thus avoiding a deadlock. 129 val.wait.Wait() 130 } 131 } 132 133 // Close closes the Watcher without closing the underlying 134 // value. It may be called concurrently with Next. 135 func (w *Watcher) Close() { 136 w.value.mu.Lock() 137 w.value.init() 138 w.closed = true 139 w.value.mu.Unlock() 140 w.value.wait.Broadcast() 141 } 142 143 // Value returns the last value that was retrieved from the watched Value by 144 // Next. 145 func (w *Watcher) Value() interface{} { 146 return w.current 147 }