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 // always execute to keep timeline from "hanging behind" for too long
45 long current = tf.getAsLong();
46 timeline.executeUntil(timeline.laterThan(current), current + 10);
48 if (timeline.hasNext())
49 sleepTime = timeline.nextEventTime() - current;
54 nextExecSimulTime.set(current + sleepTime);
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();
86 public void executeNextStep()
88 timeline.executeNext();
91 public synchronized void startLiveExecution()
93 if (shouldBeRunningLive.get())
95 shouldBeRunningLive.set(true);
96 simulationThread.start();
97 waitForIsRunning(true);
100 public synchronized void stopLiveExecution()
102 if (!shouldBeRunningLive.get())
104 shouldBeRunningLive.set(false);
105 simulationThread.interrupt();
106 waitForIsRunning(false);
109 public void unpauseLiveExecution()
111 synchronized (isPaused)
119 public void pauseLiveExecution()
121 synchronized (isPaused)
128 public boolean isPaused()
130 return isPaused.get();
133 public void setSpeedPercentage(int percentage)
135 tf.setSpeedPercentage(percentage);
138 private void waitForIsRunning(boolean expectedState)
140 while (isRunningLive.get() ^ expectedState)
143 synchronized (isRunningLive)
145 isRunningLive.wait();
148 catch (@SuppressWarnings("unused") InterruptedException e)
149 {// no need to do anything