summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt44
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowEngineImpl.kt13
2 files changed, 37 insertions, 20 deletions
diff --git a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt
index e2f7874c..908e902a 100644
--- a/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt
+++ b/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/core/SimulationCoroutineDispatcher.kt
@@ -37,11 +37,6 @@ import kotlin.coroutines.CoroutineContext
@OptIn(InternalCoroutinesApi::class)
public class SimulationCoroutineDispatcher : CoroutineDispatcher(), SimulationController, Delay {
/**
- * The virtual clock of this dispatcher.
- */
- override val clock: Clock = VirtualClock()
-
- /**
* Queue of ordered tasks to run.
*/
private val queue = PriorityQueue<TimedRunnable>()
@@ -54,7 +49,12 @@ public class SimulationCoroutineDispatcher : CoroutineDispatcher(), SimulationCo
/**
* The current virtual time of simulation
*/
- private var _time = 0L
+ private var _clock = SimClock()
+
+ /**
+ * The virtual clock of this dispatcher.
+ */
+ override val clock: Clock = ClockAdapter(_clock)
override fun dispatch(context: CoroutineContext, block: Runnable) {
block.run()
@@ -79,14 +79,14 @@ public class SimulationCoroutineDispatcher : CoroutineDispatcher(), SimulationCo
}
override fun toString(): String {
- return "SimulationCoroutineDispatcher[time=${_time}ms, queued=${queue.size}]"
+ return "SimulationCoroutineDispatcher[time=${_clock.time}ms, queued=${queue.size}]"
}
private fun post(block: Runnable) =
queue.add(TimedRunnable(block, _counter++))
private fun postDelayed(block: Runnable, delayTime: Long) =
- TimedRunnable(block, _counter++, safePlus(_time, delayTime))
+ TimedRunnable(block, _counter++, safePlus(_clock.time, delayTime))
.also {
queue.add(it)
}
@@ -100,31 +100,41 @@ public class SimulationCoroutineDispatcher : CoroutineDispatcher(), SimulationCo
override fun advanceUntilIdle(): Long {
val queue = queue
- val oldTime = _time
- while (queue.isNotEmpty()) {
- val current = queue.poll()
+ val clock = _clock
+ val oldTime = clock.time
+
+ while (true) {
+ val current = queue.poll() ?: break
// If the scheduled time is 0 (immediate) use current virtual time
if (current.time != 0L) {
- _time = current.time
+ clock.time = current.time
}
current.run()
}
- return _time - oldTime
+ return clock.time - oldTime
}
- private inner class VirtualClock(private val zone: ZoneId = ZoneId.systemDefault()) : Clock() {
+ /**
+ * A helper class that holds the time of the simulation.
+ */
+ private class SimClock(@JvmField var time: Long = 0)
+
+ /**
+ * A helper class to expose a [Clock] instance for this dispatcher.
+ */
+ private class ClockAdapter(private val clock: SimClock, private val zone: ZoneId = ZoneId.systemDefault()) : Clock() {
override fun getZone(): ZoneId = zone
- override fun withZone(zone: ZoneId): Clock = VirtualClock(zone)
+ override fun withZone(zone: ZoneId): Clock = ClockAdapter(clock, zone)
override fun instant(): Instant = Instant.ofEpochMilli(millis())
- override fun millis(): Long = _time
+ override fun millis(): Long = clock.time
- override fun toString(): String = "SimulationCoroutineDispatcher.VirtualClock[time=$_time]"
+ override fun toString(): String = "SimulationCoroutineDispatcher.ClockAdapter[time=${clock.time}]"
}
/**
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowEngineImpl.kt b/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowEngineImpl.kt
index a9234abf..450556f8 100644
--- a/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowEngineImpl.kt
+++ b/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowEngineImpl.kt
@@ -38,7 +38,7 @@ import kotlin.coroutines.CoroutineContext
* @param context The coroutine context to use.
* @param clock The virtual simulation clock.
*/
-internal class FlowEngineImpl(private val context: CoroutineContext, override val clock: Clock) : FlowEngine, Runnable {
+internal class FlowEngineImpl(private val context: CoroutineContext, clock: Clock) : FlowEngine, Runnable {
/**
* The [Delay] instance that provides scheduled execution of [Runnable]s.
*/
@@ -71,6 +71,13 @@ internal class FlowEngineImpl(private val context: CoroutineContext, override va
private var batchIndex = 0
/**
+ * The virtual [Clock] of this engine.
+ */
+ override val clock: Clock
+ get() = _clock
+ private val _clock: Clock = clock
+
+ /**
* Update the specified [ctx] synchronously.
*/
fun scheduleSync(now: Long, ctx: FlowConsumerContextImpl) {
@@ -113,7 +120,7 @@ internal class FlowEngineImpl(private val context: CoroutineContext, override va
try {
// Flush the work if the engine is not already running
if (batchIndex == 1 && queue.isNotEmpty()) {
- doRunEngine(clock.millis())
+ doRunEngine(_clock.millis())
}
} finally {
batchIndex--
@@ -122,7 +129,7 @@ internal class FlowEngineImpl(private val context: CoroutineContext, override va
/* Runnable */
override fun run() {
- val now = clock.millis()
+ val now = _clock.millis()
val invocation = futureInvocations.poll() // Clear invocation from future invocation queue
assert(now >= invocation.timestamp) { "Future invocations invariant violated" }