diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2018-10-30 23:53:58 +0100 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2019-05-13 20:26:03 +0200 |
| commit | 2bc0e9834a81738e3af24886d8daf7af490bcc59 (patch) | |
| tree | 31762b3b6b062554cc38346218a5d1f11ae9291e /odcsim-engine-omega/src | |
| parent | a98d8ce9f3dfa5df99f0573cdf741fb251881d7e (diff) | |
refactor: Add support for deferred and special behavior
This change adds support for deferred and special behavior in the
Behavior API. Additionally, the new Behavior DSL is implemented using
the new primitives to make the tests cleaner.
Diffstat (limited to 'odcsim-engine-omega/src')
| -rw-r--r-- | odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt | 68 |
1 files changed, 56 insertions, 12 deletions
diff --git a/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt b/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt index 3eaddf51..3da82b3d 100644 --- a/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt +++ b/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt @@ -29,6 +29,7 @@ import com.atlarge.odcsim.ActorPath import com.atlarge.odcsim.ActorRef import com.atlarge.odcsim.ActorSystem import com.atlarge.odcsim.Behavior +import com.atlarge.odcsim.BehaviorInterpreter import com.atlarge.odcsim.Duration import com.atlarge.odcsim.Instant import com.atlarge.odcsim.PostStop @@ -58,6 +59,11 @@ class OmegaActorSystem<in T : Any>(root: Behavior<T>, override val name: String) override val path: ActorPath = ActorPath.Root(name = "/user") /** + * A flag to indicate the system has started. + */ + private var isStarted: Boolean = false + + /** * The event queue to process */ private val queue: PriorityQueue<Envelope> = PriorityQueue(Comparator @@ -69,10 +75,21 @@ class OmegaActorSystem<in T : Any>(root: Behavior<T>, override val name: String) */ private val registry: MutableMap<ActorPath, Actor<*>> = HashMap() + init { + registry[path] = Actor(this, root) + schedule(this, PreStart, .0) + } + override fun run(until: Duration) { require(until >= .0) { "The given instant must be a non-negative number" } - while (true) { + // Start the root actor on initial run + if (!isStarted) { + registry[path]!!.start() + isStarted = true + } + + while (time < until) { val envelope = queue.peek() ?: break val delivery = envelope.time.takeUnless { it > until } ?: break @@ -99,13 +116,15 @@ class OmegaActorSystem<in T : Any>(root: Behavior<T>, override val name: String) */ private var nextId: Long = 0 - init { - registry[path] = Actor(this, root) - schedule(this, PreStart, .0) - } - - private inner class Actor<T : Any>(override val self: ActorRef<T>, var behavior: Behavior<T>) : ActorContext<T> { + /** + * An actor as represented in the Omega engine. + * + * @param self The [ActorRef] to this actor. + * @param initialBehavior The initial behavior of this actor. + */ + private inner class Actor<T : Any>(override val self: ActorRef<T>, initialBehavior: Behavior<T>) : ActorContext<T> { val children: MutableSet<Actor<*>> = mutableSetOf() + val interpreter = BehaviorInterpreter(initialBehavior) override val time: Instant get() = this@OmegaActorSystem.time @@ -117,6 +136,7 @@ class OmegaActorSystem<in T : Any>(root: Behavior<T>, override val name: String) registry[ref.path] = actor children += actor schedule(ref, PreStart, .0) + actor.start() } return ref } @@ -127,25 +147,49 @@ class OmegaActorSystem<in T : Any>(root: Behavior<T>, override val name: String) return false } val ref = registry[child.path] ?: return false - ref.terminate() + ref.stop() return true } /** + * Start this actor. + */ + fun start() { + interpreter.start(this) + } + + /** + * Stop this actor. + */ + fun stop() { + interpreter.stop(this) + terminate() + interpreter.interpretSignal(this, PostStop) + } + + /** * Terminate this actor and its children. */ fun terminate() { children.forEach { it.terminate() } registry.remove(self.path) - interpretMessage(PostStop) } /** - * Interpret the given message send to an actor. Make sure the message is of the correct type. + * Interpret the given message send to an actor. */ fun interpretMessage(msg: Any) { - @Suppress("UNCHECKED_CAST") - behavior = if (msg is Signal) behavior.receiveSignal(this, msg) else behavior.receive(this, msg as T) + if (msg is Signal) { + interpreter.interpretSignal(this, msg) + } else { + @Suppress("UNCHECKED_CAST") + interpreter.interpretMessage(this, msg as T) + } + + if (!interpreter.isAlive) { + terminate() + interpreter.interpretSignal(this, PostStop) + } } override fun equals(other: Any?): Boolean = |
