1 | package desmoj.core.simulator; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.Enumeration; |
5 | import java.util.Vector; //TODO: oder dem Anwender �berlassen...? |
6 | |
7 | import desmoj.core.advancedModellingFeatures.Res; |
8 | import desmoj.core.report.ErrorMessage; |
9 | |
10 | /** |
11 | * Sim-process represents entities with an own active lifecycle. Since |
12 | * Sim-processes are in fact special entities with extended capabilities (esp. |
13 | * the method <tt>lifeCycle()</tt>), they inherit from Entity and thus can also be used |
14 | * in conjunction with events. So they can be handled in both ways, event- and |
15 | * process-oriented. Clients are supposed to implement the lifeCycle() method to |
16 | * specify the individual behaviour of a special SimProcess subclass. Since |
17 | * implementing activity- and transaction-oriented synchronization mechanisms |
18 | * requires significant changes in this class, methods that have been |
19 | * implemented by Soenke Claassen have been marked. |
20 | * |
21 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
22 | * @author Tim Lechler. |
23 | * @author Methods: canCooperate, clearInterruptCode, cooperate, |
24 | * getInterruptCode, getMaster, getSlaveWaitQueue, IsInterrupted, |
25 | * resetMaster and setSlaveWaitQueue by Soenke Claassen |
26 | * |
27 | * Licensed under the Apache License, Version 2.0 (the "License"); |
28 | * you may not use this file except in compliance with the License. You |
29 | * may obtain a copy of the License at |
30 | * http://www.apache.org/licenses/LICENSE-2.0 |
31 | * |
32 | * Unless required by applicable law or agreed to in writing, software |
33 | * distributed under the License is distributed on an "AS IS" |
34 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
35 | * or implied. See the License for the specific language governing |
36 | * permissions and limitations under the License. |
37 | * |
38 | */ |
39 | public abstract class SimProcess extends Entity { |
40 | |
41 | /** |
42 | * The Thread needed for implementing coroutine behaviour. |
43 | */ |
44 | private Thread _myThread; |
45 | |
46 | /** |
47 | * Displays the current blocked status of this SimProcess. A sim-process is |
48 | * blocked whenever it has to wait inside a queue or synchronization object. |
49 | */ |
50 | private boolean _isBlocked; |
51 | |
52 | /** |
53 | * Displays the current status of this SimProcess. Is <code>true</code> if |
54 | * lifeCycle method has finished, <code>false</code> if it is still running |
55 | * or has not been started yet |
56 | */ |
57 | private boolean _isTerminated; |
58 | |
59 | /** |
60 | * Displays if the thread in of control of this SimProcess is already the |
61 | * associated simthread. Is <code>true</code> if the simthread is active and |
62 | * is carrying on its lifeCycle. Is <code>false</code> if it has not started |
63 | * its lifeCycle yet or is terminated already. |
64 | */ |
65 | private boolean _isRunning; |
66 | |
67 | /** |
68 | * If this SimProcess is cooperating as a slave with a master process, it |
69 | * keeps a reference to its master here. Master is set in the |
70 | * <code>cooperate()</code> -method, when the slave cooperates with his |
71 | * master and deleted every time the slave process is activated. |
72 | * |
73 | * @author Soenke Claassen |
74 | */ |
75 | private SimProcess _master; |
76 | |
77 | /** |
78 | * If this SimProcess is cooperating as a slave it has to wait in this |
79 | * waitQueue until a master is cooperating with it. |
80 | * |
81 | * @author Soenke Claassen |
82 | */ |
83 | private ProcessQueue<? extends SimProcess> _slaveWaitQueue; |
84 | |
85 | /** |
86 | * The <code>InterruptCode</code> with which this SimProcess is interrupted. |
87 | * |
88 | * @author Soenke Claassen |
89 | */ |
90 | private InterruptCode _irqCode; |
91 | |
92 | /** |
93 | * The <code>Vector</code> holding all the resources this SimProcess is |
94 | * using at the moment. |
95 | * |
96 | * @author Soenke Claassen |
97 | */ |
98 | private Vector<Resource> _usedResources; |
99 | |
100 | /** |
101 | * A reference to the container this SimProcess belongs to. Is |
102 | * <code>null</code> as long as this SimProcess is not contained in any |
103 | * <code>ComplexSimProcess</code>. |
104 | * |
105 | * @author Soenke Claassen |
106 | */ |
107 | private ComplexSimProcess _supervisor; |
108 | |
109 | /** |
110 | * The realTime deadline for this SimProcess in nanoseconds. In case of a |
111 | * real-time execution (i. e. the execution speed rate is set to a positive |
112 | * value) the Scheduler will produce a warning message if a deadline is |
113 | * missed. |
114 | */ |
115 | private long _realTimeConstraint; |
116 | |
117 | /** |
118 | * Constructs a sim-process. |
119 | * |
120 | * @param name |
121 | * java.lang.String : The name of the sim-process |
122 | * @param owner |
123 | * Model : The model this SimProcess is associated to |
124 | * @param showInTrace |
125 | * boolean : Flag for showing SimProcess in trace-files. Set it |
126 | * to <code>true</code> if SimProcess should show up in trace. |
127 | * Set it to <code>false</code> if SimProcess should not be shown |
128 | * in trace. |
129 | */ |
130 | public SimProcess(Model owner, String name, boolean showInTrace) { |
131 | |
132 | super(owner, name, showInTrace); |
133 | |
134 | // init variables |
135 | _isBlocked = false; // not waiting in queue so far |
136 | _isRunning = false; // not running so far |
137 | _isTerminated = false; // not terminated either |
138 | _master = null; // this SimProcess has no master, so far |
139 | _slaveWaitQueue = null; // this SimProcess is not waiting in any queue |
140 | _irqCode = null; // this is not interrupted |
141 | |
142 | // set up simthread |
143 | _myThread = new SimThread(getModel().getExperiment().getThreadGroup(), |
144 | this); |
145 | |
146 | // set up the Vector holding the used Resources |
147 | _usedResources = new Vector<Resource>(); |
148 | |
149 | // this SimProcess is not contained in any ComplexSimProcess yet |
150 | _supervisor = null; |
151 | |
152 | } |
153 | |
154 | /** |
155 | * Used to synchronize the change of control between scheduler and |
156 | * Sim-processes. This method must only be called by the scheduler resp. the |
157 | * experiment's main thread in order to prevent multiple SimProcess' threads |
158 | * running in parallel which has to be avoided. |
159 | */ |
160 | synchronized void resume() { |
161 | |
162 | // check that the SimThread has not finished yet |
163 | if (_isTerminated) { |
164 | sendWarning( |
165 | "Can't activate SimProcess! Command ignored.", |
166 | "SimProcess : " + getName() + " Method: void resume()", |
167 | "The sim-process' lifeCycle method has already terminated.", |
168 | "Be sure to check the sim-process' status before resuming." |
169 | + " Use method isTerminated() to check the current status"); |
170 | return; |
171 | } |
172 | |
173 | // wake up the SimThread waiting in a block for the sim-process' lock |
174 | // to be released |
175 | notify(); |
176 | |
177 | // now go wait until the next notification by the SimThread |
178 | // of this SimProcess |
179 | try { |
180 | wait(); |
181 | } catch (InterruptedException irqEx) { // must be caught when using |
182 | // wait |
183 | // create eror message |
184 | ErrorMessage errmsg = new ErrorMessage(getModel(), |
185 | "Simulation stopped!", |
186 | "InterruptedException thrown by Java VM : " + irqEx, |
187 | "Thread conflict assumed.", "Check Java VM.", presentTime()); |
188 | // throw it back to Experiment's start routine |
189 | throw (new desmoj.core.exception.DESMOJException(errmsg)); |
190 | } |
191 | |
192 | } |
193 | |
194 | /** |
195 | * Schedules the sim-process to be activated at the specified point in |
196 | * simulation time. The point of time is given as an offset to the current |
197 | * simulation time. This will allow a sim-process to continue executing its |
198 | * <code>lifeCycle</code> method. Thus in contrast to the entity, no Event |
199 | * is needed for scheduling here. |
200 | * |
201 | * @param dt |
202 | * TimeSpan : The offset to the current simulation time this |
203 | * process is to be activated |
204 | */ |
205 | public void activate(TimeSpan dt) { |
206 | if (isBlocked()) { |
207 | sendWarning( |
208 | "Can't activate SimProcess! Command ignored.", |
209 | "SimProcess : " + getName() |
210 | + " Method: activate(TimeSpan dt)", |
211 | "The sim-process to be activated is blocked inside " |
212 | + "a higher level synchronization object.", |
213 | "Simprocesses waiting inside higher synchronization " |
214 | + "constructs can not be activated by other SimProcesses or " |
215 | + "events!"); |
216 | return; // is blocked in some synch construction |
217 | } |
218 | |
219 | if (dt == null) { |
220 | sendWarning( |
221 | "Can't activate SimProcess! Command ignored.", |
222 | "SimProcess : " + getName() + " Method: void activate" |
223 | + "(TimeSpan dt)", |
224 | "The simulation time given as parameter is a null reference", |
225 | "Be sure to have a valid simulation time reference before " |
226 | + "calling this method"); |
227 | return; // no proper parameter |
228 | } |
229 | // tell in the trace when the sim-process will be activated |
230 | if (currentlySendTraceNotes()) { |
231 | if (this == currentSimProcess()) { |
232 | if (dt == TimeSpan.ZERO) { |
233 | sendTraceNote("activates itself immediately (NOW)"); |
234 | } else { |
235 | if (TimeSpan.isEqual(dt, TimeSpan.ZERO)) { |
236 | sendTraceNote("activates itself now"); |
237 | } else { |
238 | sendTraceNote("activates itself at " |
239 | + TimeOperations.add(presentTime(), dt) |
240 | .toString()); |
241 | } |
242 | } |
243 | } else { // this is not the currently running SimProcess |
244 | |
245 | if (dt == TimeSpan.ZERO) { |
246 | sendTraceNote("activates " + getQuotedName() |
247 | + " immediately (NOW)"); |
248 | } else { |
249 | if (TimeSpan.isEqual(dt, TimeSpan.ZERO)) { |
250 | sendTraceNote("activates " + getQuotedName() + " now"); |
251 | } else { |
252 | sendTraceNote("activates " |
253 | + getQuotedName() |
254 | + " at " |
255 | + TimeOperations.add(presentTime(), dt) |
256 | .toString()); |
257 | } |
258 | } |
259 | } |
260 | } |
261 | |
262 | // schedule this SimProcess |
263 | getModel().getExperiment().getScheduler().schedule(this, null, dt); |
264 | |
265 | // debug output |
266 | if (currentlySendDebugNotes()) { |
267 | sendDebugNote("is activated on EventList<br>" |
268 | + getModel().getExperiment().getScheduler().toString()); |
269 | } |
270 | |
271 | resetMaster(); // if activate(TimeSpan dt) is called for this |
272 | // SimProcess, |
273 | // there is no Master anymore controlling it. |
274 | |
275 | } |
276 | |
277 | /** |
278 | * Schedules the sim-process to be activated at the present point in |
279 | * simulation time, yielding the same result as calling |
280 | * <code>activate(new TimeSpan(0))</code>. The process will continue executing |
281 | * its <code>lifeCycle</code> method. |
282 | */ |
283 | public void activate() { |
284 | if (isBlocked()) { |
285 | sendWarning( |
286 | "Can't activate SimProcess! Command ignored.", |
287 | "SimProcess : " + getName() |
288 | + " Method: activate()", |
289 | "The sim-process to be activated is blocked inside " |
290 | + "a higher level synchronization object.", |
291 | "Simprocesses waiting inside higher synchronization " |
292 | + "constructs can not be activated by other SimProcesses or " |
293 | + "events!"); |
294 | return; // is blocked in some synch construction |
295 | } |
296 | |
297 | // tell in the trace when the sim-process will be activated |
298 | if (currentlySendTraceNotes()) { |
299 | if (this == currentSimProcess()) { |
300 | sendTraceNote("activates itself now"); |
301 | } else { // this is not the currently running SimProcess |
302 | sendTraceNote("activates " + getQuotedName() + " now"); |
303 | } |
304 | } |
305 | |
306 | // schedule this SimProcess |
307 | getModel().getExperiment().getScheduler().schedule(this, null, new TimeSpan(0)); |
308 | |
309 | // debug output |
310 | if (currentlySendDebugNotes()) { |
311 | sendDebugNote("is activated on EventList<br>" |
312 | + getModel().getExperiment().getScheduler().toString()); |
313 | } |
314 | |
315 | resetMaster(); // if activate(TimeSpan dt) is called for this |
316 | // SimProcess, |
317 | // there is no Master anymore controlling it. |
318 | } |
319 | |
320 | /** |
321 | * Schedules the sim-process to be activated at the given point in simulation |
322 | * time. This will allow a sim-process to continue executing its |
323 | * <code>lifeCycle</code> method. |
324 | * |
325 | * @param when |
326 | * TimeInstant : The point in simulation time this process is to |
327 | * be activated. |
328 | */ |
329 | public void activate(TimeInstant when) { |
330 | if (isBlocked()) { |
331 | sendWarning( |
332 | "Can't activate SimProcess! Command ignored.", |
333 | "SimProcess : " + getName() |
334 | + " Method: activate(TimeInstant when)", |
335 | "The sim-process to be activated is blocked inside " |
336 | + "a higher level synchronization object.", |
337 | "Simprocesses waiting inside higher synchronization " |
338 | + "constructs can not be activated by other SimProcesses or " |
339 | + "events!"); |
340 | return; // is blocked in some synch construction |
341 | } |
342 | |
343 | if (when == null) { |
344 | sendWarning( |
345 | "Can't activate SimProcess! Command ignored.", |
346 | "SimProcess : " + getName() + " Method: void activate" |
347 | + "(TimeInstant when)", |
348 | "The simulation time given as parameter is a null reference", |
349 | "Be sure to have a valid simulation time reference before " |
350 | + "calling this method"); |
351 | return; // no proper parameter |
352 | } |
353 | // tell in the trace when the sim-process will be activated |
354 | if (currentlySendTraceNotes()) { |
355 | if (this == currentSimProcess()) { |
356 | if (when == presentTime()) { |
357 | sendTraceNote("activates itself immediately (NOW)"); |
358 | } else { |
359 | if (TimeInstant.isEqual(when, presentTime())) { |
360 | sendTraceNote("activates itself now"); |
361 | } else { |
362 | sendTraceNote("activates itself at " + when.toString()); |
363 | |
364 | } |
365 | } |
366 | } else { // this is not the currently running SimProcess |
367 | |
368 | if (when == presentTime()) { |
369 | sendTraceNote("activates " + getQuotedName() |
370 | + " immediately (NOW)"); |
371 | } else { |
372 | // stand auch oben: if (dt.getTimeValue() == 0.0) { |
373 | if (TimeInstant.isEqual(when, presentTime())) { |
374 | sendTraceNote("activates " + getQuotedName() + " now"); |
375 | } else { |
376 | sendTraceNote("activates " + getQuotedName() + " at " |
377 | + when.toString()); |
378 | } |
379 | } |
380 | } |
381 | } |
382 | |
383 | // schedule this SimProcess |
384 | getModel().getExperiment().getScheduler().schedule(this, null, when); |
385 | |
386 | // debug output |
387 | if (currentlySendDebugNotes()) { |
388 | sendDebugNote("is activated on EventList<br>" |
389 | + getModel().getExperiment().getScheduler().toString()); |
390 | } |
391 | |
392 | resetMaster(); // if activate(TimeInstant when) is called for this |
393 | // SimProcess, |
394 | // there is no Master anymore controlling it. |
395 | } |
396 | |
397 | /** |
398 | * @deprecated Replaced by activate(TimeSpan dt). Schedules the sim-process |
399 | * to be activated at the given time offset to the current |
400 | * simulation time. This will allow a sim-process to continue |
401 | * executing its <code>lifeCycle</code> method. |
402 | * |
403 | * @param dt |
404 | * SimTime : The offset to the current simulation time that this |
405 | * SimProcess is due to be activated |
406 | */ |
407 | @Deprecated |
408 | public void activate(SimTime dt) { |
409 | activate(SimTime.toTimeSpan(dt)); |
410 | |
411 | } |
412 | |
413 | /** |
414 | * Schedules this SimProcess to be activated directly after the given |
415 | * Schedulable, which itself is already scheduled. Note that this |
416 | * Sim-process' point of simulation time will be set to be the same as the |
417 | * Schedulable's time. Thus this SimProcess will continue to execute its |
418 | * <code>lifeCycle</code> method directly after the given Schedulable but |
419 | * the simulation clock will not change. Please make sure that the |
420 | * Schedulable given as parameter is actually scheduled. |
421 | * |
422 | * @param after |
423 | * Schedulable : The Schedulable this SimProcess should be |
424 | * scheduled after |
425 | */ |
426 | public void activateAfter(Schedulable after) { |
427 | |
428 | if (after == null) { |
429 | sendWarning( |
430 | "Can't activate this SimProcess after the given SimProcess " |
431 | + "parameter! Command ignored.", "SimProcess : " |
432 | + getName() + " Method: void " |
433 | + "activateAfter(Schedulable after)", |
434 | "The Schedulable given as parameter is a null reference", |
435 | "Be sure to have a valid Schedulable reference before " |
436 | + "calling this method"); |
437 | return; // no proper parameter |
438 | } |
439 | |
440 | if (isBlocked()) { |
441 | sendWarning( |
442 | "Can't activate SimProcess! Command ignored.", |
443 | "SimProcess : " + getName() |
444 | + " Method: void activateAfter(Schedulable after)", |
445 | "The sim-process to be activated is blocked inside " |
446 | + "a higher level synchronization object.", |
447 | "Simprocesses waiting inside higher synchronization " |
448 | + "constructs can not be activated by other SimProcesses or " |
449 | + "events!"); |
450 | return; // is blocked in some synch construction |
451 | } |
452 | |
453 | if (currentlySendTraceNotes()) { |
454 | if (this == currentSimProcess()) { |
455 | sendTraceNote("activates itself after " + getQuotedName()); |
456 | } else { |
457 | sendTraceNote("activates " + getQuotedName() + " after " |
458 | + after.getQuotedName()); |
459 | } |
460 | } |
461 | |
462 | // schedule this SimProcess |
463 | getModel().getExperiment().getScheduler().scheduleAfter(after, this, |
464 | null); |
465 | |
466 | if (currentlySendDebugNotes()) { |
467 | sendDebugNote("is activated after " + after.getQuotedName() |
468 | + " on EventList<br>" |
469 | + getModel().getExperiment().getScheduler().toString()); |
470 | } |
471 | |
472 | } |
473 | |
474 | /** |
475 | * Schedules this SimProcess to be activated directly before the given |
476 | * Schedulable, which itself is already scheduled. Note that this |
477 | * Sim-process' point of simulation time will be set to be the same as the |
478 | * Schedulable's time. Thus this SimProcess will continue to execute its |
479 | * <code>lifeCycle</code> method directly before the given Schedulable but |
480 | * the simulation clock will not change. Please make sure that the |
481 | * Schedulable given as parameter is actually scheduled. |
482 | * |
483 | * @param before |
484 | * Schedulable : The Schedulable this SimProcess should be |
485 | * scheduled before |
486 | */ |
487 | public void activateBefore(Schedulable before) { |
488 | |
489 | if (before == null) { |
490 | sendWarning("Can't activate this SimProcess before the given " |
491 | + "SimProcess parameter", "SimProcess : " + getName() |
492 | + " Method: void activateBefore" + "(Schedulable before)", |
493 | "The Schedulable given as parameter is a null reference", |
494 | "Be sure to have a valid Schedulable reference before " |
495 | + "calling this method"); |
496 | return; // no proper parameter |
497 | } |
498 | |
499 | if (isBlocked()) { |
500 | sendWarning( |
501 | "Can't activate SimProcess! Command ignored.", |
502 | "SimProcess : " |
503 | + getName() |
504 | + " Method: void activateBefore(Schedulable before)", |
505 | "The sim-process to be activated is blocked inside " |
506 | + "a higher level synchronization object.", |
507 | "Simprocesses waiting inside higher synchronization " |
508 | + "constructs can not be activated by other SimProcesses or " |
509 | + "events!"); |
510 | return; // is blocked in some synch construction |
511 | } |
512 | |
513 | if (currentlySendTraceNotes()) { |
514 | if (this == currentSimProcess()) { |
515 | sendTraceNote("activates itself before " |
516 | + before.getQuotedName()); |
517 | } else { |
518 | sendTraceNote("activates " + getQuotedName() + " before " |
519 | + before.getQuotedName()); |
520 | } |
521 | } |
522 | |
523 | // schedule this SimProcess |
524 | getModel().getExperiment().getScheduler().scheduleBefore(before, this, |
525 | null); |
526 | |
527 | if (currentlySendDebugNotes()) { |
528 | sendDebugNote("activateBefore " + before.getQuotedName() |
529 | + " on EventList<br>" |
530 | + getModel().getExperiment().getScheduler().toString()); |
531 | } |
532 | |
533 | // hand control over to scheduler only if this is |
534 | // a running thread of SimProcess |
535 | // if ( isRunning ) passivate(); |
536 | |
537 | resetMaster(); // if activateBefore() is called for this SimProcess, |
538 | // there is no Master anymore controlling it. |
539 | |
540 | } |
541 | |
542 | /** |
543 | * Returns <code>true</code> if this process can cooperate with another |
544 | * Sim-process. If this process is already cooperating with a master |
545 | * <code>false</code> is returned. |
546 | * |
547 | * @return boolean : Is this process ready to cooperate with another |
548 | * SimProcess? |
549 | * @author Soenke Claassen |
550 | */ |
551 | public boolean canCooperate() { |
552 | return _master == null; // if the master is not set yet this SimProcess |
553 | // can cooperate with another SimProcess |
554 | } |
555 | |
556 | /** |
557 | * Resets the interrupt-status of this SimProcess to not interrupted. Should |
558 | * be called every time the sim-process has successfully dealt with the |
559 | * interrupt. The internal <code>InterruptCode</code> of this SimProcess |
560 | * will be reset to <code>null</code>. |
561 | * |
562 | * @author Soenke Claassen |
563 | */ |
564 | public void clearInterruptCode() { |
565 | this._irqCode = null; |
566 | } |
567 | |
568 | /** |
569 | * The current (master) process is calling this method (within |
570 | * <code>WaitQueue.cooperate()</code>) on the slave process to lead him |
571 | * through the joint cooperation. After the joint cooperation is finished |
572 | * the master is still active and after him the slave will be activated. |
573 | * |
574 | * @author Soenke Claassen |
575 | */ |
576 | public void cooperate() { |
577 | // this is the slave and current the master |
578 | |
579 | // check if this slave already has a master |
580 | if (this._master != null) { |
581 | sendWarning( |
582 | "Slaves can not cooperate with more than one master at a " |
583 | + "time! The attempted cooperation is ignored.", |
584 | "SimProcess : " + getName() + " Method: cooperate () ", |
585 | "This slave process is already cooperating with another " |
586 | + "master: " + _master.getName(), |
587 | "Be sure to have finished one cooperation before starting " |
588 | + "the next one."); |
589 | return; // this process has a master already |
590 | } |
591 | |
592 | // check if this slave is not terminated yet |
593 | if (this._isTerminated) { |
594 | sendWarning( |
595 | "Attempt to cooperate with a terminated slave process! " |
596 | + "The attempted cooperation is ignored.", |
597 | "SimProcess : " + getName() + " Method: cooperate () ", |
598 | "This slave process is already terminated.", |
599 | "Make sure not to cooperate with terminated processes."); |
600 | return; // this process is already terminated |
601 | } |
602 | |
603 | // check the master |
604 | SimProcess currentMaster = currentSimProcess(); // the current master |
605 | // process |
606 | if (currentMaster == null) // if currentMaster is only a null pointer |
607 | { |
608 | sendWarning("A non existing process is trying to cooperate as a " |
609 | + "master! The attempted cooperation is ignored!", |
610 | "SimProcess : " + getName() + " Method: cooperate ()", |
611 | "The master process is only a null pointer.", |
612 | "Make sure that only real SimProcesses are cooperating with other " |
613 | + "processes. "); |
614 | return; // the currentMaster process is only a null pointer |
615 | } |
616 | |
617 | if (!isModelCompatible(currentMaster)) { |
618 | sendWarning( |
619 | "The given master SimProcess object does not " |
620 | + "belong to this model. The attempted cooperation is ignored!", |
621 | "SimProcess : " + getName() + " Method: cooperate ()", |
622 | "The master SimProcess is not modelcompatible.", |
623 | "Make sure that the processes all belong to this model."); |
624 | return; // the currentMaster is not modelcompatible |
625 | } |
626 | |
627 | // the slave must be waiting in a WaitQueue |
628 | if (_slaveWaitQueue == null) { |
629 | sendWarning( |
630 | "Attempt to cooperate with a slave process, that is not " |
631 | + "waiting in a WaitQueue. The attempted cooperation is ignored!", |
632 | "SimProcess : " + getName() + " Method: cooperate ()", |
633 | "Slave processes must wait in a WaitQueue before they can get into " |
634 | + "a cooperation.", |
635 | "Make sure that the slave processes are waiting in a WaitQueue."); |
636 | return; // the slave is not waiting in a queue |
637 | } |
638 | |
639 | // now prepare for the real cooperation |
640 | this._master = currentMaster; // set the master for this slave process |
641 | |
642 | // leave a note in the trace |
643 | if (_master.currentlySendTraceNotes()) { |
644 | // trace note for a cooperation without any special conditions |
645 | sendTraceNote("cooperates " + this.getQuotedName() + " from " |
646 | + _slaveWaitQueue.getQuotedName()); |
647 | } |
648 | |
649 | // get this slave out of his slaveWaitQueue |
650 | _slaveWaitQueue.remove(this); |
651 | // this slave process is not waiting in any slaveWaitingQueue anymore |
652 | _slaveWaitQueue = null; |
653 | // and therefore this slave process is not blocked anymore |
654 | this._isBlocked = false; |
655 | |
656 | } |
657 | |
658 | /** |
659 | * Method to release the waiting scheduler when the SimThread finishes. |
660 | */ |
661 | synchronized void freeThread() { |
662 | |
663 | notify(); // free the scheduler |
664 | |
665 | } |
666 | |
667 | /** |
668 | * Returns the InterruptCode from this SimProcess. If this SimProcess is not |
669 | * interrupted, the InterruptCode is <code>null</code>. |
670 | * |
671 | * @return irqCode : The InterruptCode of this SimProcess. |
672 | * @author Soenke Claassen |
673 | */ |
674 | public InterruptCode getInterruptCode() { |
675 | return _irqCode; |
676 | } |
677 | |
678 | /** |
679 | * Returns the master when two SimProcesses are cooperating. If this method |
680 | * is called on a sim-process which is not a slave <code>null</code> is |
681 | * returned. |
682 | * |
683 | * @return SimProcess : The master process during the cooperation or |
684 | * <code>null</code> if this process is not a slave process. |
685 | * @author Soenke Claassen |
686 | */ |
687 | public SimProcess getMaster() { |
688 | return _master; |
689 | } |
690 | |
691 | |
692 | /**Returns the realTime deadline for this SimProcess (in nanoseconds). In case of a |
693 | * real-time execution (i. e. the execution speed rate is set to a positive |
694 | * value) the Scheduler will produce a warning message if a deadline is |
695 | * missed. |
696 | * |
697 | * @return the realTimeConstraint in nanoseconds |
698 | */ |
699 | public long getRealTimeConstraint() { |
700 | return _realTimeConstraint; |
701 | } |
702 | |
703 | /** |
704 | * Returns the waiting-queue in which this SimProcess is waiting as a slave |
705 | * to cooperate with a master. If this method is called on a sim-process |
706 | * which is not a slave <code>null</code> is returned. |
707 | * |
708 | * @return ProcessQueue : The waiting-queue in which this SimProcess is |
709 | * waiting as a slave or <code>null</code> if this SimProcess is not |
710 | * waiting as a slave for cooperation. |
711 | * @author Soenke Claassen |
712 | */ |
713 | public ProcessQueue<? extends SimProcess> getSlaveWaitQueue() { |
714 | return _slaveWaitQueue; |
715 | } |
716 | |
717 | /** |
718 | * Returns the supervising <code>ComplexSimProcess</code> this SimProcess is |
719 | * contained in. |
720 | * |
721 | * @return desmoj.ComplexSimProcess : The supervising |
722 | * <code>ComplexSimProcess</code> this SimProcess is contained in. |
723 | * Is <code>null</code> if this SimProcess is not contained in any |
724 | * <code>ComplexSimProcess</code>. |
725 | * @author Soenke Claassen |
726 | */ |
727 | public ComplexSimProcess getSupervisor() { |
728 | |
729 | return _supervisor; |
730 | } |
731 | |
732 | /** |
733 | * Returns a clone of the internal <code>Vector</code> containing all the |
734 | * <code>Resource</code> objects this SimProcess is using at the moment. |
735 | * |
736 | * @return java.util.Vector : the internal <code>Vector</code> containing |
737 | * all the <code>Resource</code> objects this SimProcess is using at |
738 | * the moment. |
739 | * @author Soenke Claassen |
740 | */ |
741 | protected Vector<Resource> getUsedResources() { |
742 | |
743 | // clone the internal Vector |
744 | Vector<Resource> usedRes = (Vector<Resource>) _usedResources.clone(); |
745 | |
746 | // return the cloned Vector |
747 | return usedRes; |
748 | } |
749 | |
750 | /** |
751 | * Passivates a sim-process for the given span of time. The simthread of this |
752 | * Sim-process is put into a lock and the scheduler, resp. the experiment's |
753 | * main thread is released from its block and continues with the next |
754 | * EventNote to be processed. |
755 | * |
756 | * @param dt |
757 | * TimeSpan : The duration of the sim-process' passivation |
758 | */ |
759 | public void hold(TimeSpan dt) { |
760 | if ((dt == null)) { |
761 | sendWarning("Can't schedule SimProcess! Command ignored.", |
762 | "SimProcess : " + getName() |
763 | + " Method: void hold(TimeSpan dt)", |
764 | "The TimeSpan given as parameter is a null reference.", |
765 | "Be sure to have a valid TimeSpan reference before calling this method."); |
766 | return; // no proper parameter |
767 | } |
768 | |
769 | if (isBlocked()) { |
770 | sendWarning( |
771 | "Can't activate SimProcess! Command ignored.", |
772 | "SimProcess : " + getName() + " Method: hold(TimeSpan dt)", |
773 | "The sim-process to be activated is blocked inside " |
774 | + "a higher level synchronization object.", |
775 | "Simprocesses waiting inside higher synchronization " |
776 | + "constructs can not be set to be activated by other " |
777 | + "SimProcesses or events!"); |
778 | return; // is blocked in some synch construction |
779 | } |
780 | |
781 | if (isScheduled()) { |
782 | sendWarning("Can't schedule SimProcess! Command ignored.", |
783 | "SimProcess : " + getName() |
784 | + " Method: void hold(TimeSpan dt)", |
785 | "The sim-process to be scheduled is already scheduled.", |
786 | "Use method reActivate(TimeSpan dt) to shift the sim-process " |
787 | + "to be scheduled at some other point of time."); |
788 | return; // was already scheduled |
789 | } |
790 | |
791 | if (currentlySendTraceNotes()) { |
792 | if (this == currentSimProcess()) { |
793 | sendTraceNote("holds for " + dt.toString() + " until " |
794 | + TimeOperations.add(presentTime(), dt).toString()); |
795 | } else { |
796 | sendTraceNote("holds " + getQuotedName() + "for " |
797 | + dt.toString() + " until " |
798 | + TimeOperations.add(presentTime(), dt).toString()); |
799 | } |
800 | skipTraceNote(); // skip passivate message |
801 | } |
802 | |
803 | // schedule to be reactivated in dt |
804 | getModel().getExperiment().getScheduler().schedule(this, null, dt); |
805 | |
806 | if (currentlySendDebugNotes()) { |
807 | sendDebugNote("holds on EventList<br>" |
808 | + getModel().getExperiment().getScheduler().toString()); |
809 | } |
810 | |
811 | // hand control over to scheduler only if this is |
812 | // a running thread of SimProcess |
813 | passivate(); |
814 | } |
815 | |
816 | /** |
817 | * Passivates a sim-process until the given point in simulation time. The |
818 | * simthread of this SimProcess is put into a lock and the scheduler, resp. |
819 | * the experiment's main thread is released from its block and continues |
820 | * with the next event-note to be processed. |
821 | * |
822 | * @param until |
823 | * TimeInstant : The point in simulation time when the |
824 | * SimProcess' passivation ends. |
825 | * |
826 | */ |
827 | public void hold(TimeInstant until) { |
828 | if ((until == null)) { |
829 | sendWarning("Can't schedule SimProcess! Command ignored.", |
830 | "SimProcess : " + getName() |
831 | + " Method: void hold(TimeInstant until)", |
832 | "The TimeInstant given as parameter is a null reference.", |
833 | "Be sure to have a valid TimeInstant reference before calling this method."); |
834 | return; // no proper parameter |
835 | } |
836 | |
837 | if (isBlocked()) { |
838 | sendWarning( |
839 | "Can't activate SimProcess! Command ignored.", |
840 | "SimProcess : " + getName() |
841 | + " Method: hold(TimeInstant until)", |
842 | "The sim-process to be activated is blocked inside " |
843 | + "a higher level synchronization object.", |
844 | "Simprocesses waiting inside higher synchronization " |
845 | + "constructs can not be set to be activated by other " |
846 | + "SimProcesses or events!"); |
847 | return; // is blocked in some synch construction |
848 | } |
849 | |
850 | if (isScheduled()) { |
851 | sendWarning("Can't schedule SimProcess! Command ignored.", |
852 | "SimProcess : " + getName() |
853 | + " Method: void hold(TimeInstant until)", |
854 | "The sim-process to be scheduled is already scheduled.", |
855 | "Use method reActivate(TimeInstant when) to shift the sim-process " |
856 | + "to be scheduled at some other point of time."); |
857 | return; // was already scheduled |
858 | } |
859 | |
860 | if (TimeInstant.isBefore(until, presentTime())) { |
861 | sendWarning("Can't schedule SimProcess! Command ignored.", |
862 | "SimProcess : " + getName() |
863 | + " Method: void hold(TimeInstant until)", |
864 | "The instant given is in the past.", |
865 | "To hold a sim-process, use a TimeInstant no earlier than the present time. " |
866 | + "The present time can be obtained using the " |
867 | + "presentTime() method."); |
868 | return; // do not hold |
869 | } |
870 | |
871 | if (currentlySendTraceNotes()) { |
872 | if (this == currentSimProcess()) { |
873 | sendTraceNote("holds until " + until.toString()); |
874 | } else { |
875 | sendTraceNote("holds " + getQuotedName() + "until " |
876 | + until.toString()); |
877 | } |
878 | skipTraceNote(); // skip passivate message |
879 | } |
880 | |
881 | // schedule to be reactivated at the point of simulation time "until" |
882 | getModel().getExperiment().getScheduler().schedule(this, null, until); |
883 | |
884 | if (currentlySendDebugNotes()) { |
885 | sendDebugNote("holds on EventList<br>" |
886 | + getModel().getExperiment().getScheduler().toString()); |
887 | } |
888 | |
889 | // hand control over to scheduler only if this is |
890 | // a running thread of SimProcess |
891 | passivate(); |
892 | } |
893 | |
894 | /** |
895 | * @deprecated Replaced by hold(TimeSpan dt). Passivates a sim-process for |
896 | * the time given. The simthread of this SimProcess is put into |
897 | * a lock and the scheduler, resp. the experiment's main thread |
898 | * is released from its block and continues with the next |
899 | * EventNote to be processed. |
900 | * |
901 | * @param dt |
902 | * desmoj.SimTime : The duration of the sim-process' passivation |
903 | */ |
904 | @Deprecated |
905 | public void hold(SimTime dt) { |
906 | hold(SimTime.toTimeSpan(dt)); |
907 | |
908 | } |
909 | |
910 | /** |
911 | * Interrupts the sim-process setting the given InterruptCode as the reason |
912 | * for the interruption. Blocked, terminated or already interrupted |
913 | * Sim-processes can not be interrupted. In this case a warning message will |
914 | * be produced and the interrupt will be ignord. If the sim-process is |
915 | * cooperating as a slave the interrupt will be passed to the master. |
916 | * |
917 | * @param interruptReason |
918 | * desmoj.InterruptCode |
919 | */ |
920 | public void interrupt(InterruptCode interruptReason) { |
921 | |
922 | if (interruptReason == null) { |
923 | sendWarning( |
924 | "Can't interrupt SimProcess! Command ignored", |
925 | "SimProcess : " + getName() + " Method: void " |
926 | + "interrupt(InterruptCode interruptReason)", |
927 | "The InterruptCode given as parameter is a null reference.", |
928 | "Be sure to have a valid InterruptCode reference before " |
929 | + "calling this method."); |
930 | return; // no proper parameter |
931 | } |
932 | |
933 | // if the sim-process is cooperating as a slave |
934 | if (_master != null) { |
935 | if (currentlySendTraceNotes()) { |
936 | sendTraceNote("interrupts '" + this.getName() + "' , who ..."); |
937 | } |
938 | |
939 | // interrupt the master, too. (with the same reason/InterruptCode) |
940 | _master.interrupt(interruptReason); |
941 | } |
942 | |
943 | if (isBlocked()) { |
944 | sendWarning("Can't interrupt SimProcess! Command ignored", |
945 | "SimProcess : " + getName() + " Method: void " |
946 | + "interrupt(InterruptCode interruptReason)", |
947 | "Blocked SimProcesses can not be interrupted.", |
948 | "You can check if a sim-process is blocked using method " |
949 | + "isBlocked()."); |
950 | return; // is Blocked |
951 | } |
952 | |
953 | if (isTerminated()) { |
954 | sendWarning("Can't interrupt SimProcess! Command ignored", |
955 | "SimProcess : " + getName() + " Method: void " |
956 | + "interrupt(InterruptCode interruptReason)", |
957 | "Terminated SimProcesses can not be interrupted.", |
958 | "You can check if a sim-process is terminated using method " |
959 | + "isTerminated()."); |
960 | return; // is Terminated |
961 | } |
962 | |
963 | if (_irqCode != null) { |
964 | sendWarning( |
965 | "Can't interrupt SimProcess! Command ignored", |
966 | "SimProcess : " + getName() + " Method: void " |
967 | + "interrupt(InterruptCode interruptReason)", |
968 | "SimProcesses has already a InterruptCode set :" |
969 | + _irqCode.getName(), |
970 | "SimProcesses may only be interrupted if no other " |
971 | + "InterruptCode is set on that SimProcess. You can check " |
972 | + "on that using mehtod getInterruptCode, which must return " |
973 | + "null if no other InterruptCode is set."); |
974 | return; // is Interrupted |
975 | } |
976 | |
977 | if (this == currentSimProcess()) { |
978 | sendWarning("Can't interrupt SimProcess! Command ignored", |
979 | "SimProcess : " + getName() + " Method: void " |
980 | + "interrupt(InterruptCode interruptReason)", |
981 | "SimProcess is the currently active SimProcess.", |
982 | "Make sure not to interrupt the currently active " |
983 | + "SimProcess."); |
984 | return; // is currentSimProcess |
985 | } |
986 | |
987 | if (currentlySendTraceNotes()) { |
988 | sendTraceNote("interrupts '" + this.getName() + "', with reason " |
989 | + interruptReason.getName() + " [" |
990 | + interruptReason.getCodeNumber() + "]"); |
991 | } |
992 | |
993 | _irqCode = interruptReason; // set the InterruptCode |
994 | |
995 | // if on EventList, remove first ... |
996 | if (isScheduled()) { |
997 | skipTraceNote(2); |
998 | cancel(); |
999 | } else { |
1000 | skipTraceNote(); |
1001 | } |
1002 | // ... then activate after the one interrupting this SimProcess |
1003 | activateAfter(current()); |
1004 | } |
1005 | |
1006 | /** |
1007 | * Returns the current block-status of the sim-process. If a sim-process is |
1008 | * blocked, it is waiting inside a queue or synchronization block for it's |
1009 | * release. |
1010 | * |
1011 | * @return boolean : Is <code>true</code> if SimProcess is blocked, |
1012 | * <code>false</code> otherwise |
1013 | */ |
1014 | public boolean isBlocked() { |
1015 | |
1016 | return _isBlocked; |
1017 | |
1018 | } |
1019 | |
1020 | /** |
1021 | * Returns the current component status of this SimProcess. If a sim-process |
1022 | * is a component of a <code>ComplexSimProcess</code> it is blocked and |
1023 | * passivated. It exists only within the <code>ComplexSimProcess</code>; |
1024 | * it's own lifeCycle is stopped and will only be activated again when it is |
1025 | * removed from the <code>ComplexSimProcess</code>. |
1026 | * |
1027 | * @return boolean :<code>true</code> if and only if this SimProcess is a |
1028 | * component (part of) a <code>ComplexSimProcess</code>; |
1029 | * <code>false</code> otherwise. |
1030 | * @author Soenke Claassen |
1031 | */ |
1032 | public boolean isComponent() { |
1033 | |
1034 | return (_supervisor != null); |
1035 | } |
1036 | |
1037 | /** |
1038 | * Returns the current interrupt-status of this SimProcess. If a sim-process |
1039 | * is interrupted, it should deal with the interrupt and then call the |
1040 | * <code>clearInterruptCode()</code> -method. |
1041 | * |
1042 | * @return boolean : Is <code>true</code> if this SimProcess is interrupted, |
1043 | * <code>false</code> otherwise. |
1044 | * @author Soenke Claassen |
1045 | */ |
1046 | public boolean isInterrupted() { |
1047 | return (_irqCode != null); |
1048 | } |
1049 | |
1050 | /** |
1051 | * Returns the current running status of the sim-process. If a sim-process is |
1052 | * not ready, it has already finished its <code>lifeCycle()</code> method |
1053 | * and can not further be used as a sim-process. A terminated SimProcess can |
1054 | * still be used like any other Entity which it is derived from. |
1055 | * |
1056 | * @return boolean : Is <code>true</code> if the sim-process is terminated, |
1057 | * <code>false</code> otherwise |
1058 | * @see Entity |
1059 | */ |
1060 | boolean isReady() { |
1061 | |
1062 | return _isRunning; |
1063 | |
1064 | } |
1065 | |
1066 | /** |
1067 | * Returns the current status of the sim-process. If a sim-process is |
1068 | * terminated, it has already finished its <code>lifeCycle()</code> method |
1069 | * and can not further be used as a sim-process. A terminated SimProcess can |
1070 | * still be used like any other Entity which it is derived from. |
1071 | * |
1072 | * @return boolean : Is <code>true</code> if the sim-process is terminated, |
1073 | * <code>false</code> otherwise |
1074 | * @see Entity |
1075 | */ |
1076 | public boolean isTerminated() { |
1077 | |
1078 | return _isTerminated; |
1079 | |
1080 | } |
1081 | |
1082 | /** |
1083 | * Override this method in a subclass of SimProcess to implement that |
1084 | * Sim-process' specific behaviour. This method starts after a sim-process has |
1085 | * been created and activated by the scheduler. |
1086 | */ |
1087 | public abstract void lifeCycle(); |
1088 | |
1089 | /** |
1090 | * Makes the sim-process obtain an array of resources and store them for |
1091 | * further usage. |
1092 | * |
1093 | * @param obtainedResources |
1094 | * Resource[] : The array of resources obtained. |
1095 | * |
1096 | * @author Soenke Claassen |
1097 | */ |
1098 | public void obtainResources(Resource[] obtainedResources) { |
1099 | if (obtainedResources.length <= 0) { |
1100 | sendWarning("Attempt to obtain resources, but got none! Command " |
1101 | + "ignored!", "SimProcess : " + getName() |
1102 | + " Method: void obtain" |
1103 | + "Resources(Resource[] obtainedResources)", |
1104 | "The array of obtained resources is empty.", |
1105 | "Make sure to obtain at least one resource. Check if the " |
1106 | + "resource pool can provide any resources."); |
1107 | return; // parameter contains nothing |
1108 | } |
1109 | |
1110 | // put all the obtained resources in the Vector of used resources |
1111 | for (int i = 0; i < obtainedResources.length; i++) { |
1112 | _usedResources.addElement(obtainedResources[i]); |
1113 | } |
1114 | |
1115 | // for debugging purposes |
1116 | if (currentlySendDebugNotes()) { |
1117 | // make a string of all resources used by this SimProcess |
1118 | String t = "uses: "; |
1119 | |
1120 | for (Enumeration<Resource> e = _usedResources.elements(); e.hasMoreElements();) { |
1121 | t += "<br>" + (e.nextElement()).getName(); |
1122 | } |
1123 | |
1124 | sendDebugNote(t); |
1125 | } |
1126 | } |
1127 | |
1128 | /** |
1129 | * Passivates the sim-process for an indefinite time. This method must be |
1130 | * called by the sim-process' own Thread only. The sim-process can only be |
1131 | * reactivated by another SimProcess or Entity. |
1132 | */ |
1133 | public synchronized void passivate() { |
1134 | |
1135 | if (currentlySendTraceNotes()) { |
1136 | if (this == currentSimProcess()) { |
1137 | sendTraceNote("passivates"); |
1138 | } else { |
1139 | sendTraceNote("passivates " + getQuotedName()); |
1140 | } |
1141 | } |
1142 | |
1143 | notify(); // frees the scheduler after wait() |
1144 | |
1145 | try { |
1146 | wait(); |
1147 | } catch (InterruptedException ioEx) { |
1148 | // create eror message |
1149 | ErrorMessage errmsg = new ErrorMessage(getModel(), |
1150 | "Simulation stopped!", |
1151 | "Exception thrown by Java VM" + ioEx, |
1152 | "Thread conflict assumed.", "Check Java VM.", presentTime()); |
1153 | // throw it back to Experiment's start routine |
1154 | throw (new desmoj.core.exception.DESMOJException(errmsg)); |
1155 | } |
1156 | |
1157 | // if simulation is not running, throw SimFinishedException to stop |
1158 | // thread |
1159 | if (getModel().getExperiment().isAborted()) { |
1160 | throw (new desmoj.core.exception.SimFinishedException(getModel(), |
1161 | getName(), presentTime())); |
1162 | } |
1163 | |
1164 | } |
1165 | |
1166 | /** |
1167 | * The current (master) process is calling this method (within |
1168 | * <code>TransportJunction.cooperate()</code>) on the slave process to make |
1169 | * him prepare for the transportation. After the transport is finished the |
1170 | * master is still active and after him the slave will be activated. |
1171 | * |
1172 | * @author Soenke Claassen |
1173 | */ |
1174 | public void prepareTransport() { |
1175 | // this is the slave and current the master |
1176 | |
1177 | // check if this slave already has a master |
1178 | if (this._master != null) { |
1179 | sendWarning( |
1180 | "Slaves can not be transported from more than one master at " |
1181 | + "a time! The attempted transport is ignored.", |
1182 | "SimProcess : " + getName() |
1183 | + " Method: prepareTransport () ", |
1184 | "This slave process is already transported by another " |
1185 | + "master: " + _master.getName(), |
1186 | "Be sure to have finished one transportation before starting " |
1187 | + "the next one."); |
1188 | return; // this process has a master already |
1189 | } |
1190 | |
1191 | // check if this slave is not terminated yet |
1192 | if (this._isTerminated) { |
1193 | sendWarning("Attempt to transport a terminated slave process! " |
1194 | + "The attempted transport is ignored.", "SimProcess : " |
1195 | + getName() + " Method: prepareTransport () ", |
1196 | "This slave process is already terminated.", |
1197 | "Make sure not to transport terminated processes."); |
1198 | return; // this process is already terminated |
1199 | } |
1200 | |
1201 | // check the master |
1202 | SimProcess currentMaster = currentSimProcess(); // the current master |
1203 | // process |
1204 | if (currentMaster == null) // if currentMaster is only a null pointer |
1205 | { |
1206 | sendWarning( |
1207 | "A non existing process is trying to transport other " |
1208 | + "processes as a master! The attempted transport is ignored!", |
1209 | "SimProcess : " + getName() |
1210 | + " Method: prepareTransport ()", |
1211 | "The master process is only a null pointer.", |
1212 | "Make sure that only real SimProcesses are transporting other " |
1213 | + "processes. "); |
1214 | return; // the currentMaster process is only a null pointer |
1215 | } |
1216 | |
1217 | if (!isModelCompatible(currentMaster)) { |
1218 | sendWarning( |
1219 | "The given master SimProcess object does not " |
1220 | + "belong to this model. The attempted transport is ignored!", |
1221 | "SimProcess : " + getName() |
1222 | + " Method: prepareTransport ()", |
1223 | "The master SimProcess is not modelcompatible.", |
1224 | "Make sure that the processes all belong to this model."); |
1225 | return; // the currentMaster is not modelcompatible |
1226 | } |
1227 | |
1228 | // the slave must be waiting in a WaitQueue |
1229 | if (_slaveWaitQueue == null) { |
1230 | sendWarning( |
1231 | "Attempt to transport a slave process, that is not " |
1232 | + "waiting in a TransportJunction. The attempted transport is ignored!", |
1233 | "SimProcess : " + getName() |
1234 | + " Method: prepareTransport ()", |
1235 | "Slave processes must wait in a TransportJunction before they can be " |
1236 | + "transported.", |
1237 | "Make sure that the slave processes are waiting in a " |
1238 | + "TransportJunction."); |
1239 | return; // the slave is not waiting in a queue |
1240 | } |
1241 | |
1242 | // now prepare for the real cooperation |
1243 | this._master = currentMaster; // set the master for this slave process |
1244 | |
1245 | // leave a note in the trace |
1246 | if (_master.currentlySendTraceNotes()) { |
1247 | // trace note for a transport without any special conditions |
1248 | sendTraceNote("transports " + this.getQuotedName() + " from " |
1249 | + _slaveWaitQueue.getQuotedName()); |
1250 | } |
1251 | |
1252 | // get this slave out of his slaveWaitQueue |
1253 | _slaveWaitQueue.remove(this); |
1254 | // this slave process is not waiting in any slaveWaitingQueue anymore |
1255 | _slaveWaitQueue = null; |
1256 | // and therefore this slave process is not blocked anymore |
1257 | this._isBlocked = false; |
1258 | |
1259 | } |
1260 | |
1261 | /** |
1262 | * Re-schedules the sim-process to be activated at the given TimeSpan offset |
1263 | * to the current simulation time. The Simprocess has already been scheduled |
1264 | * but is now supposed to be reactivated at some other point of simulation |
1265 | * time. |
1266 | * |
1267 | * @param dt |
1268 | * TimeSpan : The offset to the current simulation time that this |
1269 | * SimProcess is due to be re-activated |
1270 | */ |
1271 | public void reActivate(TimeSpan dt) { |
1272 | if (isBlocked()) { |
1273 | sendWarning( |
1274 | "Can't reactivate SimProcess! Command ignored.", |
1275 | "SimProcess : " + getName() |
1276 | + " Method: reActivate(TimeSpan dt)", |
1277 | "The sim-process to be activated is blocked inside " |
1278 | + "a higher level synchronization object.", |
1279 | "Simprocesses waiting inside higher synchronization " |
1280 | + "constructs can not be activated by other SimProcesses or " |
1281 | + "events!"); |
1282 | return; // is blocked in some synch construction |
1283 | } |
1284 | |
1285 | if (!isScheduled()) { |
1286 | sendWarning("Can't reactivate SimProcess! Command ignored.", |
1287 | "SimProcess : " + getName() |
1288 | + " Method: reActivate(TimeSpan dt)", |
1289 | "The sim-process to be reactivated is not scheduled.", |
1290 | "Use method activate(TimeSpan dt) to activate a sim-process" |
1291 | + "that is not scheduled yet."); |
1292 | return; // was already scheduled |
1293 | } |
1294 | |
1295 | if (dt == null) { |
1296 | sendWarning( |
1297 | "Can't reactivate SimProcess! Command ignored.", |
1298 | "SimProcess : " + getName() + " Method: void reActivate" |
1299 | + "(TimeSpan dt)", |
1300 | "The simulation time given as parameter is a null reference", |
1301 | "Be sure to have a valid simulation time reference before " |
1302 | + "calling this method"); |
1303 | return; // no proper parameter |
1304 | } |
1305 | |
1306 | if (currentlySendTraceNotes()) { |
1307 | if (this == currentSimProcess()) { |
1308 | if (dt == TimeSpan.ZERO) |
1309 | sendTraceNote("reactivates itself now"); |
1310 | else |
1311 | sendTraceNote("reactivates itself at " |
1312 | + TimeOperations.add(presentTime(), dt)); |
1313 | } else { |
1314 | if (dt == TimeSpan.ZERO) |
1315 | sendTraceNote("reactivates " + getQuotedName() + " now"); |
1316 | else |
1317 | sendTraceNote("reactivates " + getQuotedName() + " at " |
1318 | + TimeOperations.add(presentTime(), dt)); |
1319 | } |
1320 | } |
1321 | |
1322 | getModel().getExperiment().getScheduler().reSchedule(this, dt); |
1323 | |
1324 | resetMaster(); // if reActivate(TimeSpan dt) is called for this |
1325 | // SimProcess, |
1326 | // there is no Master anymore controlling it. |
1327 | } |
1328 | |
1329 | /** |
1330 | * Gets the InterruptCode from the master and resets the master to |
1331 | * <code>null</code>. |
1332 | * |
1333 | * @author Soenke Claassen |
1334 | */ |
1335 | public void resetMaster() { |
1336 | if (this._master != null) { |
1337 | _irqCode = _master.getInterruptCode(); |
1338 | } |
1339 | |
1340 | this._master = null; |
1341 | } |
1342 | |
1343 | /** |
1344 | * Makes the sim-process return all resources it holds at the moment to all |
1345 | * the different Res pools it is holding resources from. This is useful in |
1346 | * situations the Simprocess is about to terminate. |
1347 | * |
1348 | * @author Soenke Claassen |
1349 | */ |
1350 | public void returnAllResources() { |
1351 | // check if something can be returned |
1352 | if (_usedResources.isEmpty()) { |
1353 | sendWarning( |
1354 | "Attempt to return all resources, but the " |
1355 | + "SimProcess does not hold any resources! Command ignored!", |
1356 | "SimProcess : " + getName() |
1357 | + " Method: returnAllResources()", |
1358 | "If the sim-process does not hold any resources it is " |
1359 | + "impossible to return any.", |
1360 | "Make sure that the sim-process holds resources that " |
1361 | + "should be returned!"); |
1362 | return; // return nothing, go to where you came from |
1363 | } |
1364 | |
1365 | // repeat while vector of usedResources is not empty |
1366 | while (!_usedResources.isEmpty()) { |
1367 | // get the first resource and check the Res pool it belongs to |
1368 | Res crntResPool = ((Resource) _usedResources.firstElement()) |
1369 | .getResPool(); |
1370 | |
1371 | // counter how many resources of that res pool are used |
1372 | int n = 1; |
1373 | |
1374 | // search the whole vector of usedResources for resources of the |
1375 | // current |
1376 | // Res pool |
1377 | for (int i = 1; i < _usedResources.size(); i++) { |
1378 | // is the resource of the desired Res pool? |
1379 | if (((Resource) _usedResources.elementAt(i)).getResPool() == crntResPool) { |
1380 | n++; // increase the counter |
1381 | } |
1382 | } // end for-loop |
1383 | |
1384 | // make the array to store the resources which will be returned |
1385 | Resource[] returningRes = new Resource[n]; |
1386 | |
1387 | // counter for the index of the array |
1388 | int k = 0; |
1389 | |
1390 | // collect all the resources from the Vector of usedResources |
1391 | for (int j = 0; j < _usedResources.size(); j++) { |
1392 | // is the resource of the desired Res pool? |
1393 | if ((_usedResources.elementAt(j)).getResPool() == crntResPool) { |
1394 | // put res in array |
1395 | returningRes[k] = _usedResources.elementAt(j); |
1396 | k++; // increase counter of array |
1397 | } |
1398 | if (k == n) // array is full |
1399 | break; // stop the for-loop |
1400 | } |
1401 | |
1402 | // return the array of resources to the Res pool they belong to |
1403 | crntResPool.takeBack(returningRes); |
1404 | |
1405 | // remove the returned resources from the vector of usedResources |
1406 | for (int m = 0; m < n; m++) // go through the array of |
1407 | // returningResources |
1408 | { |
1409 | // remove each resource that is in the array of |
1410 | // returningResources |
1411 | _usedResources.removeElement(returningRes[m]); |
1412 | } |
1413 | |
1414 | } // end while |
1415 | |
1416 | // for debugging purposes |
1417 | if (currentlySendDebugNotes()) { |
1418 | // make a string including all elements of the vector usedResources |
1419 | String s = "All resources returned! Contents of vector usedResources: "; |
1420 | |
1421 | if (_usedResources.isEmpty()) // anything left ? |
1422 | { |
1423 | s += "<br>none"; |
1424 | } |
1425 | |
1426 | for (Enumeration<Resource> e = _usedResources.elements(); e.hasMoreElements();) { |
1427 | s += e.nextElement(); |
1428 | } |
1429 | |
1430 | // send a debugNote representing the state of the vector |
1431 | // usedResources |
1432 | sendDebugNote(s); |
1433 | } |
1434 | |
1435 | } // end method returnAllResources |
1436 | |
1437 | /** |
1438 | * Makes the sim-process return a certain number of resources of the given |
1439 | * resource pool. |
1440 | * |
1441 | * @param resPool |
1442 | * Res : The resource pool which resources will be returned. |
1443 | * @param n |
1444 | * int : The number of resources which will be returned. |
1445 | * @return Resource[] : the array containing the resources which will be |
1446 | * returned. |
1447 | * @author Soenke Claassen |
1448 | */ |
1449 | public Resource[] returnResources(Res resPool, int n) { |
1450 | // check if nothing should be returned |
1451 | if (n <= 0) { |
1452 | sendWarning( |
1453 | "Attempt to return no or a negative number of resources! " |
1454 | + " Command ignored!", "SimProcess : " + getName() |
1455 | + " Method: Resource[] " |
1456 | + "returnResources(Res resPool, int n)", |
1457 | "It makes no sense to return nothing or a negative number " |
1458 | + "of resources.", |
1459 | "Make sure to return at least one resource. Only resources " |
1460 | + "which have been obtained once can be returned!"); |
1461 | return null; // return nothing, go to where you came from |
1462 | } |
1463 | |
1464 | // check if nothing can be returned |
1465 | if (_usedResources.isEmpty()) { |
1466 | sendWarning( |
1467 | "Attempt to return a number of resources, but the " |
1468 | + "SimProcess does not hold any resources! Command ignored!", |
1469 | "SimProcess : " + getName() + " Method: Resource[] " |
1470 | + "returnResources(Res resPool, int n)", |
1471 | "If the sim-process does not hold any resources it is " |
1472 | + "impossible to return any.", |
1473 | "Make sure that the sim-process holds the resources that " |
1474 | + "should be returned!"); |
1475 | return null; // return nothing, go to where you came from |
1476 | } |
1477 | |
1478 | // make the array to store the resources which will be returned |
1479 | Resource[] returningRes = new Resource[n]; |
1480 | |
1481 | // counter for the index of the array |
1482 | int j = 0; |
1483 | |
1484 | // collect all the resources from the Vector of usedResources |
1485 | for (int i = 0; i < _usedResources.size(); i++) { |
1486 | // is the resource of the desired kind? |
1487 | if ((_usedResources.elementAt(i)).getResPool() == resPool) { |
1488 | // put res in array |
1489 | returningRes[j] = _usedResources.elementAt(i); |
1490 | j++; // increase counter of array |
1491 | } |
1492 | if (j == n) // array is full |
1493 | break; // stop the for-loop |
1494 | } |
1495 | |
1496 | // for debugging: make a string of all returning resources |
1497 | String s = "<b>returns</b> to Res '" + resPool.getName() + "' : "; |
1498 | |
1499 | // remove the returning resources from the vector of usedResources |
1500 | for (int m = 0; m < j; m++) // go through the array of |
1501 | // returningResources |
1502 | { |
1503 | // remove each resource that is in the array of returningResources |
1504 | _usedResources.removeElement(returningRes[m]); |
1505 | |
1506 | // add them to string of returning resources |
1507 | s += "<br>" + returningRes[m].getName(); |
1508 | } |
1509 | |
1510 | if (j < n) // array is not full |
1511 | { |
1512 | sendWarning("Attempt to return " + n |
1513 | + " resources to the Res pool. " |
1514 | + "But the sim-process holds only" + j |
1515 | + "resources of that " + "kind. The " + j |
1516 | + "resources will be returned.", "SimProcess : " |
1517 | + getName() + " Method: Resource[] " |
1518 | + "returnResources(Res resPool, int n)", |
1519 | "The sim-process can not return " + n + " resources, " |
1520 | + "because it holds only" + j + "resources.", |
1521 | "Make sure that the sim-process holds at least as many " |
1522 | + "resources as it should return."); |
1523 | } |
1524 | |
1525 | // for debugging purposes |
1526 | if (currentlySendDebugNotes()) { |
1527 | sendDebugNote(s); |
1528 | |
1529 | // make a string of all resources still held by this SimProcess |
1530 | String t = "still holds: "; |
1531 | |
1532 | if (_usedResources.isEmpty()) // anything left ? |
1533 | { |
1534 | t += "<br>none"; |
1535 | } |
1536 | |
1537 | for (Enumeration<Resource> e = _usedResources.elements(); e.hasMoreElements();) { |
1538 | t += "<br>" + (e.nextElement()).getName(); |
1539 | } |
1540 | |
1541 | sendDebugNote(t); |
1542 | } |
1543 | |
1544 | return returningRes; // return the array of resources |
1545 | } |
1546 | |
1547 | /** |
1548 | * Sets the sim-process' blocked status to the boolean value given. This is |
1549 | * necessary for some operations in conjunction with some synchronization |
1550 | * classes. |
1551 | * |
1552 | * @param blockStatus |
1553 | * boolean : The new value for the blocked status |
1554 | */ |
1555 | public void setBlocked(boolean blockStatus) { |
1556 | |
1557 | _isBlocked = blockStatus; |
1558 | |
1559 | } |
1560 | |
1561 | /**Sets the realTime deadline for this SimProcess (in nanoseconds). In case of a |
1562 | * real-time execution (i. e. the execution speed rate is set to a positive |
1563 | * value) the Scheduler will produce a warning message if a deadline is |
1564 | * missed. |
1565 | * |
1566 | * @param realTimeConstraint the realTimeConstraint in nanoseconds to set |
1567 | */ |
1568 | public void setRealTimeConstraint(long realTimeConstraint) { |
1569 | this._realTimeConstraint = realTimeConstraint; |
1570 | } |
1571 | |
1572 | /** |
1573 | * Sets the sim-process' running status to the boolean value given. This is |
1574 | * necessary for some operations in conjunction with synchronization |
1575 | * classes. |
1576 | * |
1577 | * @param runStatus |
1578 | * boolean : The new value for the running status |
1579 | */ |
1580 | void setRunning(boolean runStatus) { |
1581 | |
1582 | _isRunning = runStatus; |
1583 | |
1584 | } |
1585 | |
1586 | /** |
1587 | * Sets the sim-process' slaveWaitQueue variable to the ProcessQueue in which |
1588 | * this SimProcess is waiting as a slave to cooperate with a master. |
1589 | * |
1590 | * @param slvWaitQueue |
1591 | * ProcessQueue : The waiting-queue in which this SimProcess is |
1592 | * waiting as a slave to cooperate with a master. |
1593 | * @author Soenke Claassen |
1594 | */ |
1595 | public void setSlaveWaitQueue(ProcessQueue<? extends SimProcess> slvWaitQueue) { |
1596 | _slaveWaitQueue = slvWaitQueue; |
1597 | } |
1598 | |
1599 | /** |
1600 | * Sets the supervising <code>ComplexSimProcess</code> this SimProcess is |
1601 | * contained in. Setting it to <code>null</code> indicates that this |
1602 | * Sim-process is not contained in any <code>ComplexSimProcess</code> |
1603 | * (anymore). |
1604 | * |
1605 | * @param complexProcess |
1606 | * desmoj.ComplexSimProcess : The <code>ComplexSimProcess</code> |
1607 | * which serves as a container for this SimProcess. |
1608 | * @author Soenke Claassen |
1609 | */ |
1610 | protected void setSupervisor(ComplexSimProcess complexProcess) { |
1611 | |
1612 | this._supervisor = complexProcess; |
1613 | } |
1614 | |
1615 | /** |
1616 | * Sets the attribute indicating that this SimProcess' simthread has |
1617 | * finished to the given value. This method is used by class |
1618 | * <code>SimThread<code> only. |
1619 | * |
1620 | * @param termValue |
1621 | * boolean : The new value for the attribute indicating the |
1622 | * SimThread's end |
1623 | */ |
1624 | void setTerminated(boolean termValue) { |
1625 | |
1626 | _isTerminated = termValue; // Hasta la vista, baby! |
1627 | |
1628 | } |
1629 | |
1630 | /** |
1631 | * Starts the simthread associated with this SimProcess. This is method must |
1632 | * be called the first time a sim-process is supposed to start processing its |
1633 | * <code>lifeCycle()</code> method. |
1634 | */ |
1635 | synchronized void start() { |
1636 | |
1637 | // setting this flag shows that the simthread is now ready to take over |
1638 | // control from the scheduler's thread |
1639 | _isRunning = true; |
1640 | |
1641 | // start thread and let it run into the block |
1642 | _myThread.start(); |
1643 | |
1644 | // put thread in to a wait for synchronization |
1645 | try { |
1646 | wait(); |
1647 | } catch (InterruptedException irqEx) { |
1648 | // create eror message |
1649 | ErrorMessage errmsg = new ErrorMessage(getModel(), |
1650 | "Simulation stopped!", "Exception thrown by Java VM" |
1651 | + irqEx, "Thread conflict assumed.", |
1652 | "Check Java VM.", presentTime()); |
1653 | // throw it back to Experiment's start routine |
1654 | throw (new desmoj.core.exception.DESMOJException(errmsg)); |
1655 | } |
1656 | |
1657 | // check if simulation has been stopped in between and throw SimFinished |
1658 | if (getModel().getExperiment().isAborted()) { |
1659 | throw (new desmoj.core.exception.SimFinishedException(getModel(), |
1660 | getName(), presentTime())); |
1661 | } |
1662 | } |
1663 | |
1664 | /** |
1665 | * As there is no generally appliciable means of cloning a SimProcess |
1666 | * (which would require cloning the execution state as well), this |
1667 | * method returns a </code>CloneNotSupportedException</code>. |
1668 | * |
1669 | * @return SimProcess : A copy of this process. |
1670 | */ |
1671 | protected SimProcess clone() throws CloneNotSupportedException { |
1672 | throw new CloneNotSupportedException(); |
1673 | } |
1674 | } // end class SimProcess |