summaryrefslogtreecommitdiff
path: root/src/library/scala/concurrent/SyncVar.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-01-26 00:21:02 +0000
committerPaul Phillips <paulp@improving.org>2011-01-26 00:21:02 +0000
commit3cf67d788a747191f78fce8150194b3c1c48e7be (patch)
tree6ebae922ffd01c31de673b374388d230ec5cabdc /src/library/scala/concurrent/SyncVar.scala
parent85e79881a01678b53293297e030fd71e83dfa374 (diff)
downloadscala-3cf67d788a747191f78fce8150194b3c1c48e7be.tar.gz
scala-3cf67d788a747191f78fce8150194b3c1c48e7be.tar.bz2
scala-3cf67d788a747191f78fce8150194b3c1c48e7be.zip
SyncVar should not swallow interrupts and shoul...
SyncVar should not swallow interrupts and should be robust against spurious wakeups. Closes #4094, review by prokopec. (What did you mean in your comment that it is vulnerable against the take method?)
Diffstat (limited to 'src/library/scala/concurrent/SyncVar.scala')
-rw-r--r--src/library/scala/concurrent/SyncVar.scala30
1 files changed, 22 insertions, 8 deletions
diff --git a/src/library/scala/concurrent/SyncVar.scala b/src/library/scala/concurrent/SyncVar.scala
index 123208cf8b..61f8188ab1 100644
--- a/src/library/scala/concurrent/SyncVar.scala
+++ b/src/library/scala/concurrent/SyncVar.scala
@@ -15,21 +15,35 @@ package scala.concurrent
* @version 1.0, 10/03/2003
*/
class SyncVar[A] {
- private var isDefined: Boolean = false
- private var value: A = _
+ @volatile private var isDefined: Boolean = false
+ @volatile private var value: A = _
def get = synchronized {
while (!isDefined) wait()
value
}
+ /** Like Object.wait but reports millis elapsed.
+ */
+ private def waitMeasuringElapsed(timeout: Long): Long = {
+ val start = System.currentTimeMillis
+ wait(timeout)
+ System.currentTimeMillis - start
+ }
+
def get(timeout: Long): Option[A] = synchronized {
- if (!isDefined) {
- try wait(timeout)
- catch { case _: InterruptedException => () }
- }
- if (isDefined) Some(value)
- else None
+ /** 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(timeout)
+ if (!isDefined && elapsed > 0)
+ rest -= elapsed
+ }
+ if (isDefined) Some(value)
+ else None
}
def take() = synchronized {