diff options
author | Philipp Haller <hallerp@gmail.com> | 2010-01-07 11:35:41 +0000 |
---|---|---|
committer | Philipp Haller <hallerp@gmail.com> | 2010-01-07 11:35:41 +0000 |
commit | b5c141b4ed5e2db673a306a2ba0c23a1fbe2d9ee (patch) | |
tree | f9916464bb630df0e57a7ad1c8e5616cf0155b6a /src/actors | |
parent | 57f14277dad0427b90abc1e6f70e2f8ae4dcbb51 (diff) | |
download | scala-b5c141b4ed5e2db673a306a2ba0c23a1fbe2d9ee.tar.gz scala-b5c141b4ed5e2db673a306a2ba0c23a1fbe2d9ee.tar.bz2 scala-b5c141b4ed5e2db673a306a2ba0c23a1fbe2d9ee.zip |
Fixed issue in Reactor/Actor that could lead to...
Fixed issue in Reactor/Actor that could lead to premature termination
of actors. Added test that could reproduce it (occurred more often on
larger inputs, but test should not take too much time). The issue also
caused the reactor-exceptionOnSend test to timeout sometimes. Review by
plocinic.
Diffstat (limited to 'src/actors')
-rw-r--r-- | src/actors/scala/actors/Actor.scala | 8 | ||||
-rw-r--r-- | src/actors/scala/actors/Debug.scala | 9 | ||||
-rw-r--r-- | src/actors/scala/actors/Reactor.scala | 22 | ||||
-rw-r--r-- | src/actors/scala/actors/ReactorTask.scala | 1 | ||||
-rw-r--r-- | src/actors/scala/actors/ReplyReactor.scala | 8 |
5 files changed, 44 insertions, 4 deletions
diff --git a/src/actors/scala/actors/Actor.scala b/src/actors/scala/actors/Actor.scala index fb90cb9c46..907389b9f0 100644 --- a/src/actors/scala/actors/Actor.scala +++ b/src/actors/scala/actors/Actor.scala @@ -646,6 +646,7 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { } // guarded by lock of this + // never throws SuspendActorException private[actors] override def scheduleActor(f: Any =>? Unit, msg: Any) = if ((f eq null) && (continuation eq null)) { // do nothing (timeout is handled instead) @@ -825,6 +826,13 @@ trait Actor extends AbstractActor with ReplyReactor with ReplyableActor { resumeActor() else if (waitingFor ne waitingForNone) { scheduleActor(continuation, null) + /* Here we should not throw a SuspendActorException, + since the current method is called from an actor that + is in the process of exiting. + + Therefore, the contract for scheduleActor is that + it never throws a SuspendActorException. + */ } } } diff --git a/src/actors/scala/actors/Debug.scala b/src/actors/scala/actors/Debug.scala index 481b68d7f4..bad19b8aeb 100644 --- a/src/actors/scala/actors/Debug.scala +++ b/src/actors/scala/actors/Debug.scala @@ -27,6 +27,15 @@ object Debug { def error(s: String) = if (lev > 0) System.err.println("Error: " + s) + + def doInfo(b: => Unit) = + if (lev > 2) b + + def doWarning(b: => Unit) = + if (lev > 1) b + + def doError(b: => Unit) = + if (lev > 0) b } class Debug(tag: String) { diff --git a/src/actors/scala/actors/Reactor.scala b/src/actors/scala/actors/Reactor.scala index d641f54eb6..8545b92d1e 100644 --- a/src/actors/scala/actors/Reactor.scala +++ b/src/actors/scala/actors/Reactor.scala @@ -108,8 +108,17 @@ trait Reactor extends OutputChannel[Any] { // assert continuation != null if (onSameThread) continuation(item._1) - else + else { scheduleActor(continuation, item._1) + /* Here, we throw a SuspendActorException to avoid + terminating this actor when the current ReactorTask + is finished. + + The SuspendActorException skips the termination code + in ReactorTask. + */ + throw Actor.suspendException + } } def !(msg: Any) { @@ -149,7 +158,14 @@ trait Reactor extends OutputChannel[Any] { // keep going } else { waitingFor = handlesMessage - done = true + /* Here, we throw a SuspendActorException to avoid + terminating this actor when the current ReactorTask + is finished. + + The SuspendActorException skips the termination code + in ReactorTask. + */ + throw Actor.suspendException } } } else { @@ -171,6 +187,8 @@ trait Reactor extends OutputChannel[Any] { * an actors act method. * * assume handler != null + * + * never throws SuspendActorException */ private[actors] def scheduleActor(handler: Any =>? Unit, msg: Any) = { val fun = () => handler(msg) diff --git a/src/actors/scala/actors/ReactorTask.scala b/src/actors/scala/actors/ReactorTask.scala index 28e93bbbff..f6ec67e94c 100644 --- a/src/actors/scala/actors/ReactorTask.scala +++ b/src/actors/scala/actors/ReactorTask.scala @@ -46,6 +46,7 @@ private[actors] class ReactorTask[T >: Null <: Reactor](var reactor: T, var fun: case e: Exception => Debug.info(reactor+": caught "+e) + Debug.doInfo { e.printStackTrace() } reactor.terminated() afterExecuting(e) } finally { diff --git a/src/actors/scala/actors/ReplyReactor.scala b/src/actors/scala/actors/ReplyReactor.scala index 4b31369db4..64860f4d38 100644 --- a/src/actors/scala/actors/ReplyReactor.scala +++ b/src/actors/scala/actors/ReplyReactor.scala @@ -57,8 +57,11 @@ trait ReplyReactor extends Reactor with ReplyableReactor { // assert continuation != null if (onSameThread) continuation(item._1) - else + else { scheduleActor(continuation, item._1) + // see Reactor.resumeReceiver + throw Actor.suspendException + } } // assume continuation != null @@ -83,7 +86,8 @@ trait ReplyReactor extends Reactor with ReplyableReactor { // keep going } else { waitingFor = handlesMessage - done = true + // see Reactor.searchMailbox + throw Actor.suspendException } } } else { |