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  }