1 package net.mograsim.logic.model;
3 import java.util.concurrent.atomic.AtomicBoolean;
4 import java.util.concurrent.atomic.AtomicLong;
6 import net.mograsim.logic.core.timeline.PauseableTimeFunction;
7 import net.mograsim.logic.core.timeline.Timeline;
9 //TODO maybe move to logic core?
10 public class LogicExecuter
12 // TODO replace with CoreModel when it exists
13 private final Timeline timeline;
15 private final AtomicBoolean shouldBeRunningLive;
16 private final AtomicBoolean isRunningLive;
17 private final AtomicBoolean isPaused;
18 private final AtomicLong nextExecSimulTime;
19 private final Thread simulationThread;
21 PauseableTimeFunction tf;
23 public LogicExecuter(Timeline timeline)
25 this.timeline = timeline;
27 tf = new PauseableTimeFunction();
28 timeline.setTimeFunction(tf);
29 shouldBeRunningLive = new AtomicBoolean();
30 isRunningLive = new AtomicBoolean();
31 isPaused = new AtomicBoolean();
32 nextExecSimulTime = new AtomicLong();
33 simulationThread = new Thread(() ->
35 isRunningLive.set(true);
36 synchronized (isRunningLive)
38 isRunningLive.notify();
42 while (shouldBeRunningLive.get())
44 long current = tf.getAsLong();
45 timeline.executeUntil(timeline.laterThan(current), System.currentTimeMillis() + 10);
46 long nextEventTime = timeline.nextEventTime();
48 if (timeline.hasNext())
49 sleepTime = (long) ((nextEventTime - current) * tf.getSimulTimeToRealTimeFactor());
54 nextExecSimulTime.set(nextEventTime);
56 Thread.sleep(sleepTime);
58 synchronized (isPaused)
60 while (isPaused.get())
64 catch (@SuppressWarnings("unused") InterruptedException e)
65 {// do nothing; it is normal execution flow to be interrupted
71 isRunningLive.set(false);
72 synchronized (isRunningLive)
74 isRunningLive.notify();
78 timeline.addEventAddedListener(event ->
80 if (isRunningLive.get())
81 if (Timeline.timeCmp(event.getTiming(), nextExecSimulTime.get()) < 0)
82 simulationThread.interrupt();
84 // not optimal; but we don't expect this to happen very often
85 tf.addSimulTimeToRealTimeFactorChangedListener(d -> simulationThread.interrupt());
88 public void executeNextStep()
90 timeline.executeNext();
93 public synchronized void startLiveExecution()
95 if (shouldBeRunningLive.get())
97 shouldBeRunningLive.set(true);
98 simulationThread.start();
99 waitForIsRunning(true);
102 public synchronized void stopLiveExecution()
104 if (!shouldBeRunningLive.get())
106 shouldBeRunningLive.set(false);
107 simulationThread.interrupt();
108 waitForIsRunning(false);
111 public void unpauseLiveExecution()
113 synchronized (isPaused)
121 public void pauseLiveExecution()
123 synchronized (isPaused)
130 public boolean isPaused()
132 return isPaused.get();
135 public void setSpeedFactor(double factor)
137 tf.setSpeedFactor(factor);
140 private void waitForIsRunning(boolean expectedState)
142 while (isRunningLive.get() ^ expectedState)
145 synchronized (isRunningLive)
147 isRunningLive.wait();
150 catch (@SuppressWarnings("unused") InterruptedException e)
151 {// no need to do anything