From c41961c10aecbf12432c4fa329efa3910a771ef5 Mon Sep 17 00:00:00 2001 From: Allan Renucci Date: Thu, 15 Nov 2018 16:42:11 +0100 Subject: [PATCH] Fix #2275: Fix deadlock in @volatile lazy vals Apply patch suggested in #2276 --- docs/docs/reference/changed/lazy-vals-spec.md | 2 +- library/src/dotty/runtime/LazyVals.scala | 5 +++-- tests/run/i2275.scala | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 tests/run/i2275.scala diff --git a/docs/docs/reference/changed/lazy-vals-spec.md b/docs/docs/reference/changed/lazy-vals-spec.md index cb7cf9b0f4c5..9a48ebab5fc2 100644 --- a/docs/docs/reference/changed/lazy-vals-spec.md +++ b/docs/docs/reference/changed/lazy-vals-spec.md @@ -55,7 +55,7 @@ class Foo { LazyVals.wait4Notification(this, bitmap_offset, flag, ) case => retry = false - result = $target + result = value_0 } } result diff --git a/library/src/dotty/runtime/LazyVals.scala b/library/src/dotty/runtime/LazyVals.scala index 513311060e0c..e289aeb6f05a 100644 --- a/library/src/dotty/runtime/LazyVals.scala +++ b/library/src/dotty/runtime/LazyVals.scala @@ -43,7 +43,7 @@ object LazyVals { var retry = true while (retry) { val cur = get(t, offset) - if (STATE(cur, ord) == 1) retry = CAS(t, offset, cur, v, ord) + if (STATE(cur, ord) == 1) retry = !CAS(t, offset, cur, v, ord) else { // cur == 2, somebody is waiting on monitor if (CAS(t, offset, cur, v, ord)) { @@ -67,7 +67,8 @@ object LazyVals { else if (state == 2) { val monitor = getMonitor(t, ord) monitor.synchronized { - monitor.wait() + if (STATE(get(t, offset), ord) == 2) // make sure notification did not happen yet. + monitor.wait() } } else retry = false diff --git a/tests/run/i2275.scala b/tests/run/i2275.scala new file mode 100644 index 000000000000..9ba28a072462 --- /dev/null +++ b/tests/run/i2275.scala @@ -0,0 +1,19 @@ +object Test { + var count = 0 + + @volatile lazy val x: Int = { + if (count < 100) { + count += 1 + ??? + } + 1 + } + + def main(args: Array[String]): Unit = { + def fetchLazy(): Unit = try x catch { case _: Throwable => fetchLazy() } + + for (_ <- 0 until 10) { + new Thread(() => fetchLazy()).start() + } + } +}