]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
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 | } |