summaryrefslogtreecommitdiff
path: root/odcsim-engine-omega/src
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2018-10-30 23:53:58 +0100
committerFabian Mastenbroek <mail.fabianm@gmail.com>2019-05-13 20:26:03 +0200
commit2bc0e9834a81738e3af24886d8daf7af490bcc59 (patch)
tree31762b3b6b062554cc38346218a5d1f11ae9291e /odcsim-engine-omega/src
parenta98d8ce9f3dfa5df99f0573cdf741fb251881d7e (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.kt68
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 =