summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/actors/scala/actors/Actor.scala13
-rw-r--r--src/actors/scala/actors/ActorTask.scala6
-rw-r--r--src/actors/scala/actors/Reaction.scala8
-rw-r--r--src/actors/scala/actors/Reactor.scala37
-rw-r--r--src/actors/scala/actors/ReactorTask.scala23
-rw-r--r--src/actors/scala/actors/ReplyReactor.scala4
-rw-r--r--src/actors/scala/actors/ReplyReactorTask.scala6
-rw-r--r--src/actors/scala/actors/UncaughtException.scala31
-rw-r--r--test/files/jvm/actor-exceptions.check14
-rw-r--r--test/files/jvm/actor-exceptions.scala20
-rw-r--r--test/files/jvm/actor-executor.scala10
-rw-r--r--test/files/jvm/actor-link-getstate.check3
-rw-r--r--test/files/jvm/actor-link-getstate.scala7
13 files changed, 125 insertions, 57 deletions
diff --git a/src/actors/scala/actors/Actor.scala b/src/actors/scala/actors/Actor.scala
index 69e3bd243e..32b27d5e20 100644
--- a/src/actors/scala/actors/Actor.scala
+++ b/src/actors/scala/actors/Actor.scala
@@ -410,8 +410,8 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor {
}
} else super.startSearch(msg, replyTo, handler)
- private[actors] override def makeReaction(fun: () => Unit): Runnable =
- new ActorTask(this, fun)
+ private[actors] override def makeReaction(fun: () => Unit, handler: PartialFunction[Any, Any], msg: Any): Runnable =
+ new ActorTask(this, fun, handler, msg)
/**
* Receives a message from this actor's mailbox.
@@ -570,7 +570,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor {
// do nothing (timeout is handled instead)
}
else {
- val task = new Reaction(this, f, msg)
+ val task = new ActorTask(this, null, f, msg)
scheduler executeFromActor task
}
@@ -804,6 +804,13 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor {
case object TIMEOUT
+/** An `Exit` message (an instance of this class) is sent to an actor
+ * with `trapExit` set to `true` whenever one of its linked actors
+ * terminates.
+ *
+ * @param from the actor that terminated
+ * @param reason the reason that caused the actor to terminate
+ */
case class Exit(from: AbstractActor, reason: AnyRef)
/** <p>
diff --git a/src/actors/scala/actors/ActorTask.scala b/src/actors/scala/actors/ActorTask.scala
index cf4283f7de..bceea06072 100644
--- a/src/actors/scala/actors/ActorTask.scala
+++ b/src/actors/scala/actors/ActorTask.scala
@@ -17,7 +17,11 @@ package scala.actors
*
* @author Philipp Haller
*/
-private[actors] class ActorTask(actor: Actor, fun: () => Unit) extends ReplyReactorTask[Actor](actor, fun) {
+private[actors] class ActorTask(actor: Actor,
+ fun: () => Unit,
+ handler: PartialFunction[Any, Any],
+ msg: Any)
+ extends ReplyReactorTask(actor, fun, handler, msg) {
protected override def beginExecution() {
super.beginExecution()
diff --git a/src/actors/scala/actors/Reaction.scala b/src/actors/scala/actors/Reaction.scala
index 7ff9204363..5a6d9b643c 100644
--- a/src/actors/scala/actors/Reaction.scala
+++ b/src/actors/scala/actors/Reaction.scala
@@ -26,12 +26,8 @@ private[actors] class KillActorControl extends ControlThrowable
* @author Philipp Haller
*/
@deprecated("This class will be removed in a future release")
-class Reaction(a: Actor, f: PartialFunction[Any, Any], msg: Any) extends ActorTask(a, () => {
- if (f == null)
- a.act()
- else
- f(msg)
-}) {
+class Reaction(a: Actor, f: PartialFunction[Any, Any], msg: Any)
+extends ActorTask(a, if (f == null) (() => a.act()) else null, f, msg) {
def this(a: Actor) = this(a, null, null)
diff --git a/src/actors/scala/actors/Reactor.scala b/src/actors/scala/actors/Reactor.scala
index ecd7148da0..db43921056 100644
--- a/src/actors/scala/actors/Reactor.scala
+++ b/src/actors/scala/actors/Reactor.scala
@@ -114,29 +114,33 @@ trait Reactor[Msg >: Null] extends OutputChannel[Msg] with Combinators {
}
private[actors] def startSearch(msg: Msg, replyTo: OutputChannel[Any], handler: PartialFunction[Msg, Any]) =
- () => scheduler execute (makeReaction(() => {
+ () => scheduler execute makeReaction(() => {
val startMbox = new MQueue[Msg]("Start")
synchronized { startMbox.append(msg, replyTo) }
searchMailbox(startMbox, handler, true)
- }))
+ })
- private[actors] def makeReaction(fun: () => Unit): Runnable =
- new ReactorTask(this, fun)
+ private[actors] final def makeReaction(fun: () => Unit): Runnable =
+ makeReaction(fun, null, null)
+
+ /* This method is supposed to be overridden. */
+ private[actors] def makeReaction(fun: () => Unit, handler: PartialFunction[Msg, Any], msg: Msg): Runnable =
+ new ReactorTask(this, fun, handler, msg)
private[actors] def resumeReceiver(item: (Msg, OutputChannel[Any]), handler: PartialFunction[Msg, Any], onSameThread: Boolean) {
if (onSameThread)
- handler(item._1)
- else {
+ makeReaction(null, handler, item._1).run()
+ else
scheduleActor(handler, item._1)
- /* Here, we throw a SuspendActorControl to avoid
- terminating this actor when the current ReactorTask
- is finished.
- The SuspendActorControl skips the termination code
- in ReactorTask.
- */
- throw Actor.suspendException
- }
+ /* Here, we throw a SuspendActorControl to avoid
+ terminating this actor when the current ReactorTask
+ is finished.
+
+ The SuspendActorControl skips the termination code
+ in ReactorTask.
+ */
+ throw Actor.suspendException
}
def !(msg: Msg) {
@@ -210,9 +214,8 @@ trait Reactor[Msg >: Null] extends OutputChannel[Msg] with Combinators {
*
* never throws SuspendActorControl
*/
- private[actors] def scheduleActor(handler: PartialFunction[Msg, Any], msg: Msg) = {
- val fun = () => handler(msg): Unit
- scheduler executeFromActor makeReaction(fun)
+ private[actors] def scheduleActor(handler: PartialFunction[Msg, Any], msg: Msg) {
+ scheduler executeFromActor makeReaction(null, handler, msg)
}
def start(): Reactor[Msg] = synchronized {
diff --git a/src/actors/scala/actors/ReactorTask.scala b/src/actors/scala/actors/ReactorTask.scala
index 7d4409199a..ac809f04ff 100644
--- a/src/actors/scala/actors/ReactorTask.scala
+++ b/src/actors/scala/actors/ReactorTask.scala
@@ -21,7 +21,10 @@ import scala.concurrent.forkjoin.RecursiveAction
*
* @author Philipp Haller
*/
-private[actors] class ReactorTask[T >: Null <: TrackedReactor](var reactor: T, var fun: () => Any)
+private[actors] class ReactorTask[Msg >: Null](var reactor: Reactor[Msg],
+ var fun: () => Any,
+ var handler: PartialFunction[Msg, Any],
+ var msg: Msg)
extends RecursiveAction with Callable[Unit] with Runnable {
def run() {
@@ -29,7 +32,10 @@ private[actors] class ReactorTask[T >: Null <: TrackedReactor](var reactor: T, v
beginExecution()
try {
try {
- fun()
+ if (fun eq null)
+ handler(msg)
+ else
+ fun()
} catch {
case e: Exception if (reactor.exceptionHandler.isDefinedAt(e)) =>
reactor.exceptionHandler(e)
@@ -44,14 +50,21 @@ private[actors] class ReactorTask[T >: Null <: TrackedReactor](var reactor: T, v
// do nothing (continuation is already saved)
case e: Exception =>
- Debug.info(reactor+": caught "+e)
- Debug.doInfo { e.printStackTrace() }
+ // print message on default error stream
+ val msgException = "Uncaught exception in "+reactor+"\n"
+ val msgMessage = if (msg != null) "Message: "+msg+"\n" else ""
+ Console.err.print(msgException + msgMessage)
+ e.printStackTrace()
+
+ val uncaught = new UncaughtException(reactor, if (msg != null) Some(msg) else None, currentThread, e)
reactor.terminated()
- terminateExecution(e)
+ terminateExecution(uncaught)
} finally {
suspendExecution()
this.reactor = null
this.fun = null
+ this.handler = null
+ this.msg = null
}
}
diff --git a/src/actors/scala/actors/ReplyReactor.scala b/src/actors/scala/actors/ReplyReactor.scala
index 196f7b1f4c..c933c43cf2 100644
--- a/src/actors/scala/actors/ReplyReactor.scala
+++ b/src/actors/scala/actors/ReplyReactor.scala
@@ -106,8 +106,8 @@ trait ReplyReactor extends Reactor[Any] with ReplyableReactor {
}
}
- private[actors] override def makeReaction(fun: () => Unit): Runnable =
- new ReplyReactorTask(this, fun)
+ private[actors] override def makeReaction(fun: () => Unit, handler: PartialFunction[Any, Any], msg: Any): Runnable =
+ new ReplyReactorTask(this, fun, handler, msg)
protected[actors] override def react(handler: PartialFunction[Any, Unit]): Nothing = {
assert(Actor.rawSelf(scheduler) == this, "react on channel belonging to other actor")
diff --git a/src/actors/scala/actors/ReplyReactorTask.scala b/src/actors/scala/actors/ReplyReactorTask.scala
index 2ad0884166..59150276c0 100644
--- a/src/actors/scala/actors/ReplyReactorTask.scala
+++ b/src/actors/scala/actors/ReplyReactorTask.scala
@@ -16,7 +16,11 @@ package scala.actors
*
* @author Philipp Haller
*/
-private[actors] class ReplyReactorTask[T >: Null <: ReplyReactor](reactor: T, fun: () => Unit) extends ReactorTask[ReplyReactor](reactor, fun) {
+private[actors] class ReplyReactorTask(reactor: ReplyReactor,
+ fun: () => Unit,
+ handler: PartialFunction[Any, Any],
+ msg: Any)
+ extends ReactorTask(reactor, fun, handler, msg) {
var saved: ReplyReactor = _
diff --git a/src/actors/scala/actors/UncaughtException.scala b/src/actors/scala/actors/UncaughtException.scala
new file mode 100644
index 0000000000..30043465a1
--- /dev/null
+++ b/src/actors/scala/actors/UncaughtException.scala
@@ -0,0 +1,31 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2005-2010, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.actors
+
+/**
+ * The exit reason when an actor fails to catch an exception.
+ *
+ * @param actor the actor that threw the exception
+ * @param message the message the actor was processing, or None if no message (e.g. on initial startup)
+ * @param thread the thread on which the actor was running
+ * @param cause the uncaught exception
+ *
+ * @author Philipp Haller
+ * @author Erik Engbrecht
+ */
+class UncaughtException[Msg >: Null](val actor: Reactor[Msg],
+ val message: Option[Msg],
+ val thread: Thread,
+ cause: Exception)
+extends Exception(cause) {
+
+ override def toString() =
+ "UncaughtException("+actor+","+message+","+cause+")"
+
+}
diff --git a/test/files/jvm/actor-exceptions.check b/test/files/jvm/actor-exceptions.check
index 021ccea1f1..bd44b968cc 100644
--- a/test/files/jvm/actor-exceptions.check
+++ b/test/files/jvm/actor-exceptions.check
@@ -1,11 +1,3 @@
-problem
-received A
-problem
-received A
-problem
-received A
-problem
-received A
-problem
-received last A
-slave exited because of java.lang.Exception: unhandled
+Uncaught exception in Slave
+Message: A
+MyOtherException
diff --git a/test/files/jvm/actor-exceptions.scala b/test/files/jvm/actor-exceptions.scala
index ccec84c56c..77bf05c048 100644
--- a/test/files/jvm/actor-exceptions.scala
+++ b/test/files/jvm/actor-exceptions.scala
@@ -2,7 +2,13 @@
import scala.actors.{Actor, Exit}
import Actor._
-case class MyException(text: String) extends Exception
+case class MyException(text: String) extends Exception {
+ override def fillInStackTrace() = this
+}
+
+case class MyOtherException(text: String) extends Exception {
+ override def fillInStackTrace() = this
+}
object Master extends Actor {
trapExit = true
@@ -11,14 +17,15 @@ object Master extends Actor {
Slave.start()
for (i <- 0 until 10) Slave ! A
react {
- case Exit(from, reason) => println("slave exited because of "+reason)
+ case Exit(from, reason) =>
}
}
}
object Slave extends Actor {
+ override def toString = "Slave"
override def exceptionHandler: PartialFunction[Exception, Unit] = {
- case MyException(text) => println(text)
+ case MyException(text) =>
}
def act() {
var cnt = 0
@@ -27,11 +34,8 @@ object Slave extends Actor {
case A =>
cnt += 1
if (cnt % 2 != 0) throw MyException("problem")
- if (cnt < 10)
- println("received A")
- else {
- println("received last A")
- throw new Exception("unhandled")
+ if (cnt == 10) {
+ throw new MyOtherException("unhandled")
}
}
}
diff --git a/test/files/jvm/actor-executor.scala b/test/files/jvm/actor-executor.scala
index e650043382..435c666fff 100644
--- a/test/files/jvm/actor-executor.scala
+++ b/test/files/jvm/actor-executor.scala
@@ -47,9 +47,15 @@ object Test {
val scheduler =
new SchedulerAdapter {
def execute(block: => Unit) {
- executor.execute(new Runnable {
+ val task = new Runnable {
def run() { block }
- })
+ }
+ try {
+ executor.execute(task)
+ } catch {
+ case ree: java.util.concurrent.RejectedExecutionException =>
+ task.run()
+ }
}
}
diff --git a/test/files/jvm/actor-link-getstate.check b/test/files/jvm/actor-link-getstate.check
index 9755447320..45967222e6 100644
--- a/test/files/jvm/actor-link-getstate.check
+++ b/test/files/jvm/actor-link-getstate.check
@@ -1,2 +1,5 @@
Done
+Uncaught exception in Master
+Message: 'done
+MyException: Master crashed
Terminated
diff --git a/test/files/jvm/actor-link-getstate.scala b/test/files/jvm/actor-link-getstate.scala
index 955ea45499..cdfc8d6310 100644
--- a/test/files/jvm/actor-link-getstate.scala
+++ b/test/files/jvm/actor-link-getstate.scala
@@ -1,6 +1,10 @@
import scala.actors.{Actor, Exit}
import scala.actors.Actor._
+case class MyException(text: String) extends Exception(text) {
+ override def fillInStackTrace() = this
+}
+
object Slave extends Actor {
def act() {
loop {
@@ -14,12 +18,13 @@ object Slave extends Actor {
}
object Master extends Actor {
+ override def toString = "Master"
def act() {
link(Slave)
Slave ! 'doWork
react {
case 'done =>
- throw new Exception("Master crashed")
+ throw new MyException("Master crashed")
}
}
}