/******************************************************************************* * This file is part of logisim-evolution. * * logisim-evolution is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * logisim-evolution is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>. * * Original code by Carl Burch (http://www.cburch.com), 2011. * Subsequent modifications by : * + Haute École Spécialisée Bernoise * http://www.bfh.ch * + Haute École du paysage, d'ingénierie et d'architecture de Genève * http://hepia.hesge.ch/ * + Haute École d'Ingénierie et de Gestion du Canton de Vaud * http://www.heig-vd.ch/ * The project is currently maintained by : * + REDS Institute - HEIG-VD * Yverdon-les-Bains, Switzerland * http://reds.heig-vd.ch *******************************************************************************/ package com.cburch.logisim.circuit; class SimulatorTicker extends Thread { private Simulator.PropagationManager manager; private int ticksPerTickPhase; private int millisPerTickPhase; private boolean shouldTick; private int ticksPending; private boolean complete; public SimulatorTicker(Simulator.PropagationManager manager) { this.manager = manager; ticksPerTickPhase = 1; millisPerTickPhase = 1000; shouldTick = false; ticksPending = 0; complete = false; } @Override public void run() { long lastTick = System.currentTimeMillis(); while (true) { boolean curShouldTick = shouldTick; int millis = millisPerTickPhase; int ticks = ticksPerTickPhase; try { synchronized (this) { curShouldTick = shouldTick; millis = millisPerTickPhase; ticks = ticksPerTickPhase; while (!curShouldTick && ticksPending == 0 && !complete) { wait(); curShouldTick = shouldTick; millis = millisPerTickPhase; ticks = ticksPerTickPhase; } } } catch (InterruptedException e) { } if (complete) break; int toTick; long now = System.currentTimeMillis(); if (curShouldTick && now - lastTick >= millis) { toTick = ticks; } else { toTick = ticksPending; } if (toTick > 0) { lastTick = now; for (int i = 0; i < toTick; i++) { manager.requestTick(); } synchronized (this) { if (ticksPending > toTick) ticksPending -= toTick; else ticksPending = 0; } // we fire tickCompleted in this thread so that other // objects (in particular the repaint process) can slow // the thread down. } try { long nextTick = lastTick + millis; int wait = (int) (nextTick - System.currentTimeMillis()); if (wait < 1) wait = 1; if (wait > 100) wait = 100; Thread.sleep(wait); } catch (InterruptedException e) { } } } synchronized void setAwake(boolean value) { shouldTick = value; if (shouldTick) notifyAll(); } public synchronized void setTickFrequency(int millis, int ticks) { millisPerTickPhase = millis; ticksPerTickPhase = ticks; } public synchronized void shutDown() { complete = true; notifyAll(); } public synchronized void tickOnce() { ticksPending++; notifyAll(); } }