diff options
author | Paul Phillips <paulp@improving.org> | 2011-01-26 00:21:02 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-01-26 00:21:02 +0000 |
commit | 3cf67d788a747191f78fce8150194b3c1c48e7be (patch) | |
tree | 6ebae922ffd01c31de673b374388d230ec5cabdc /src/library | |
parent | 85e79881a01678b53293297e030fd71e83dfa374 (diff) | |
download | scala-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')
-rw-r--r-- | src/library/scala/concurrent/SyncVar.scala | 30 |
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 { |