home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 21 / IOPROG_21.ISO / SOFT / JSL.ZIP / JSL20 / simula / simset / simulation / Simulation.java < prev    next >
Encoding:
Java Source  |  1998-02-22  |  19.7 KB  |  547 lines

  1.  
  2. package simula.simset.simulation;
  3.  
  4. import simula.SimulaException;
  5. import simula.simset.*;
  6.  
  7. /**
  8.  * This class is the simulation context of the wanted model. Its main function is to
  9.  * schedule the event list of the processes.
  10.  */
  11.  
  12.  //[AP2.0]  now extends Observable, instead of extends simulationmonitor
  13. public class Simulation extends java.util.Observable  {
  14.     
  15.     
  16.  
  17.   // -----------------------------------  Variables -----------------------------------
  18.   /**
  19.    * Currently active process.
  20.    */
  21.   protected Process currProcess;
  22.   protected EventThread firstThread;
  23.   protected EventThread lastThread;
  24.   
  25.   // [AP2.0]  It is read by the UI, with the observer/observable pattern. 
  26.   // Replaces the SimulationMonitor interface 
  27.   /** Is true if the Main process finished. It has to be set with a call to <code> end() </code> */
  28.   private boolean finished=false ;
  29.   
  30.  
  31.  
  32.         // ----------------------------------- Constructors -----------------------------------
  33.         /**
  34.          * Initialize an empty simulation.
  35.          */
  36.         public Simulation () {
  37.                 currProcess = null;
  38.                 firstThread = null;
  39.                 lastThread = null;
  40.                 
  41.             
  42.         }
  43.         /**
  44.          * Initialize a simulation with the given process.
  45.          * @param _first The first process in this simulation.
  46.          */
  47.         public Simulation(Process _first) {
  48.                 
  49.                 if (_first == null) {
  50.                         currProcess = null;
  51.                         firstThread = null;
  52.                         lastThread = null;
  53.                 } else {
  54.                         currProcess = _first;
  55.                         lastThread = firstThread = _first.processThread();
  56.                 }
  57.         }
  58.         /**
  59.          * Activate immediately the given process.
  60.          * And notify it to observers.
  61.          * @param _process Process to be activated.
  62.          * @exception SimulaException Fired if the process is already active.
  63.          */
  64.         public void activate(Process _process) throws SimulaException {
  65.                 if (!_process.idle()) throw new SimulaException(SimulaException.ACTIVATE_SCHEDULED);
  66.  
  67.                 // [AP2.0] notify the change to observers
  68.                 this.update() ;
  69.                 
  70.                 
  71.                 EventThread _Thread = _process.processThread();
  72.  
  73.                 // [AP] firstThread can be null
  74.                 if (firstThread == null ){ // The evemt list is empty
  75.                         lastThread = _Thread;
  76.                 } else {
  77.                         _process.evtime(this.time());
  78.                         // the Thread formerly in first position has to be suspended and placed in second position
  79.                         (firstThread.eventProcess()).setStatus(Process.SUSPENDED);
  80.  
  81.                         // The given thread becomes the first of the event list
  82.                         firstThread.prevThread(_Thread);
  83.                 }
  84.                 
  85.                 // [AP] currProcess has to be set to _process
  86.                 currProcess = _process ;
  87.                 currProcess.setStatus(Process.ACTIVE);
  88.             
  89.                 
  90.                 _Thread.prevThread(null);
  91.                 _Thread.nextThread(firstThread);
  92.                 firstThread = _Thread;
  93.  
  94.                 if (_Thread.isAlive()) {
  95.                         _Thread.resume();
  96.                 } else {
  97.                         _Thread.start();
  98.                 }
  99.                 if (firstThread.nextThread() != null ) (firstThread.nextThread()).suspend();
  100.         }
  101.         /**
  102.          * Activates the first given process after the second one.
  103.          * @param _P Process to be activated.
  104.          * @param _Q Process to be followed.
  105.          * @exception SimulaException Fired if already active or unable to activate.
  106.          */
  107.         public void activate_after(Process _P, Process _Q) throws SimulaException {
  108.                 if (_Q.idle()) throw new SimulaException(SimulaException.IDLE_PROCESS);
  109.                 activate_at(_P, _Q.evtime(), false);
  110.         }
  111.         /**
  112.          * Activates the given process at the given time.
  113.          * @param _process Process to be activated.
  114.          * @param _time Wanted time of activation.
  115.          * @param _prior If <code>True</a> consider the time like an exclusive bound.
  116.          * @exception SimulaException Fired if the process is already active or the time is obsolete.
  117.          */
  118.         public void activate_at(Process _process, double _time, boolean _prior) throws SimulaException {
  119.  
  120.                 if (_time <= this.time()) throw new SimulaException(SimulaException.PAST_TIME);
  121.                 if (!_process.idle()) throw new SimulaException(SimulaException.ACTIVATE_SCHEDULED);
  122.  
  123.                 EventThread _Thread = _process.processThread();
  124.                 (_process).setStatus(Process.SUSPENDED);
  125.                 (_process).evtime(_time);
  126.  
  127.                 // Scan the event list to find a place for the given thread
  128.                 EventThread tmpThread = firstThread;
  129.  
  130.                 if (_prior) {
  131.                         while ((tmpThread != null) && ((tmpThread.eventProcess()).evtime() < _time)) {
  132.                                 //System.out.println("Activate at ha deciso che " + _process.toString() + " va dopo di " + (tmpThread.eventProcess()).toString());
  133.                                 tmpThread = tmpThread.nextThread();
  134.                         }
  135.                 } else {
  136.                         while ((tmpThread != null) && ((tmpThread.eventProcess()).evtime() <= _time)) {
  137.                                 //System.out.println("Activate at ha deciso che " + _process.toString() + " va dopo di " + (tmpThread.eventProcess()).toString());
  138.                                 tmpThread = tmpThread.nextThread();
  139.                         }
  140.                 }
  141.  
  142.                 if (tmpThread == null) { // This thread gets the last place
  143.                         //System.out.println("Activate at mette " + _process.toString() + " all'ultimo posto");
  144.                         lastThread.nextThread(_Thread);
  145.                         _Thread.prevThread(lastThread);
  146.                         _Thread.nextThread(null);
  147.                         lastThread = _Thread;
  148.  
  149.                 } else {  // given _Thread has to be scheduled BEFORE tmpThread
  150.  
  151.                         //System.out.println("Activate at mette " + _process.toString() + " subito prima di " + (tmpThread.eventProcess()).toString());
  152.                         (tmpThread.prevThread()).nextThread(_Thread);
  153.                         _Thread.prevThread(tmpThread.prevThread());
  154.                         _Thread.nextThread(tmpThread);
  155.                         tmpThread.prevThread(_Thread);
  156.                 }
  157.         }
  158.         /**
  159.          * Activates the first given process before the second one.
  160.          * @param _P Process to be activated.
  161.          * @param _Q Process to be preceded.
  162.          * @exception SimulaException Fired if already active or unable to activate.
  163.          */
  164.         public void activate_before(Process _P, Process _Q) throws SimulaException {
  165.                 if (_Q.idle()) throw new SimulaException(SimulaException.IDLE_PROCESS);
  166.                 activate_at(_P, _Q.evtime(), true);
  167.         }
  168.         /**
  169.          * Activates the given process at the given time from now.
  170.          * @param _process Process to be activated.
  171.          * @param _delay Time of activation from now.
  172.          * @param _prior If <code>True</a> consider the time like an exclusive bound.
  173.          * @exception SimulaException Fired if unable to activate.
  174.          */
  175.         public void activate_delay(Process _process, double _delay, boolean _prior) throws SimulaException {
  176.                 activate_at(_process, this.time() + _delay, _prior);
  177.         }
  178.         /**
  179.          * Cancel the given process from the event list.
  180.          * @param _process Process to be cancelled.
  181.          * @exception SimulaException There was an attempt to passivate the main process of the simulation.
  182.          */
  183.         public void cancel(Process _process) throws SimulaException {
  184.                 // Cancel called on first process of the event list is equal to a Passivate
  185.                 if (_process == currProcess) {
  186.                         passivate();
  187.                 } else {
  188.  
  189.                         EventThread _Thread = _process.processThread();
  190.                         EventThread tmpThread = firstThread;
  191.  
  192.                         // Scan the event list to find the given thread
  193.                         while (tmpThread.nextThread() != null) {
  194.                                 if (tmpThread == _Thread) break;
  195.                                 tmpThread = tmpThread.nextThread();
  196.                         }
  197.  
  198.                         if (tmpThread != null) { // The given thread has been found in the event list so..
  199.  
  200.                                 //System.out.println("CANCEL : " + _process.toString() + " sta per essere rimosso ");
  201.                                 _process.setStatus(Process.PASSIVE); // ..it is passivated
  202.                                 _process.evtime(0);
  203.  
  204.                                 //System.out.println("CANCEL : " + _process.toString() + " aveva come prev " + ((_Thread.prevThread()).eventProcess()).toString());
  205.                                 (_Thread.prevThread()).nextThread(_Thread.nextThread());
  206.  
  207.                                 if (_Thread.nextThread() == null) { // the given Thread was the last in event list
  208.                                         lastThread = _Thread.prevThread();
  209.                                         lastThread.nextThread(null);
  210.                                 } else {
  211.                                         (_Thread.nextThread()).prevThread(_Thread.prevThread());
  212.                                 }
  213.  
  214.                                 _Thread.prevThread(null);
  215.                                 _Thread.nextThread(null);
  216.                         }
  217.                 }
  218.         }
  219.         // ----------------------------------- Accessors -----------------------------------
  220.         /**
  221.          * Returns the currently active process.
  222.          * @return the currently active process.
  223.          */
  224.         public Process current() { return currProcess; }
  225. /**
  226.  * Kills all sctive threads. 
  227.  * Can' t be called by a Proceess or a Mainprocess, because it while try to kill the active thread too.
  228.  * should be used by a UI to kill all processes and MainProcess
  229.  * If called from an applet it will trhow an exception;  to avoid this install a security manager
  230.  * @exception SimulaException If thre is problems while unscheduling processes.
  231.  * @since 2.0
  232.  */
  233. public void destroy ( ) throws SimulaException  {
  234.     //if (this.maingroup!=null)
  235.         //this.maingroup.stop() ;
  236.         
  237.     ThreadGroup g=this.firstThread.getThreadGroup() ;
  238.     g.stop() ;
  239.     this.end() ;
  240.     
  241.     this.currProcess=null;
  242.       this.firstThread=null;
  243.     this.lastThread=null;
  244.     return;
  245. }
  246.         /**
  247.          * Debug function used to dump scheduling informations.
  248.          */
  249.         protected void dump() {
  250.                 EventThread tmpThread = firstThread;
  251.  
  252.                 System.out.println("DUMP ******************>>>>>>>>>>>");
  253.                 while (tmpThread != null) {
  254.                         System.out.print((tmpThread.eventProcess()).toString() + " -> ");
  255.                         tmpThread = tmpThread.nextThread();
  256.                 }
  257.                 System.out.println(";");
  258.  
  259.                 tmpThread = lastThread;
  260.  
  261.                 System.out.println("DUMP <<<<<<<<<<<<<<<<<*************");
  262.                 while (tmpThread != null) {
  263.                         System.out.print((tmpThread.eventProcess()).toString() + " <- ");
  264.                         tmpThread = tmpThread.prevThread();
  265.                 }
  266.                 System.out.println(";");
  267.         }
  268. /**
  269.  * Kills all sctive threads. 
  270.  * Can' t be called by a Proceess, because it while try to kill the active thread too.
  271.  * It shold be called in the last instruction of <code> SimulationMain </code>, to ensure that
  272.  * there are no zombi threads.
  273.  * @exception SimulaException If thre is problems while unscheduling processes
  274.  * @since 2.0
  275.  */
  276. public void end ( ) throws SimulaException  {
  277. //    System.err.println("Simulation : starting cleanup ") ;
  278.     EventThread first= this.firstThread ;
  279.     EventThread curr ;
  280.     Process p ;
  281.     EventThread next ;
  282.     
  283.     //System.err.println("Stopping processes") ;
  284.     //this.processes.stop() ;    
  285.     //System.err.println("Processes stopped") ;
  286.     
  287.     curr=this.firstThread ;
  288.     try {
  289.     while (curr!=null) {
  290.         next=curr.nextThread() ;
  291.         
  292.         if (!(curr.eventProcess() instanceof SimulationMain)) {
  293.             p=curr.eventProcess();
  294.             //System.err.println("Selected process "+p) ;
  295.             curr.stop() ;
  296.         //    System.err.println("Stopped "+curr) ;        
  297.             this.cancel(p) ;
  298.             //System.err.println("Unscheduled "+curr) ;
  299.             
  300.             /*p.end() ;
  301.             curr.end();
  302.             System.err.println("Killed "+curr) ;        */
  303.         }    
  304.         curr=next ;
  305.     }
  306.     } catch (    Exception e) {System.err.println("while killing : "+e);} ;
  307.     /*
  308.     curr=first ;
  309.     while (curr!=null) {
  310.         next=curr.nextThread() ;
  311.         if (!(curr.eventProcess() instanceof SimulationMain)) {
  312.             p=curr.eventProcess();
  313.             p.end() ;
  314.             curr.end();
  315.             System.err.println("Killed "+curr) ;
  316.         }    
  317.         curr=next ;
  318.     }
  319.     */
  320.         
  321.  
  322.     this.finished=true ;
  323.     //this.currProcess=null;
  324.       this.firstThread=null;
  325.     this.lastThread=null;    
  326.     //System.err.println("Simulation : finishing") ;
  327.     this.update() ;
  328.     return;
  329. }
  330. /**
  331.  * Returns the simulation status. Not to be confused with the old <code> SimulationMonitor.finished() </code>
  332.  * This reads the status, does not set it.
  333.  * @return boolean True is one of metods <code> end() <code> and </code> destroy() </code> has been called
  334.  * @since 2.0
  335.  */
  336. public boolean finished ( ) {
  337.     return this.finished;
  338. }
  339.         // ----------------------------------- Methods -----------------------------------
  340.         /**
  341.          * Suspends the currently active process for the given amount of time.
  342.          * And notify it to observers.
  343.          * @param _time The amount of time to hold the main process of the simulation.
  344.          * @exception SimulaException There is no active process in the simulation.
  345.          */
  346.         public void hold(double _time) throws SimulaException {
  347.                 
  348.                 // [AP2.0] notify the change to observers
  349.                 this.update() ;
  350.                 
  351.                 if (currProcess == null) {
  352.                         throw new SimulaException(SimulaException.NO_CURRENT_PROCESS);
  353.                 } else {
  354.                         // Passivate the current process
  355.                         EventThread currThread = currProcess.processThread();
  356.                         double tmpTime = currProcess.evtime() + _time;
  357.                         currProcess.evtime(tmpTime); // Set the scheduling time of caller process to its old time + _time
  358.                         currProcess.setStatus(Process.SUSPENDED);
  359.  
  360.                         if (currThread.nextThread() != null) { //This is not the only Thread in the event list
  361.  
  362.                                 // Reschedule the caller thread after _time
  363.                                 EventThread tmpThread = firstThread;
  364.                                 while (tmpThread != null && ((tmpThread.eventProcess()).evtime() <= tmpTime)) {
  365.                                         //System.out.println("Hold ha deciso che " + currProcess.toString() + " va dopo di " + (tmpThread.eventProcess()).toString());
  366.                                         tmpThread = tmpThread.nextThread();
  367.                                 }
  368.                                 if (tmpThread == null) { // This thread gets the last place
  369.                                         //System.out.println("Hold mette " + currProcess.toString() + " all'ultimo posto");
  370.                                         firstThread = currThread.nextThread();
  371.                                         lastThread.nextThread(currThread);
  372.                                         currThread.prevThread(lastThread);
  373.                                         currThread.nextThread(null);
  374.                                         lastThread = currThread;
  375.                                 } else {  // This thread has to be scheduled BEFORE tmpThread
  376.  
  377.                                         //System.out.println("Hold mette " + currProcess.toString() + " subito prima di " + (tmpThread.eventProcess()).toString());
  378.                                         // the former second thread becomes the first UNLESS the held thread still has the lowest time
  379.                                         if (tmpThread.prevThread() != currThread) {
  380.                                                 firstThread = currThread.nextThread();
  381.                                                 firstThread.prevThread(null);
  382.  
  383.                                                 currThread.nextThread(tmpThread);
  384.                                                 currThread.prevThread(tmpThread.prevThread());
  385.  
  386.                                                 (currThread.prevThread()).nextThread(currThread);
  387.                                                 tmpThread.prevThread(currThread);
  388.  
  389.                                         }
  390.                                 }
  391.  
  392.                                 // Activate the next thread in event list with the related process
  393.  
  394.                                 //if (firstThread == null) System.out.println("FIRST e' nullo !");
  395.  
  396.                                 firstThread.prevThread(null);
  397.  
  398.                                 currProcess = firstThread.eventProcess();
  399.                                 currProcess.setStatus(Process.ACTIVE);
  400.  
  401.                                 //dump();
  402.                                 //System.out.println("HOLD: sta per far partire : " + currProcess.toString());
  403.  
  404.                                 if (currThread != firstThread) {
  405.                                         if (firstThread.isAlive()) {
  406.                                                 firstThread.resume();
  407.                                         } else {
  408.                                                 firstThread.start();
  409.                                         }
  410.                                         currThread.suspend();
  411.                                 }
  412.                         }
  413.                 }
  414.         }
  415.         /**
  416.          * Passivate the currently active process.
  417.          * And notify it to observers.
  418.          * @exception SimulaException There was an attempt to passivate the main process of the simulation.
  419.          */
  420.         public void passivate() throws SimulaException {
  421.                 if (currProcess instanceof SimulationMain) throw new SimulaException(SimulaException.MAIN_PASSIVATED);
  422.  
  423.                 // [AP2.0] notify the change to observers
  424.                 this.update() ;
  425.                 
  426.                 EventThread callerThread = currProcess.processThread();
  427.                 currProcess.setStatus(Process.PASSIVE);
  428.                 currProcess.evtime(0);
  429.  
  430.                 // Activate the next thread in event list with the related process
  431.                 firstThread = callerThread.nextThread();
  432.  
  433.                 // Caller Thread gets out the event list
  434.                 callerThread.nextThread(null);
  435.                 callerThread.prevThread(null);
  436.  
  437.                 // [AP] if there is more than one process
  438.                 if (firstThread == null ){
  439.                         //System.out.println("Simulation: io avrei finito...");
  440.                         System.exit(1); // No more process in evenbt list
  441.                 } else {
  442.          //System.out.println("Simulation.passivate : adesso ariva l' eccezione") ;
  443.          firstThread.prevThread(null);
  444.          //System.out.println("Simulation.passivate : qui non ci arrivi !") ;
  445.          currProcess = firstThread.eventProcess();
  446.          currProcess.setStatus(Process.ACTIVE);
  447.          if (firstThread.isAlive()) {
  448.                                 firstThread.resume();
  449.                         } else {
  450.                                 firstThread.start();
  451.                         }
  452.                 }
  453.                 callerThread.suspend();
  454.         }
  455.         /**
  456.          * Reactivate immediately the given process.
  457.          * And notify it to observers.
  458.          * @param _process Process to be reactivated.
  459.          * @exception SimulaException Fired if unable to cancel or activate the process.
  460.          */
  461.         public void reactivate(Process _process) throws SimulaException {
  462.                 //[AP2.0] Notify change
  463.                 this.update() ;
  464.                 if (_process != currProcess) {
  465.                         cancel(_process); // Pulls out the process if it is already scheduled
  466.                         activate(_process); // Now get that on top of event list
  467.                 }
  468.         }
  469.         /**
  470.          * Reactivates the first given process after the second one.
  471.          * @param _P Process to be activated.
  472.          * @param _Q Process to be preceded.
  473.          * @exception SimulaException Fired if already active or unable to reactivate.
  474.          */
  475.         public void reactivate_after(Process _P, Process _Q) throws SimulaException {
  476.                 if (_Q.idle()) throw new SimulaException(SimulaException.IDLE_PROCESS);
  477.                 reactivate_at(_P, _Q.evtime(), false);
  478.         }
  479.         /**
  480.          * Reactivate the given process at the given time.
  481.          * @param _process Process to be reactivated.
  482.          * @param _time Wanted time of activation.
  483.          * @param _prior If <code>True</a> consider the time like an exclusive bound.
  484.          * @exception SimulaException Fired if unable to cancel or activate the process.
  485.          */
  486.         public void reactivate_at(Process _process, double _time, boolean _prior) throws SimulaException {
  487.                 if (_process != currProcess) {
  488.                         cancel(_process); // Pulls out the process if it is already scheduled
  489.                         activate_at(_process, _time, _prior); // Now get that on top of event list
  490.                 }
  491.         }
  492.         /**
  493.          * Reactivates the first given process before the second one.
  494.          * @param _P Process to be activated.
  495.          * @param _Q Process to be preceded.
  496.          * @exception SimulaException Fired if already active or unable to reactivate.
  497.          */
  498.         public void reactivate_before(Process _P, Process _Q) throws SimulaException {
  499.                 if (_Q.idle()) throw new SimulaException(SimulaException.IDLE_PROCESS);
  500.                 reactivate_at(_P, _Q.evtime(), true);
  501.         }
  502.         /**
  503.          * Reactivate the given process at the given time from now.
  504.          * @param _process Process to be reactivated.
  505.          * @param _delay Time of activation from now.
  506.          * @param _prior If <code>True</a> consider the time like an exclusive bound.
  507.          * @exception SimulaException Fired if unable to reactivate.
  508.          */
  509.         public void reactivate_delay(Process _process, double _delay, boolean _prior) throws SimulaException {
  510.                 reactivate_at(_process, this.time() + _delay, _prior);
  511.         }
  512.         /**
  513.          * Returns the time from the beginning of the simulation.
  514.          * @return the time from the beginning of the simulation.
  515.          * @exception SimulaException If there is no process currently active.
  516.          */
  517.         public double time() throws SimulaException {
  518.                 if (currProcess == null) {
  519.                         throw new SimulaException(SimulaException.NO_CURRENT_PROCESS);
  520.                 } else return currProcess.evtime();
  521.         }
  522. /**
  523.  * Notify simulation status to observers (if there are any)
  524.  * It is called when a process passivates or holds
  525.  * The current active process is passed as parameter to the <code> update </code> call in observers.
  526.  * Can be called by a <code> Process </code> too, to force display update.
  527.  * @since 2.0
  528.  */
  529. public void update ( ) {
  530.     this.setChanged() ;
  531.     this.notifyObservers(currProcess) ;
  532.     return;
  533. }
  534.         /**
  535.          * Adds the current process to the given waiting list and passivates it.
  536.          * And notify it to observers.
  537.          * @param _list List where the current process will be added to.
  538.          * @exception SimulaException Fired if unable to insert or passivate the current process.
  539.          */
  540.         public void wait(Head _list) throws SimulaException {
  541.                 //[AP2.0] notify
  542.                 this.update() ;
  543.                 currProcess.into(_list);
  544.                 this.passivate();
  545.         }
  546. } // End of class Simulation
  547.