From 3cf67d788a747191f78fce8150194b3c1c48e7be Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 26 Jan 2011 00:21:02 +0000 Subject: 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?) --- src/library/scala/concurrent/SyncVar.scala | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'src') 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 { -- cgit v1.2.3