/* This file is part of jpcsp. Jpcsp 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. Jpcsp 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 Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.scheduler; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import jpcsp.Emulator; import jpcsp.Allegrex.compiler.RuntimeContext; import jpcsp.HLE.kernel.types.IAction; public class Scheduler { private static Scheduler instance = null; private List<SchedulerAction> actions; private SchedulerAction nextAction; public static Scheduler getInstance() { if (instance == null) { instance = new Scheduler(); } return instance; } public synchronized void reset() { actions = new LinkedList<SchedulerAction>(); nextAction = null; } public void step() { synchronized (this) { if (nextAction == null) { return; } } long now = getNow(); while (true) { IAction action = getAction(now); if (action == null) { break; } action.execute(); } } public synchronized long getNextActionDelay(long noActionDelay) { if (nextAction == null) { return noActionDelay; } long now = getNow(); return nextAction.getSchedule() - now; } private void addSchedulerAction(SchedulerAction schedulerAction) { actions.add(schedulerAction); if (updateNextAction(schedulerAction)) { RuntimeContext.onNextScheduleModified(); } } /** * Add a new action to be executed as soon as possible to the Scheduler. * This method has to be thread-safe. * * @param action action to be executed on the defined schedule. */ public synchronized void addAction(IAction action) { SchedulerAction schedulerAction = new SchedulerAction(0, action); addSchedulerAction(schedulerAction); } /** * Add a new action to the Scheduler. * This method has to be thread-safe. * * @param schedule microTime when the action has to be executed. 0 for now. * @param action action to be executed on the defined schedule. */ public synchronized void addAction(long schedule, IAction action) { SchedulerAction schedulerAction = new SchedulerAction(schedule, action); addSchedulerAction(schedulerAction); } public synchronized void removeAction(long schedule, IAction action) { for (ListIterator<SchedulerAction> lit = actions.listIterator(); lit.hasNext(); ) { SchedulerAction schedulerAction = lit.next(); if (schedulerAction.getSchedule() == schedule && schedulerAction.getAction() == action) { lit.remove(); updateNextAction(); break; } } } private boolean updateNextAction(SchedulerAction schedulerAction) { if (nextAction == null || schedulerAction.getSchedule() < nextAction.getSchedule()) { nextAction = schedulerAction; return true; } return false; } private void updateNextAction() { nextAction = null; for (Iterator<SchedulerAction> it = actions.iterator(); it.hasNext(); ) { SchedulerAction schedulerAction = it.next(); updateNextAction(schedulerAction); } RuntimeContext.onNextScheduleModified(); } public synchronized IAction getAction(long now) { if (nextAction == null || now < nextAction.getSchedule()) { return null; } IAction action = nextAction.getAction(); actions.remove(nextAction); updateNextAction(); return action; } public static long getNow() { return Emulator.getClock().microTime(); } }