From c72307ffad42f25777e27df68d6147e75d761fce Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Jun 2012 18:11:03 +0200 Subject: REPL no longer hangs after initialization crashes --- .../scala/tools/nsc/interpreter/ILoop.scala | 2 +- .../scala/tools/nsc/interpreter/ILoopInit.scala | 32 +++++++++++++++++----- .../scala/tools/nsc/interpreter/IMain.scala | 1 + 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index de778e7469..d2e62e171e 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -554,7 +554,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) // return false if repl should exit def processLine(line: String): Boolean = { if (isAsync) { - awaitInitialized() + if (!awaitInitialized()) return false runThunks() } if (line eq null) false // assume null means EOF diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala index 9072eaae46..5bc2ee1278 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala @@ -44,6 +44,7 @@ trait ILoopInit { } // a condition used to ensure serial access to the compiler. @volatile private var initIsComplete = false + @volatile private var initError: String = null private def elapsed() = "%.3f".format((System.nanoTime - initStart).toDouble / 1000000000L) // the method to be called when the interpreter is initialized. @@ -63,9 +64,17 @@ trait ILoopInit { } // called from main repl loop - protected def awaitInitialized() { + protected def awaitInitialized(): Boolean = { if (!initIsComplete) withLock { while (!initIsComplete) initLoopCondition.await() } + if (initError != null) { + println(""" + |Failed to initialize the REPL due to an unexpected error. + |This is a bug, please, report it along with the error diagnostics printed below. + |%s.""".stripMargin.format(initError) + ) + false + } else true } // private def warningsThunks = List( // () => intp.bind("lastWarnings", "" + typeTag[List[(Position, String)]], intp.lastWarnings _), @@ -80,13 +89,22 @@ trait ILoopInit { // ) // called once after init condition is signalled protected def postInitialization() { - postInitThunks foreach (f => addThunk(f())) - runThunks() - initIsComplete = true + try { + postInitThunks foreach (f => addThunk(f())) + runThunks() + } catch { + case ex => + val message = new java.io.StringWriter() + ex.printStackTrace(new java.io.PrintWriter(message)) + initError = message.toString + throw ex + } finally { + initIsComplete = true - if (isAsync) { - asyncMessage("[info] total init time: " + elapsed() + " s.") - withLock(initLoopCondition.signal()) + if (isAsync) { + asyncMessage("[info] total init time: " + elapsed() + " s.") + withLock(initLoopCondition.signal()) + } } } // code to be executed only after the interpreter is initialized diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 956e282b26..c54b401f3f 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -149,6 +149,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends private def _initSources = List(new BatchSourceFile("", "class $repl_$init { }")) private def _initialize() = { try { + // [Eugene] todo. if this crashes, REPL will hang new _compiler.Run() compileSources _initSources _initializeComplete = true true -- cgit v1.2.3