summaryrefslogtreecommitdiff
path: root/src/actors/scala/actors/Reaction.scala
blob: 5940628124101712bb45740a00633edb77ac01d7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2005-2009, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |                                         **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

// $Id$


package scala.actors

import java.lang.{InterruptedException, Runnable}

/** <p>
 *    This exception is thrown whenever an actor exits.
 *    Its purpose is to let <code>exit</code> have
 *    return type <code>Nothing</code>.
 *  </p>
 *
 *  @version 0.9.10
 *  @author Philipp Haller
 */
private[actors] class ExitActorException extends Throwable {
  /*
   * For efficiency reasons we do not fill in
   * the execution stack trace.
   */
  override def fillInStackTrace(): Throwable = this
}

private[actors] class KillActorException extends Throwable {
  /*
   * For efficiency reasons we do not fill in
   * the execution stack trace.
   */
  override def fillInStackTrace(): Throwable = this
}

/** <p>
 *    The abstract class <code>Reaction</code> associates
 *    an instance of an <code>Actor</code> with a
 *    <a class="java/lang/Runnable" href="" target="contentFrame">
 *    <code>java.lang.Runnable</code></a>.
 *  </p>
 *
 *  @version 0.9.10
 *  @author Philipp Haller
 */
class Reaction extends Runnable {

  private[actors] var a: Actor = _
  private var f: PartialFunction[Any, Unit] = _
  private var msg: Any = _

  def this(a: Actor, f: PartialFunction[Any, Unit], msg: Any) = {
    this()
    this.a = a
    this.f = f
    this.msg = msg
  }

  def this(a: Actor) = this(a, null, null)

  def run() {
    val saved = Actor.tl.get.asInstanceOf[Actor]
    Actor.tl.set(a)
    a.isDetached = false
    try {
      if (a.shouldExit) // links
        a.exit()
      else {
        try {
          if (f == null)
            a.act()
          else
            f(msg)
        } catch {
          case _: KillActorException =>
        }
        a.kill(); a.exit()
      }
    }
    catch {
      case eae: ExitActorException => {
        //Debug.info(a+": exiting...")
        ActorGC.terminated(a)
      }
      case _: SuspendActorException => {
        // do nothing (continuation is already saved)
      }
      case t: Throwable => {
        Debug.info(a+": caught "+t)
        ActorGC.terminated(a)
        // links
        a.synchronized {
          if (!a.links.isEmpty)
            a.exitLinked(t)
          else
            t.printStackTrace()
        }
      }
    } finally {
      Actor.tl.set(saved)
    }
  }

}