summaryrefslogtreecommitdiff
path: root/src/actors
diff options
context:
space:
mode:
authorPhilipp Haller <hallerp@gmail.com>2010-03-24 17:29:59 +0000
committerPhilipp Haller <hallerp@gmail.com>2010-03-24 17:29:59 +0000
commit361799635196b1e2cc5dfdea569252cba3aa9ee1 (patch)
treec592b57463ef1079c85a4fd592a9b87f7f26a167 /src/actors
parenta09cf5dbf7ed64e1ff52bebb53971d16304b58e5 (diff)
downloadscala-361799635196b1e2cc5dfdea569252cba3aa9ee1.tar.gz
scala-361799635196b1e2cc5dfdea569252cba3aa9ee1.tar.bz2
scala-361799635196b1e2cc5dfdea569252cba3aa9ee1.zip
Addresses see #2017.
Diffstat (limited to 'src/actors')
-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
8 files changed, 93 insertions, 35 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+")"
+
+}