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), System.currentTimeMillis() + 10);
47 long nextEventTime = timeline.nextEventTime();
49 if (timeline.hasNext())
50 sleepTime = tf.simulTimeDeltaToRealTimeMillis(nextEventTime - current);
55 nextExecSimulTime.set(nextEventTime);
57 Thread.sleep(sleepTime);
59 synchronized (isPaused)
61 while (isPaused.get())
65 catch (@SuppressWarnings("unused") InterruptedException e)
66 {// do nothing; it is normal execution flow to be interrupted
72 isRunningLive.set(false);
73 synchronized (isRunningLive)
75 isRunningLive.notify();
79 timeline.addEventAddedListener(event ->
81 if (isRunningLive.get())
82 if (Timeline.timeCmp(event.getTiming(), nextExecSimulTime.get()) < 0)
83 simulationThread.interrupt();
87 public void executeNextStep()
89 timeline.executeNext();
92 public synchronized void startLiveExecution()
94 if (shouldBeRunningLive.get())
96 shouldBeRunningLive.set(true);
97 simulationThread.start();
98 waitForIsRunning(true);
101 public synchronized void stopLiveExecution()
103 if (!shouldBeRunningLive.get())
105 shouldBeRunningLive.set(false);
106 simulationThread.interrupt();
107 waitForIsRunning(false);
110 public void unpauseLiveExecution()
112 synchronized (isPaused)
120 public void pauseLiveExecution()
122 synchronized (isPaused)
129 public boolean isPaused()
131 return isPaused.get();
134 public void setSpeedFactor(double factor)
136 tf.setSpeedFactor(factor);
139 private void waitForIsRunning(boolean expectedState)
141 while (isRunningLive.get() ^ expectedState)
144 synchronized (isRunningLive)
146 isRunningLive.wait();
149 catch (@SuppressWarnings("unused") InterruptedException e)
150 {// no need to do anything