summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-07-25 15:58:45 +0200
committerMartin Odersky <odersky@gmail.com>2012-07-27 17:04:36 +0200
commite896c0ab2d36740207f91086262e9feb4fc1c32d (patch)
treea5bd5892b7a0cdcd1f5353757af640f2da7919b9
parent50903959efc2dcc4093f3d7c0b4b9b9def51cc04 (diff)
downloadscala-e896c0ab2d36740207f91086262e9feb4fc1c32d.tar.gz
scala-e896c0ab2d36740207f91086262e9feb4fc1c32d.tar.bz2
scala-e896c0ab2d36740207f91086262e9feb4fc1c32d.zip
Adds method askForResponse
Adds method askForResponse which returns a response immediately instead of waiting for a result. That way, one can wait for an ask's result using a timeout.
-rw-r--r--src/compiler/scala/tools/nsc/interactive/CompilerControl.scala15
-rw-r--r--src/compiler/scala/tools/nsc/util/InterruptReq.scala11
-rw-r--r--src/compiler/scala/tools/nsc/util/WorkScheduler.scala7
3 files changed, 31 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
index 801b4ad22b..aab1c8fb7e 100644
--- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
+++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
@@ -252,6 +252,19 @@ trait CompilerControl { self: Global =>
/** Asks for a computation to be done quickly on the presentation compiler thread */
def ask[A](op: () => A): A = if (self.onCompilerThread) op() else scheduler doQuickly op
+ /** Asks for a computation to be done on presentation compiler thread, returning
+ * a response with the result or an exception
+ */
+ def askForResponse[A](op: () => A): Response[A] = {
+ val r = new Response[A]
+ val ir = scheduler askDoQuickly op
+ ir onComplete {
+ case Left(result) => r set result
+ case Right(exc) => r raise exc
+ }
+ r
+ }
+
def onCompilerThread = Thread.currentThread == compileRunner
/** Info given for every member found by completion
@@ -390,7 +403,7 @@ trait CompilerControl { self: Global =>
case _ => println("don't know what to do with this " + action.getClass)
}
}
-
+
override def doQuickly[A](op: () => A): A = {
throw new FailedInterrupt(new Exception("Posted a work item to a compiler that's shutting down"))
}
diff --git a/src/compiler/scala/tools/nsc/util/InterruptReq.scala b/src/compiler/scala/tools/nsc/util/InterruptReq.scala
index 61aaa1bdcb..816d16f767 100644
--- a/src/compiler/scala/tools/nsc/util/InterruptReq.scala
+++ b/src/compiler/scala/tools/nsc/util/InterruptReq.scala
@@ -2,6 +2,7 @@ package scala.tools.nsc
package util
/** A class of work items to be used in interrupt requests.
+ * Todo: we should replace the Eithers by Futures or Try's.
*/
abstract class InterruptReq {
/** The result type of the operation
@@ -11,9 +12,14 @@ abstract class InterruptReq {
/** The operation to be performed */
protected val todo: () => R
+ type Continuation = Either[R, Throwable] => Unit
+
/** The result provided */
private var result: Option[Either[R, Throwable]] = None
+ /** The continuations waiting asynchronously on a provided result */
+ private var waiting: List[Continuation] = Nil
+
/** To be called from interrupted server to execute demanded task */
def execute(): Unit = synchronized {
try {
@@ -22,6 +28,7 @@ abstract class InterruptReq {
case t: Throwable => result = Some(Right(t))
} finally {
notify()
+ for (k <- waiting.reverse) k(result.get)
}
}
@@ -38,6 +45,10 @@ abstract class InterruptReq {
case Right(t) => throw new FailedInterrupt(t)
}
}
+
+ def onComplete(k: Continuation) = synchronized {
+ waiting = k :: waiting
+ }
}
class FailedInterrupt(cause: Throwable) extends Exception("Compiler exception during call to 'ask'", cause)
diff --git a/src/compiler/scala/tools/nsc/util/WorkScheduler.scala b/src/compiler/scala/tools/nsc/util/WorkScheduler.scala
index 8c037cbda5..b1f4696d3e 100644
--- a/src/compiler/scala/tools/nsc/util/WorkScheduler.scala
+++ b/src/compiler/scala/tools/nsc/util/WorkScheduler.scala
@@ -54,6 +54,11 @@ class WorkScheduler {
/** Called from client: have interrupt executed by server and return result */
def doQuickly[A](op: () => A): A = {
+ val ir = askDoQuickly(op)
+ ir.getResult()
+ }
+
+ def askDoQuickly[A](op: () => A): InterruptReq { type R = A } = {
val ir = new InterruptReq {
type R = A
val todo = op
@@ -62,7 +67,7 @@ class WorkScheduler {
interruptReqs enqueue ir
notify()
}
- ir.getResult()
+ ir
}
/** Called from client: have action executed by server */