home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-02-22 | 19.7 KB | 547 lines |
-
- package simula.simset.simulation;
-
- import simula.SimulaException;
- import simula.simset.*;
-
- /**
- * This class is the simulation context of the wanted model. Its main function is to
- * schedule the event list of the processes.
- */
-
- //[AP2.0] now extends Observable, instead of extends simulationmonitor
- public class Simulation extends java.util.Observable {
-
-
-
- // ----------------------------------- Variables -----------------------------------
- /**
- * Currently active process.
- */
- protected Process currProcess;
- protected EventThread firstThread;
- protected EventThread lastThread;
-
- // [AP2.0] It is read by the UI, with the observer/observable pattern.
- // Replaces the SimulationMonitor interface
- /** Is true if the Main process finished. It has to be set with a call to <code> end() </code> */
- private boolean finished=false ;
-
-
-
- // ----------------------------------- Constructors -----------------------------------
- /**
- * Initialize an empty simulation.
- */
- public Simulation () {
- currProcess = null;
- firstThread = null;
- lastThread = null;
-
-
- }
- /**
- * Initialize a simulation with the given process.
- * @param _first The first process in this simulation.
- */
- public Simulation(Process _first) {
-
- if (_first == null) {
- currProcess = null;
- firstThread = null;
- lastThread = null;
- } else {
- currProcess = _first;
- lastThread = firstThread = _first.processThread();
- }
- }
- /**
- * Activate immediately the given process.
- * And notify it to observers.
- * @param _process Process to be activated.
- * @exception SimulaException Fired if the process is already active.
- */
- public void activate(Process _process) throws SimulaException {
- if (!_process.idle()) throw new SimulaException(SimulaException.ACTIVATE_SCHEDULED);
-
- // [AP2.0] notify the change to observers
- this.update() ;
-
-
- EventThread _Thread = _process.processThread();
-
- // [AP] firstThread can be null
- if (firstThread == null ){ // The evemt list is empty
- lastThread = _Thread;
- } else {
- _process.evtime(this.time());
- // the Thread formerly in first position has to be suspended and placed in second position
- (firstThread.eventProcess()).setStatus(Process.SUSPENDED);
-
- // The given thread becomes the first of the event list
- firstThread.prevThread(_Thread);
- }
-
- // [AP] currProcess has to be set to _process
- currProcess = _process ;
- currProcess.setStatus(Process.ACTIVE);
-
-
- _Thread.prevThread(null);
- _Thread.nextThread(firstThread);
- firstThread = _Thread;
-
- if (_Thread.isAlive()) {
- _Thread.resume();
- } else {
- _Thread.start();
- }
- if (firstThread.nextThread() != null ) (firstThread.nextThread()).suspend();
- }
- /**
- * Activates the first given process after the second one.
- * @param _P Process to be activated.
- * @param _Q Process to be followed.
- * @exception SimulaException Fired if already active or unable to activate.
- */
- public void activate_after(Process _P, Process _Q) throws SimulaException {
- if (_Q.idle()) throw new SimulaException(SimulaException.IDLE_PROCESS);
- activate_at(_P, _Q.evtime(), false);
- }
- /**
- * Activates the given process at the given time.
- * @param _process Process to be activated.
- * @param _time Wanted time of activation.
- * @param _prior If <code>True</a> consider the time like an exclusive bound.
- * @exception SimulaException Fired if the process is already active or the time is obsolete.
- */
- public void activate_at(Process _process, double _time, boolean _prior) throws SimulaException {
-
- if (_time <= this.time()) throw new SimulaException(SimulaException.PAST_TIME);
- if (!_process.idle()) throw new SimulaException(SimulaException.ACTIVATE_SCHEDULED);
-
- EventThread _Thread = _process.processThread();
- (_process).setStatus(Process.SUSPENDED);
- (_process).evtime(_time);
-
- // Scan the event list to find a place for the given thread
- EventThread tmpThread = firstThread;
-
- if (_prior) {
- while ((tmpThread != null) && ((tmpThread.eventProcess()).evtime() < _time)) {
- //System.out.println("Activate at ha deciso che " + _process.toString() + " va dopo di " + (tmpThread.eventProcess()).toString());
- tmpThread = tmpThread.nextThread();
- }
- } else {
- while ((tmpThread != null) && ((tmpThread.eventProcess()).evtime() <= _time)) {
- //System.out.println("Activate at ha deciso che " + _process.toString() + " va dopo di " + (tmpThread.eventProcess()).toString());
- tmpThread = tmpThread.nextThread();
- }
- }
-
- if (tmpThread == null) { // This thread gets the last place
- //System.out.println("Activate at mette " + _process.toString() + " all'ultimo posto");
- lastThread.nextThread(_Thread);
- _Thread.prevThread(lastThread);
- _Thread.nextThread(null);
- lastThread = _Thread;
-
- } else { // given _Thread has to be scheduled BEFORE tmpThread
-
- //System.out.println("Activate at mette " + _process.toString() + " subito prima di " + (tmpThread.eventProcess()).toString());
- (tmpThread.prevThread()).nextThread(_Thread);
- _Thread.prevThread(tmpThread.prevThread());
- _Thread.nextThread(tmpThread);
- tmpThread.prevThread(_Thread);
- }
- }
- /**
- * Activates the first given process before the second one.
- * @param _P Process to be activated.
- * @param _Q Process to be preceded.
- * @exception SimulaException Fired if already active or unable to activate.
- */
- public void activate_before(Process _P, Process _Q) throws SimulaException {
- if (_Q.idle()) throw new SimulaException(SimulaException.IDLE_PROCESS);
- activate_at(_P, _Q.evtime(), true);
- }
- /**
- * Activates the given process at the given time from now.
- * @param _process Process to be activated.
- * @param _delay Time of activation from now.
- * @param _prior If <code>True</a> consider the time like an exclusive bound.
- * @exception SimulaException Fired if unable to activate.
- */
- public void activate_delay(Process _process, double _delay, boolean _prior) throws SimulaException {
- activate_at(_process, this.time() + _delay, _prior);
- }
- /**
- * Cancel the given process from the event list.
- * @param _process Process to be cancelled.
- * @exception SimulaException There was an attempt to passivate the main process of the simulation.
- */
- public void cancel(Process _process) throws SimulaException {
- // Cancel called on first process of the event list is equal to a Passivate
- if (_process == currProcess) {
- passivate();
- } else {
-
- EventThread _Thread = _process.processThread();
- EventThread tmpThread = firstThread;
-
- // Scan the event list to find the given thread
- while (tmpThread.nextThread() != null) {
- if (tmpThread == _Thread) break;
- tmpThread = tmpThread.nextThread();
- }
-
- if (tmpThread != null) { // The given thread has been found in the event list so..
-
- //System.out.println("CANCEL : " + _process.toString() + " sta per essere rimosso ");
- _process.setStatus(Process.PASSIVE); // ..it is passivated
- _process.evtime(0);
-
- //System.out.println("CANCEL : " + _process.toString() + " aveva come prev " + ((_Thread.prevThread()).eventProcess()).toString());
- (_Thread.prevThread()).nextThread(_Thread.nextThread());
-
- if (_Thread.nextThread() == null) { // the given Thread was the last in event list
- lastThread = _Thread.prevThread();
- lastThread.nextThread(null);
- } else {
- (_Thread.nextThread()).prevThread(_Thread.prevThread());
- }
-
- _Thread.prevThread(null);
- _Thread.nextThread(null);
- }
- }
- }
- // ----------------------------------- Accessors -----------------------------------
- /**
- * Returns the currently active process.
- * @return the currently active process.
- */
- public Process current() { return currProcess; }
- /**
- * Kills all sctive threads.
- * Can' t be called by a Proceess or a Mainprocess, because it while try to kill the active thread too.
- * should be used by a UI to kill all processes and MainProcess
- * If called from an applet it will trhow an exception; to avoid this install a security manager
- * @exception SimulaException If thre is problems while unscheduling processes.
- * @since 2.0
- */
- public void destroy ( ) throws SimulaException {
- //if (this.maingroup!=null)
- //this.maingroup.stop() ;
-
- ThreadGroup g=this.firstThread.getThreadGroup() ;
- g.stop() ;
- this.end() ;
-
- this.currProcess=null;
- this.firstThread=null;
- this.lastThread=null;
- return;
- }
- /**
- * Debug function used to dump scheduling informations.
- */
- protected void dump() {
- EventThread tmpThread = firstThread;
-
- System.out.println("DUMP ******************>>>>>>>>>>>");
- while (tmpThread != null) {
- System.out.print((tmpThread.eventProcess()).toString() + " -> ");
- tmpThread = tmpThread.nextThread();
- }
- System.out.println(";");
-
- tmpThread = lastThread;
-
- System.out.println("DUMP <<<<<<<<<<<<<<<<<*************");
- while (tmpThread != null) {
- System.out.print((tmpThread.eventProcess()).toString() + " <- ");
- tmpThread = tmpThread.prevThread();
- }
- System.out.println(";");
- }
- /**
- * Kills all sctive threads.
- * Can' t be called by a Proceess, because it while try to kill the active thread too.
- * It shold be called in the last instruction of <code> SimulationMain </code>, to ensure that
- * there are no zombi threads.
- * @exception SimulaException If thre is problems while unscheduling processes
- * @since 2.0
- */
- public void end ( ) throws SimulaException {
- // System.err.println("Simulation : starting cleanup ") ;
- EventThread first= this.firstThread ;
- EventThread curr ;
- Process p ;
- EventThread next ;
-
- //System.err.println("Stopping processes") ;
- //this.processes.stop() ;
- //System.err.println("Processes stopped") ;
-
- curr=this.firstThread ;
- try {
- while (curr!=null) {
- next=curr.nextThread() ;
-
- if (!(curr.eventProcess() instanceof SimulationMain)) {
- p=curr.eventProcess();
- //System.err.println("Selected process "+p) ;
- curr.stop() ;
- // System.err.println("Stopped "+curr) ;
- this.cancel(p) ;
- //System.err.println("Unscheduled "+curr) ;
-
- /*p.end() ;
- curr.end();
- System.err.println("Killed "+curr) ; */
- }
- curr=next ;
- }
- } catch ( Exception e) {System.err.println("while killing : "+e);} ;
- /*
- curr=first ;
- while (curr!=null) {
- next=curr.nextThread() ;
- if (!(curr.eventProcess() instanceof SimulationMain)) {
- p=curr.eventProcess();
- p.end() ;
- curr.end();
- System.err.println("Killed "+curr) ;
- }
- curr=next ;
- }
- */
-
-
- this.finished=true ;
- //this.currProcess=null;
- this.firstThread=null;
- this.lastThread=null;
- //System.err.println("Simulation : finishing") ;
- this.update() ;
- return;
- }
- /**
- * Returns the simulation status. Not to be confused with the old <code> SimulationMonitor.finished() </code>
- * This reads the status, does not set it.
- * @return boolean True is one of metods <code> end() <code> and </code> destroy() </code> has been called
- * @since 2.0
- */
- public boolean finished ( ) {
- return this.finished;
- }
- // ----------------------------------- Methods -----------------------------------
- /**
- * Suspends the currently active process for the given amount of time.
- * And notify it to observers.
- * @param _time The amount of time to hold the main process of the simulation.
- * @exception SimulaException There is no active process in the simulation.
- */
- public void hold(double _time) throws SimulaException {
-
- // [AP2.0] notify the change to observers
- this.update() ;
-
- if (currProcess == null) {
- throw new SimulaException(SimulaException.NO_CURRENT_PROCESS);
- } else {
- // Passivate the current process
- EventThread currThread = currProcess.processThread();
- double tmpTime = currProcess.evtime() + _time;
- currProcess.evtime(tmpTime); // Set the scheduling time of caller process to its old time + _time
- currProcess.setStatus(Process.SUSPENDED);
-
- if (currThread.nextThread() != null) { //This is not the only Thread in the event list
-
- // Reschedule the caller thread after _time
- EventThread tmpThread = firstThread;
- while (tmpThread != null && ((tmpThread.eventProcess()).evtime() <= tmpTime)) {
- //System.out.println("Hold ha deciso che " + currProcess.toString() + " va dopo di " + (tmpThread.eventProcess()).toString());
- tmpThread = tmpThread.nextThread();
- }
- if (tmpThread == null) { // This thread gets the last place
- //System.out.println("Hold mette " + currProcess.toString() + " all'ultimo posto");
- firstThread = currThread.nextThread();
- lastThread.nextThread(currThread);
- currThread.prevThread(lastThread);
- currThread.nextThread(null);
- lastThread = currThread;
- } else { // This thread has to be scheduled BEFORE tmpThread
-
- //System.out.println("Hold mette " + currProcess.toString() + " subito prima di " + (tmpThread.eventProcess()).toString());
- // the former second thread becomes the first UNLESS the held thread still has the lowest time
- if (tmpThread.prevThread() != currThread) {
- firstThread = currThread.nextThread();
- firstThread.prevThread(null);
-
- currThread.nextThread(tmpThread);
- currThread.prevThread(tmpThread.prevThread());
-
- (currThread.prevThread()).nextThread(currThread);
- tmpThread.prevThread(currThread);
-
- }
- }
-
- // Activate the next thread in event list with the related process
-
- //if (firstThread == null) System.out.println("FIRST e' nullo !");
-
- firstThread.prevThread(null);
-
- currProcess = firstThread.eventProcess();
- currProcess.setStatus(Process.ACTIVE);
-
- //dump();
- //System.out.println("HOLD: sta per far partire : " + currProcess.toString());
-
- if (currThread != firstThread) {
- if (firstThread.isAlive()) {
- firstThread.resume();
- } else {
- firstThread.start();
- }
- currThread.suspend();
- }
- }
- }
- }
- /**
- * Passivate the currently active process.
- * And notify it to observers.
- * @exception SimulaException There was an attempt to passivate the main process of the simulation.
- */
- public void passivate() throws SimulaException {
- if (currProcess instanceof SimulationMain) throw new SimulaException(SimulaException.MAIN_PASSIVATED);
-
- // [AP2.0] notify the change to observers
- this.update() ;
-
- EventThread callerThread = currProcess.processThread();
- currProcess.setStatus(Process.PASSIVE);
- currProcess.evtime(0);
-
- // Activate the next thread in event list with the related process
- firstThread = callerThread.nextThread();
-
- // Caller Thread gets out the event list
- callerThread.nextThread(null);
- callerThread.prevThread(null);
-
- // [AP] if there is more than one process
- if (firstThread == null ){
- //System.out.println("Simulation: io avrei finito...");
- System.exit(1); // No more process in evenbt list
- } else {
- //System.out.println("Simulation.passivate : adesso ariva l' eccezione") ;
- firstThread.prevThread(null);
- //System.out.println("Simulation.passivate : qui non ci arrivi !") ;
- currProcess = firstThread.eventProcess();
- currProcess.setStatus(Process.ACTIVE);
- if (firstThread.isAlive()) {
- firstThread.resume();
- } else {
- firstThread.start();
- }
- }
- callerThread.suspend();
- }
- /**
- * Reactivate immediately the given process.
- * And notify it to observers.
- * @param _process Process to be reactivated.
- * @exception SimulaException Fired if unable to cancel or activate the process.
- */
- public void reactivate(Process _process) throws SimulaException {
- //[AP2.0] Notify change
- this.update() ;
- if (_process != currProcess) {
- cancel(_process); // Pulls out the process if it is already scheduled
- activate(_process); // Now get that on top of event list
- }
- }
- /**
- * Reactivates the first given process after the second one.
- * @param _P Process to be activated.
- * @param _Q Process to be preceded.
- * @exception SimulaException Fired if already active or unable to reactivate.
- */
- public void reactivate_after(Process _P, Process _Q) throws SimulaException {
- if (_Q.idle()) throw new SimulaException(SimulaException.IDLE_PROCESS);
- reactivate_at(_P, _Q.evtime(), false);
- }
- /**
- * Reactivate the given process at the given time.
- * @param _process Process to be reactivated.
- * @param _time Wanted time of activation.
- * @param _prior If <code>True</a> consider the time like an exclusive bound.
- * @exception SimulaException Fired if unable to cancel or activate the process.
- */
- public void reactivate_at(Process _process, double _time, boolean _prior) throws SimulaException {
- if (_process != currProcess) {
- cancel(_process); // Pulls out the process if it is already scheduled
- activate_at(_process, _time, _prior); // Now get that on top of event list
- }
- }
- /**
- * Reactivates the first given process before the second one.
- * @param _P Process to be activated.
- * @param _Q Process to be preceded.
- * @exception SimulaException Fired if already active or unable to reactivate.
- */
- public void reactivate_before(Process _P, Process _Q) throws SimulaException {
- if (_Q.idle()) throw new SimulaException(SimulaException.IDLE_PROCESS);
- reactivate_at(_P, _Q.evtime(), true);
- }
- /**
- * Reactivate the given process at the given time from now.
- * @param _process Process to be reactivated.
- * @param _delay Time of activation from now.
- * @param _prior If <code>True</a> consider the time like an exclusive bound.
- * @exception SimulaException Fired if unable to reactivate.
- */
- public void reactivate_delay(Process _process, double _delay, boolean _prior) throws SimulaException {
- reactivate_at(_process, this.time() + _delay, _prior);
- }
- /**
- * Returns the time from the beginning of the simulation.
- * @return the time from the beginning of the simulation.
- * @exception SimulaException If there is no process currently active.
- */
- public double time() throws SimulaException {
- if (currProcess == null) {
- throw new SimulaException(SimulaException.NO_CURRENT_PROCESS);
- } else return currProcess.evtime();
- }
- /**
- * Notify simulation status to observers (if there are any)
- * It is called when a process passivates or holds
- * The current active process is passed as parameter to the <code> update </code> call in observers.
- * Can be called by a <code> Process </code> too, to force display update.
- * @since 2.0
- */
- public void update ( ) {
- this.setChanged() ;
- this.notifyObservers(currProcess) ;
- return;
- }
- /**
- * Adds the current process to the given waiting list and passivates it.
- * And notify it to observers.
- * @param _list List where the current process will be added to.
- * @exception SimulaException Fired if unable to insert or passivate the current process.
- */
- public void wait(Head _list) throws SimulaException {
- //[AP2.0] notify
- this.update() ;
- currProcess.into(_list);
- this.passivate();
- }
- } // End of class Simulation
-