1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */
package scala.concurrent
import java.util.concurrent.TimeUnit
/** A class to provide safe concurrent access to a mutable cell.
* All methods are synchronized.
*
* @tparam A type of the contained value
* @author Martin Odersky
* @version 1.0, 10/03/2003
*/
class SyncVar[A] {
private var isDefined: Boolean = false
private var value: A = _
/**
* Wait for this SyncVar to become defined and then get
* the stored value without modifying it.
*
* @return value that is held in this container
*/
def get: A = synchronized {
while (!isDefined) wait()
value
}
/** Waits `timeout` millis. If `timeout <= 0` just returns 0.
* It never returns negative results.
*/
private def waitMeasuringElapsed(timeout: Long): Long = if (timeout <= 0) 0 else {
val start = System.nanoTime()
wait(timeout)
val elapsed = System.nanoTime() - start
// nanoTime should be monotonic, but it's not possible to rely on that.
// See http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6458294.
if (elapsed < 0) 0 else TimeUnit.NANOSECONDS.toMillis(elapsed)
}
/** Wait at least `timeout` milliseconds (possibly more) for this `SyncVar`
* to become defined and then get its value.
*
* @param timeout time in milliseconds to wait
* @return `None` if variable is undefined after `timeout`, `Some(value)` otherwise
*/
def get(timeout: Long): Option[A] = synchronized {
/* Defending against the system clock going backward
* by counting time elapsed directly. Loop required
* to deal with spurious wakeups.
*/
var rest = timeout
while (!isDefined && rest > 0) {
val elapsed = waitMeasuringElapsed(rest)
rest -= elapsed
}
if (isDefined) Some(value) else None
}
/**
* Wait for this SyncVar to become defined and then get
* the stored value, unsetting it as a side effect.
*
* @return value that was held in this container
*/
def take(): A = synchronized {
try get
finally unsetVal()
}
/** Wait at least `timeout` milliseconds (possibly more) for this `SyncVar`
* to become defined and then get the stored value, unsetting it
* as a side effect.
*
* @param timeout the amount of milliseconds to wait
* @return the value or a throws an exception if the timeout occurs
* @throws NoSuchElementException on timeout
*/
def take(timeout: Long): A = synchronized {
try get(timeout).get
finally unsetVal()
}
// TODO: this method should be private
// [Heather] the reason why: it doesn't take into consideration
// whether or not the SyncVar is already defined. So, set has been
// deprecated in order to eventually be able to make "setting" private
@deprecated("use `put` instead, as `set` is potentially error-prone", "2.10.0")
// NOTE: Used by SBT 0.13.0-M2 and below
def set(x: A): Unit = setVal(x)
/** Place a value in the SyncVar. If the SyncVar already has a stored value,
* wait until another thread takes it. */
def put(x: A): Unit = synchronized {
while (isDefined) wait()
setVal(x)
}
/** Check whether a value is stored in the synchronized variable. */
def isSet: Boolean = synchronized {
isDefined
}
// TODO: this method should be private
// [Heather] the reason why: it doesn't take into consideration
// whether or not the SyncVar is already defined. So, unset has been
// deprecated in order to eventually be able to make "unsetting" private
@deprecated("use `take` instead, as `unset` is potentially error-prone", "2.10.0")
// NOTE: Used by SBT 0.13.0-M2 and below
def unset(): Unit = synchronized {
isDefined = false
value = null.asInstanceOf[A]
notifyAll()
}
// `setVal` exists so as to retroactively deprecate `set` without
// deprecation warnings where we use `set` internally. The
// implementation of `set` was moved to `setVal` to achieve this
private def setVal(x: A): Unit = synchronized {
isDefined = true
value = x
notifyAll()
}
// `unsetVal` exists so as to retroactively deprecate `unset` without
// deprecation warnings where we use `unset` internally. The
// implementation of `unset` was moved to `unsetVal` to achieve this
private def unsetVal(): Unit = synchronized {
isDefined = false
value = null.asInstanceOf[A]
notifyAll()
}
}
|