From 361799635196b1e2cc5dfdea569252cba3aa9ee1 Mon Sep 17 00:00:00 2001 From: Philipp Haller Date: Wed, 24 Mar 2010 17:29:59 +0000 Subject: Addresses see #2017. --- src/actors/scala/actors/Actor.scala | 13 +++++++-- src/actors/scala/actors/ActorTask.scala | 6 +++- src/actors/scala/actors/Reaction.scala | 8 ++---- src/actors/scala/actors/Reactor.scala | 37 +++++++++++++------------ src/actors/scala/actors/ReactorTask.scala | 23 +++++++++++---- src/actors/scala/actors/ReplyReactor.scala | 4 +-- src/actors/scala/actors/ReplyReactorTask.scala | 6 +++- src/actors/scala/actors/UncaughtException.scala | 31 +++++++++++++++++++++ 8 files changed, 93 insertions(+), 35 deletions(-) create mode 100644 src/actors/scala/actors/UncaughtException.scala (limited to 'src/actors') 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) /**

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+")" + +} -- cgit v1.2.3