Source code: desmoj/Res.java
1 package desmoj;
2
3 //34567890123456789012345678901234567890123456789012345678901234567890123456
4
5 import java.util.*; // import things like Vector
6
7 /**
8 * Res is the place where resources are stored in a pool.
9 * Processes can come by and the resource pool will <code>provide()</code>
10 * resources to them. Each process has to give back the same resources it
11 * once has acquired by calling the <code>takeBack()</code> method of the
12 * Res. Res is used to implement process synchronization between
13 * processes, which are using resources. The resource pool has a limited
14 * capacity. A process can acquire one or more resources and use them.
15 * After usage the process must release this or these same resources
16 * to make them available to other processes. If a process can
17 * not get the number of resources needed, it has to wait in a queue until
18 * enough resources are released by other processes. A process can release
19 * its resources anytime. After the resourcepool has <code>"takenBack"()</code>
20 * the used resources the waiting queue is checked for processes waiting
21 * for them.
22 * The first sort criteria of the queue is always highest priorities first,
23 * the second queueing discipline of the underlying queue and the capacity
24 * limit can be determined by the user (default is Fifo and unlimited
25 * capacity).
26 * Under certain circumstances a deadlock might block some waiting
27 * entities. Be aware of this fact when using the Res.
28 * @see QueueBased
29 *
30 * @author Soenke Claassen
31 *
32 * @version DESMO-J, Ver. 1.5 copyright (c) 2001 licensed under GNU GPL
33 */
34
35 public class Res extends desmoj.QueueBased
36 {
37
38 // ****** attributes ******
39
40 /**
41 * The number identifying a Res object. Because it is a class variable each
42 * <code>Res</code> will get its own ID number starting by zero.
43 */
44 private static long resNumber = 0;
45
46 /**
47 * The ID number of this <code>Res</code> object.
48 */
49 private long idNumber;
50
51 /**
52 * The queue, actually storing the processes waiting for resources
53 */
54 private QueueList queue;
55
56 /**
57 * The vector holding all the pairs (used resources of this Res,
58 * the SimProcess which holds the resources at the moment).
59 * See: inner class UsedResources
60 */
61 private java.util.Vector arrayOfUsedResources;
62
63 /**
64 * The vector holding all the resources of this resource pool not used at
65 * the moment.
66 */
67 private java.util.Vector unUsedResources;
68
69 /**
70 * The resource database keeping track of which SimProcesses holding which
71 * resources and SimPorcesses requesting resources.
72 */
73 private ResourceDB resourceDB;
74
75 /**
76 * To indicate whether the check for deadlocks is active or not.
77 * Default is <code>true</code> = deadlock check enabled.
78 */
79 private boolean deadlockCheck = true;
80
81 /**
82 * Is set to <code>true</code> if a deadlock is detected where this Res is
83 * involved in.
84 * Otherwise it remains <code>false</code>. Default is <code>false</code>.
85 */
86 private boolean deadlockDetected = false;
87
88 /**
89 * The number of resources in the Res (capacity)
90 */
91 private int limit;
92
93 /**
94 * The minimum number of resources being available
95 */
96 private int minimum;
97
98 /**
99 * Number of resources available at the moment
100 */
101 private int avail;
102
103 /**
104 * Number of processes having acquired and released one or more resources
105 */
106 private long users;
107
108 /**
109 * Weighted sum of available resources (in the Res over the time)
110 */
111 private double wSumAvail;
112
113 /**
114 * The last time the Res has been used
115 */
116 private SimTime lastUsage;
117
118 /**
119 * Counter for the SimProcesses which are refused to be enqueued, because the
120 * queue capacity is full.
121 */
122 private long refused;
123
124 /**
125 * Indicates the method where something has gone wrong. Is passed as a
126 * parameter to the method <code>checkProcess()</code>.
127 */
128 private String where;
129
130 /**
131 * Flag to indicate whether an entity can pass by other entities in the queue
132 * which are enqueued before that entity in the queue. Is <code>false</code> as
133 * default value.
134 */
135 private boolean passBy = false;
136
137
138 // ****** inner class ******
139
140 /**
141 * UsedResources is an inner class of Res to encapsulate the pairs of:
142 * SimProcess and an array of resources it holds. These pairs are
143 * stored in the vector <code>arrayOfUsedResources</code>.
144 */
145 class UsedResources extends java.lang.Object
146 {
147
148 // ****** attributes of inner class ******
149
150 /**
151 * The SimProcess using the resources at the moment.
152 */
153 private SimProcess process;
154
155
156 /**
157 * The array of resources occupied by the SimProcess. In fact the array is
158 * a java.util.Vector because one does not know how many resources the
159 * SimProcess holds and the number of held resources might vary.
160 */
161 private java.util.Vector occupiedResources;
162
163
164 // ****** methods of inner class ******
165
166 /**
167 * Constructor for a UsedResources object.
168 * @param sProc SimProcess : The SimProcess holding the resources.
169 * @param occupiedRes java.util.Vector : The resources occupied by the
170 * SimProcess.
171 */
172 protected UsedResources (SimProcess sProc, java.util.Vector occupiedRes)
173 {
174 // init variables
175 this.process = sProc;
176 this.occupiedResources = occupiedRes;
177 }
178
179 /**
180 * Returns the SimProcess which holds a number of resources.
181 * @return SimProcess : The SimProcess which holds a number of resources.
182 */
183 protected SimProcess getProcess ()
184 {
185 return this.process;
186 }
187
188 /**
189 * Returns the array of resources occupied by the SimProcess.
190 * @return java.util.Vector : The array of resources occupied by the
191 * SimProcess.
192 */
193 protected java.util.Vector getOccupiedResources ()
194 {
195 return this.occupiedResources;
196 }
197
198 /**
199 * Sets the array of resources occupied by the SimProcess to the given
200 * array <code>newArrayOfOccupiedResources</code>.
201 * @param newArrayOfOccupiedResources Vector : The new array of
202 * resources held by the SimProcess.
203 */
204 protected void setOccupiedResources (Vector newArrayOfOccupiedResources)
205 {
206 this.occupiedResources = newArrayOfOccupiedResources;
207 }
208
209 } // end inner class
210
211 /**
212 * Constructor for a Res with a number of initial resources in it.
213 * The queueing discipline and the capacity limit of the underlying queue
214 * can be chosen, too.
215 * @param owner Model : The model this Res is associated to.
216 * @param name java.lang.String : The Res's name
217 * @param sortOrder int : determines the sort order of the underlying
218 * queue implementation. Choose a constant from <code>QueueBased</code>
219 * like <code>QueueBased.FIFO</code> or <code>QueueBased.LIFO</code> or ...
220 * @param qCapacity int : The capacity of the queue, that is how many
221 * processes can be enqueued. Zero (0) means unlimited capacity.
222 * @param capacity int : The number of resources the Res starts
223 * with. Must be positive and greater than 0.
224 * @param showInReport boolean : Flag, if Res should produce a
225 * report or not.
226 * @param showInTrace boolean : Flag for trace to produce trace messages.
227 */
228 public Res (Model owner, String name, int sortOrder, int qCapacity,
229 int capacity, boolean showInReport, boolean showInTrace)
230 {
231 super (owner, name, showInReport, showInTrace); // construct QueueBased
232
233 idNumber = resNumber++; // increment the resNumber and get it as IDNumber
234
235 // check if a valid sortOrder is given
236 if ( sortOrder < 0 ) {
237 sendWarning ( "The given sortOrder parameter is negative! " +
238 "A queue with Fifo sort order will be created.",
239 "Res : "+getName()+
240 " Constructor: Res (Model owner, String name, int " +
241 "sortOrder, long qCapacity, int capacity, boolean " +
242 "showInReport, boolean showInTrace)",
243 "A valid positive integer number must be provided to " +
244 "determine the sort order of the underlying queue.",
245 "Make sure to provide a valid positive integer number "+
246 "by using the constants in the class QueueBased, like "+
247 "QueueBased.FIFO or QueueBased.LIFO.");
248 // make a Fifo queue
249 queue = new QueueListFifo(); // better than nothing
250 queue.setQueueBased(this);
251 }
252 else {
253 try {
254 // determine the queueing strategy
255 Class queueListStrategy = queueingStrategy[sortOrder];
256
257 queue = (QueueList)queueListStrategy.newInstance();
258 }
259
260 catch ( ArrayIndexOutOfBoundsException arrayExcept) {
261 // the given sortOrder is not valid
262 sendWarning ( "The given sortOrder parameter is not valid! " +
263 "A queue with Fifo sort order will be created.",
264 "Res : "+getName()+
265 " Constructor: Res (Model owner, String name, int " +
266 "sortOrder, long qCapacity, int capacity, boolean " +
267 "showInReport, boolean showInTrace)",
268 "A valid positive integer number must be provided to " +
269 "determine the sort order of the underlying queue.",
270 "Make sure to provide a valid positive integer number "+
271 "by using the constants in the class QueueBased, like "+
272 "QueueBased.FIFO or QueueBased.LIFO.");
273 // make a Fifo queue
274 queue = new QueueListFifo(); // better than nothing
275 }
276
277 catch ( IllegalAccessException illAccExcept) {
278 // the class to be loaded can not be found
279 sendWarning ( "IllegalAccessException: The class implementing the " +
280 "sortOrder of the queue can not be found. A queue with "+
281 "Fifo sort order will be created instead.",
282 "Res : "+getName()+
283 " Constructor: Res (Model owner, String name, int " +
284 "sortOrder, long qCapacity, int capacity, boolean " +
285 "showInReport, boolean showInTrace)",
286 "Programm error when trying to create an instance of a " +
287 "class. Maybe the zero-argument constructor of that " +
288 "class can not be found",
289 "Make sure to provide a valid positive integer number "+
290 "for the sort order by using the constants in the class "+
291 "QueueBased, like QueueBased.FIFO or QueueBased.LIFO. "+
292 "Contact one of the developers of DESMO-J!");
293 // make a Fifo queue
294 queue = new QueueListFifo(); // better than nothing
295 }
296
297 catch ( InstantiationException instExcept) {
298 // no object of the given class can be instantiated
299 sendWarning ( "InstantiationException: No object of the given class " +
300 "can be instantiated! A queue with Fifo sort order will "+
301 "be created instead.",
302 "Res : "+getName()+
303 " Constructor: Res (Model owner, String name, int " +
304 "sortOrder, long qCapacity, int capacity, boolean " +
305 "showInReport, boolean showInTrace)",
306 "Programm error when trying to create an instance of a " +
307 "class. Maybe the the class is an interface or an " +
308 "abstract class that can not be instantiated",
309 "Make sure to provide a valid positive integer number "+
310 "for the sort order by using the constants in the class "+
311 "QueueBased, like QueueBased.FIFO or QueueBased.LIFO. "+
312 "Contact one of the developers of DESMO-J!");
313 // make a Fifo queue
314 queue = new QueueListFifo(); // better than nothing
315 }
316
317 // give the QueueList a reference to this QueueBased
318 queue.setQueueBased(this);
319 }
320
321 // set the capacity of the queue
322 queueLimit = qCapacity;
323
324 // check if it the capacity does make sense
325 if ( qCapacity < 0 )
326 {
327 sendWarning ( "The given capacity of the queue is negative! " +
328 "A queue with unlimited capacity will be created instead.",
329 "Res : "+getName()+
330 " Constructor: Res (Model owner, String name, int " +
331 "sortOrder, long qCapacity, int capacity, boolean " +
332 "showInReport, boolean showInTrace)",
333 "A negative capacity for a queue does not make sense." ,
334 "Make sure to provide a valid positive capacity "+
335 "for the underlying queue.");
336 // set the capacity to the maximum value
337 queueLimit = Integer.MAX_VALUE;
338 }
339
340 // check if qCapacity is zero (that means unlimited capacity)
341 if ( qCapacity == 0 )
342 {
343 // set the capacity to the maximum value
344 queueLimit = Integer.MAX_VALUE;
345 }
346
347 // construct a vector to hold all the UnUsedResources at the moment
348 unUsedResources = new java.util.Vector();
349
350 // construct a vector to hold the UsedResources (see the inner class)
351 arrayOfUsedResources = new java.util.Vector();
352
353 // get a reference to the resource database
354 resourceDB = owner.getExperiment().getResourceDB();
355
356 this.limit = capacity;
357 this.minimum = capacity;
358 this.avail = capacity;
359 this.users = 0;
360 this.wSumAvail = 0.0;
361 this.refused = 0;
362 this.lastUsage = currentTime();
363
364 if (capacity <= 0) // nothing or less in the resource pool, you fool!
365 {
366 sendWarning ( "Attempt to construct a Res with nothing or a negativ" +
367 " number of resources. Initial number of resources is set to one!",
368 "Res: " + getName() +
369 " Constructor: Res (Model owner, String name, int sortOrder, " +
370 "long qCapacity, int capacity, boolean showInReport, " +
371 "boolean showInTrace)",
372 "A negative number of resources does not make sense here.",
373 "Make sure to initialize the capacity of a Res always with"+
374 " a positive number of resources.");
375
376 limit = minimum = avail = 1; // set it to 1, that makes more sense
377 }
378
379 // make the resource objects and store them in the vector of unused
380 // resources
381 for (int i = 0; i < capacity; i++)
382 {
383 // make the resources and give them the name of the Res pool
384 Resource aResource = new Resource(owner, name, this, true);
385
386 unUsedResources.addElement(aResource);
387 }
388 }
389 // ****** methods ******
390
391 /**
392 * Constructor for a Res with a number of initial resources in it.
393 * The underlying queue has a Fifo queueing discipline and unlimited capacity.
394 * @param owner Model : The model this Res is associated to.
395 * @param name java.lang.String : The Res's name
396 * @param capacity int : The number of resources the Res starts
397 * with. Must be positive and greater than 0.
398 * @param showInReport boolean : Flag, if Res should produce a
399 * report or not.
400 * @param showInTrace boolean : Flag for trace to produce trace messages.
401 */
402 public Res (Model owner, String name, int capacity,
403 boolean showInReport, boolean showInTrace)
404 {
405 super (owner, name, showInReport, showInTrace); // construct QueueBased
406
407 idNumber = resNumber++; // increment the resNumber and get it as IDNumber
408
409 // make an actual queue and give it a reference of this "QueueBased"-Res
410 queue = new QueueListFifo();
411 queue.setQueueBased(this);
412
413 // construct a vector to hold all the UnUsedResources at the moment
414 unUsedResources = new java.util.Vector();
415
416 // construct a vector to hold the UsedResources (see the inner class)
417 arrayOfUsedResources = new java.util.Vector();
418
419 // get a reference to the resource database
420 resourceDB = owner.getExperiment().getResourceDB();
421
422 this.limit = capacity;
423 this.minimum = capacity;
424 this.avail = capacity;
425 this.users = 0;
426 this.wSumAvail = 0.0;
427 this.refused = 0;
428 this.lastUsage = currentTime();
429
430 if (capacity <= 0) // nothing or less in the resource pool, you fool!
431 {
432 sendWarning ( "Attempt to construct a Res with nothing or a negativ" +
433 " number of resources. Initial number of resources is set to one!",
434 "Res: " + getName() +
435 " Constructor: Res (desmoj.Model owner, String name, " +
436 "int capacity, boolean showInReport, boolean showInTrace)",
437 "A negative number of resources does not make sense here.",
438 "Make sure to initialize the capacity of a Res always with"+
439 " a positive number of resources.");
440
441 limit = minimum = avail = 1; // set it to 1, that makes more sense
442 }
443
444 // make the resource objects and store them in the vector of unused
445 // resources
446 for (int i = 0; i < capacity; i++)
447 {
448 // make the resources and give them the name of the Res pool
449 Resource aResource = new Resource(owner, name, this, true);
450
451 unUsedResources.addElement(aResource);
452 }
453 }
454 /**
455 * Activates the SimProcess <code>process</code>, given as a parameter of
456 * this method, as the next process. This process should be a SimProcess
457 * waiting in the queue for some resources.
458 * @param process SimProcess : The process that is to be activated as next.
459 */
460 protected void activateAsNext ( SimProcess process )
461 {
462 where = "protected void activateAsNext(SimProcess process)";
463
464 if ( process != null )
465 {
466 // if the given process is not valid just return
467 if ( ! checkProcess (process, where) )
468 { return; }
469
470 // if the process is scheduled (on the event list) already
471 if ( process.isScheduled() )
472 {
473 process.skipTraceNote(); // don't tell the user, that we ...
474 process.cancel(); // get the process from the EventList
475 }
476
477 // remember if the process is blocked at the moment
478 boolean wasBlocked = process.isBlocked();
479
480 // unblock the process to be able to activate him
481 if (wasBlocked)
482 {
483 process.setBlocked(false); // the process is not blocked anymore and
484 } // ready to become activated
485
486 // don't tell the user, that we activate the process after the current process
487 process.skipTraceNote();
488 process.activateAfter (current());
489
490 // the process status is still "blocked"
491 if (wasBlocked)
492 {
493 process.setBlocked(true);
494 }
495 } // end outer if
496 }
497 /**
498 * Activates the first process waiting in the queue. That is a process which
499 * was trying to acquire resources, but there were not enough left in the
500 * Res. Or another process was first in the queue to be served.
501 * This method is called every time a process returns resources or when a
502 * process in the waiting queue is satisfied.
503 */
504 protected void activateFirst ()
505 {
506 where = "protected void activateFirst()";
507
508 // first is the first process in the queue (or null if none is in the queue)
509 SimProcess first = (SimProcess) queue.first();
510
511 if ( first != null )
512 {
513 // if first is not modelcompatible just return
514 if ( !checkProcess (first, where))
515 { return;}
516
517 // if first is scheduled (on the event list) already
518 if (first.isScheduled())
519 {
520 first.skipTraceNote(); // don't tell the user, that we ...
521 first.cancel(); // get the process from the Eventlist
522 }
523
524 // remember if first is blocked at the moment
525 boolean wasBlocked = first.isBlocked();
526
527 // unblock the process to be able to activate him
528 if (wasBlocked)
529 {
530 first.setBlocked(false);
531 }
532
533 // don't tell the user, that we activate first after the current process
534 first.skipTraceNote();
535 first.activateAfter (current());
536
537 // the status of first is still "blocked"
538 if (wasBlocked)
539 {
540 first.setBlocked(true);
541 }
542 } // end outer if
543 }
544 /**
545 * Returns the average usage of the Res. That means: in average,
546 * which percentage of the resources were in use over the time?
547 * @return double : the average usage of the resources in the
548 * Res.
549 */
550 public double avgUsage ()
551 {
552 SimTime now = currentTime(); // what is the time?
553
554 // how long since the last reset
555 double diff = now.getTimeValue() - resetAt().getTimeValue();
556
557 double wSumAvl = wSumAvail +
558 ((double)avail * (now.getTimeValue() - lastUsage.getTimeValue()));
559
560 if (diff < epsilon().getTimeValue()) // diff is not long enough
561 {
562 sendWarning ( "A division by zero error occured." ,
563 "Res: " + this.getName() + " Method: double avgUsage ()",
564 "The time difference between the last reset and now is shorter than " +
565 "epsilon (the shortest measurable time step)." ,
566 "Do not reset any model component shortly before the simulation is " +
567 "over or will be stopped." );
568
569 return UNDEFINED; // see QueueBased: UNDEFINED = -1
570 }
571
572 // calculate the average usage
573 double avgUsg = 1.0 - ( (wSumAvl/diff) / (double)limit );
574 // return the rounded average usage
575 return java.lang.Math.rint(100000.0 * avgUsg) / 100000.0;
576 }
577 /**
578 * Changes the limit of the available resources in the Res.
579 * Sets the number of the maximum available resources to m. m must be positive.
580 * This is only allowed as long as the Res has not been used or
581 * the Res has just been reset.
582 * @param m int : The new limit (capacity) of the Res.
583 * Must be positive.
584 */
585 public void changeLimit (int m)
586 {
587 if (limit != minimum || users != 0) // if Res is already used
588 {
589 sendWarning ( "Attempt to change the limit of a Res already" +
590 " in use. The limit will remain unchanged!" ,
591 "Res: " + this.getName() + " Method: void changeLimit (long m)",
592 "The limit of a Res which has already be used can not" +
593 " be changed afterwards." ,
594 "Do not try to change the limit of a Res which might have been" +
595 " used already. Or reset the Res before changing its limit." );
596
597 return; // without changing the limit
598 }
599
600 if ( m <= 0 ) // Trying to set the limit to 0 or a negative value.
601 {
602 sendWarning ( "Attempt to change the limit of a Res to zero" +
603 " or a negative number. The limit will remain unchanged!" ,
604 "Res: " + this.getName() + " Method: void changeLimit " +
605 "(long m)",
606 "The limit of a Res can not be set to zero or a negative" +
607 " number. That would make no sense.",
608 "Do not try to change the limit of a Res to negative " +
609 "or zero. Choose a positive integer instead." );
610
611 return; // ignore this rubbish
612 }
613
614 // adjust the number of resources stored in the array of unused resources
615 if ( m > limit ) // the limit is increasing
616 {
617 for (int i = limit; i < m; i++)
618 {
619 // make the resources and give them the name of the Res pool
620 Resource aResource = new Resource(getModel(), getName(), this, true);
621 unUsedResources.addElement(aResource);
622 }
623 }
624
625 if ( m < limit ) // the limit is decreasing
626 for (int i = m; i < limit; i++)
627 {
628 unUsedResources.removeElementAt(i);
629 }
630
631 // set the limit and the minimum to the new value
632 limit = minimum = avail = m;
633
634 }
635 /**
636 * Checks whether the process using the Res is a valid process.
637 * @return boolean : Returns whether the SimProcess is valid or not.
638 * @param p SimProcess : Is this SimProcess a valid one?
639 */
640 protected boolean checkProcess (SimProcess p, String where)
641 {
642 if (p == null) //if p is a null pointer instead of a process
643 {
644 sendWarning ( "A non existing process is trying to use a Res " +
645 "object. The attempted action is ignored!",
646 "Res: " + getName() + " Method: " + where ,
647 "The process is only a null pointer.",
648 "Make sure that only real SimProcesses are using Res's." );
649 return false;
650 }
651
652 if (!isModelCompatible( p ) ) // if p is not modelcompatible
653 {
654 sendWarning ( "The process trying to use a Res object does"+
655 " not belong to this model. The attempted action is ignored!" ,
656 "Res: " + getName() + " Method: " + where ,
657 "The process is not modelcompatible.",
658 "Make sure that processes are using only Res's within" +
659 " their model.");
660 return false;
661 }
662 return true;
663 }
664 /**
665 * Returns a Reporter to produce a report about this Res.
666 * @return desmoj.report.Reporter : The Reporter for the queue inside this
667 * Res.
668 */
669 public desmoj.report.Reporter createReporter()
670 {
671 return new desmoj.report.ResourceReporter(this);
672 }
673 /**
674 * Turns the deadlock check off. So whenever a SimProcess can not get the
675 * resources desired, there won't be checked if a deadlock situation might
676 * have occured.
677 */
678 public void deadlockCheckOff() {
679
680 deadlockCheck = false; // that's all
681
682 // send a warning if the resource pool has been used already
683 if (limit != minimum || users != 0) // if Res is already used
684 {
685 sendWarning ( "The deadlock check for the resource pool: " +
686 this.getName() + " is turned off!",
687 "Res: " + this.getName() + " Method: void deadlockCheckOff()",
688 "The deadlock check for this resource pool is turned off, but " +
689 "some resources are already in use.",
690 "Make sure, that you really want to turn the deadlock check off " +
691 " even after some resources have been used already." );
692 }
693
694 // for debugging purposes
695 if ( debugIsOn() )
696 {
697 sendDebugNote( "The deadlock check for '" + getName() + "' is turned " +
698 "off now." );
699 }
700 }
701 /**
702 * Turns the deadlock check on. So whenever a SimProcess can not get the
703 * resources desired, it will be checked if a deadlock situation might occur.
704 */
705 public void deadlockCheckOn() {
706
707 deadlockCheck = true; // that's all
708
709 // send a warning if the resource pool has been used already
710 if (limit != minimum || users != 0) // if Res is already used
711 {
712 sendWarning ( "The deadlock check for the resource pool: " +
713 this.getName() + " is turned on. But some resources have been "+
714 "used already!",
715 "Res: " + this.getName() + " Method: void deadlockCheckOn()",
716 "The deadlock check for this resource pool is turned on again, " +
717 "but some resources are already in use. So the deadlock check can " +
718 "not be performed correctly!",
719 "Make sure to turn the deadlock check on before the resources will " +
720 "be used." );
721 }
722
723 // for debugging purposes
724 if ( debugIsOn() )
725 {
726 sendDebugNote( "The deadlock check for '" + getName() + "' is turned " +
727 "on again from now on." );
728 }
729 }
730 /**
731 * Takes a number of n resources from the Res pool and delivers this array
732 * of resources to the Simprocess to use them. Is called from the method
733 * <code>provide (int n)</code>.
734 * @param n int : The number of resources the resourcepool will <code>
735 * deliver()</code> to the SimProcess.
736 * @return Resource[] : the array of resources which will be delivered
737 * to the SimProcess.
738 */
739 private Resource[] deliver (int n)
740 {
741 SimProcess currentProcess = currentSimProcess();
742
743 // get the resources from the unused resources pool
744 Resource[] resArray = new Resource[n]; // make the array of resources
745
746 // fill the array of resources
747 for (int i = 0; i < n; i++)
748 {
749 // put first res in array
750 resArray[i] = (Resource)unUsedResources.firstElement();
751 // delete first res
752 unUsedResources.removeElement(unUsedResources.firstElement());
753 }
754
755 // note which SimProcess is holding how many Resources
756 updateProvidedRes (currentProcess, resArray);
757
758 // for debugging purposes
759 if ( debugIsOn() )
760 {
761 // make a string including all elements of the array of provided res.
762 String s = "delivers to SimProcess '" + currentProcess.getName() + "': ";
763
764 for (int j = 0; j < n; j++)
765 {
766 s += "<br>" + resArray[j].getName();
767 }
768
769 sendDebugNote( s );
770
771 // make a string including all the resource that are left in the Res
772 String t = "In this Res pool are left: ";
773
774 if ( unUsedResources.isEmpty() ) // anything left ?
775 {
776 t += "<br>none";
777 }
778
779 for (Enumeration enum = unUsedResources.elements();
780 enum.hasMoreElements() ; )
781 {
782 t += "<br>"+((Resource)enum.nextElement()).getName();
783 }
784
785 sendDebugNote( t );
786 }
787
788 return resArray; // return the array of resources
789 }
790 /**
791 * Returns the number of resources available in the pool at the moment.
792 * @return int : The number of resources available at the moment.
793 */
794 public int getAvail ()
795 {
796 return this.avail;
797 }
798 /**
799 * Returns if the deadlock check is enabled (<code>true</code>) or not
800 * (<code>false</code>).
801 * @return boolean : <code>true</code> if the deadlock check is enabled,
802 * <code>false</code> if the deadlock check is not enabled
803 */
804 public boolean getDeadlockCheck() {
805
806 return deadlockCheck; // that's all
807 }
808 /**
809 * Returns the ID number of this <code>Res</code> object.
810 * @return long : The ID number of this <code>Res</code> object.
811 */
812 public long getidNumber()
813 {
814 return idNumber;
815 }
816 /**
817 * Returns the initial number of resources in the Res pool.
818 * @return int : The initial number of resources in the Res pool
819 * at the beginning.
820 */
821 public int getLimit ()
822 {
823 return this.limit;
824 }
825 /**
826 * Returns the minimum number of resources in the Res.
827 * @return int : The minimum number of resources in the Res.
828 */
829 public int getMinimum ()
830 {
831 return this.minimum;
832 }
833 /**
834 * Returns whether entities can pass by other entities which are enqueued before
835 * them in the queue.
836 * @return boolean : Indicates whether entities can pass by other entities which
837 * are enqueued before them in the queue.
838 */
839 public boolean getPassBy()
840 {
841 return passBy;
842 }
843 /**
844 * Returns the <code>QueueList</code> actually storing the
845 * <code>SimProcesses</code> waiting for resources.
846 * @return desmoj.QueueList : the queue actually storing the
847 * <code>SimProcesses</code> waiting for resources.
848 */
849 protected QueueList getQueue() {
850
851 return queue; // that's it
852 }
853 /**
854 * Returns the implemented queueing discipline of the underlying queue
855 * as a String, so it can be displayed in the report.
856 * @return String : The String indicating the queueing discipline.
857 */
858 public String getQueueStrategy() {
859
860 return queue.getAbbreviation(); // that's it
861
862 }
863 /**
864 * Returns the number of entities refused to be enqueued in the queue,
865 * because the capacity limit is reached.
866 * @return long : The number of entities refused to be enqueued in the queue.
867 */
868 public long getRefused() {
869
870 return refused; // that's it
871 }
872 /**
873 * Returns the number of users.
874 * @return long : The number of Users. That are processes having acquired
875 * and released resources.
876 */
877 public long getUsers ()
878 {
879 return this.users;
880 }
881 /**
882 * Returns the number of resources held by the given SimProcess at this time.
883 * @return int : The number of resources held by the given SimProcess at this
884 * time.
885 * @param sProc SimProcess : The SimProcess which is expected to hold some
886 * Resources.
887 */
888 protected int heldResources (SimProcess sProc)
889 {
890 int j = 0; // to count the resources held
891
892 for ( int i = 0; i < arrayOfUsedResources.size(); i++)
893 {
894 // get hold of the UsedResources pair (SimProcess/number of resources)
895 UsedResources procHoldRes =
896 (UsedResources)arrayOfUsedResources.elementAt(i);
897
898 if (procHoldRes.getProcess() == sProc)
899 {
900 j += procHoldRes.getOccupiedResources().size();
901 } // end if
902 } // end for
903
904 return j; // all the resources the SimProcess holds at the moment
905 }
906 /**
907 * Returns <code>true</code> if a deadlock is detected, <code>false</code>
908 * otherwise.
909 * @return boolean : is <code>true</code> if a deadlock is detected,
910 * <code>false</code> otherwise.
911 */
912 public boolean isDeadlockDetected() {
913
914 return deadlockDetected; // that's it
915 }
916 /**
917 * Gets a number of n resources from the Res pool and provides them to the
918 * SimProcess to use them. Hint for developers: calls the private method
919 * <code>deliver()</code>. As not enough resources are available at the moment
920 * the SimProcess has to wait in a queue until enough products are available
921 * again.
922 * @return boolean : Is <code>true</code> if the specified number of
923 * resources have been provided successfully, <code>false</code> otherwise
924 * (i.e. capacity limit of the queue is reached).
925 * @param n int : The number of resources the resourcepool will <code>
926 * provide()</code> to the SimProcess.
927 */
928 public boolean provide (int n)
929 {
930 where = " boolean provide (int n)";
931
932 SimProcess currentProcess = currentSimProcess();
933
934 if ( !checkProcess(currentProcess, where) ) // if the current process
935 { return false; } // is not valid: return
936
937 if ( n <= 0 ) // trying to provide nothing or less
938 {
939 sendWarning ( "Attempt from a Res to provide nothing or a negative " +
940 "number of resources . The attempted action is ignored!" ,
941 "Res: " + getName() + " Method: provide (int n)",
942 "It does not make sense to provide nothing or a negative number " +
943 "of resources. The statistic will be corrupted with negative numbers!" ,
944 "Make sure to provide at least one resource from the Res.");
945
946 return false; // ignore that rubbish
947 }
948
949 // total of resources acquired and already held by the current SimProcess
950 int total = n + heldResources(currentProcess);
951
952 if ( total > limit ) // trying to provide (in total) more than the
953 { // capacity of the Res
954 sendWarning ( "Attempt from a Res to provide more resources than its " +
955 "capacity holds. The attempted action is ignored!" ,
956 "Res: " + getName() + " Method: provide (int n)",
957 "The requested resources [" + total + "] could never be provided by the Res" +
958 ", because the capacity of this Res [" + limit + "] is not that big. <br>" +
959 "Therefore the process '" + currentProcess.getName() + "' might be blocked " +
960 "for ever." ,
961 "Make sure never to let the Res provide more resources than its " +
962 "capacity.");
963
964 return false; // ignore that rubbish
965 }
966
967 if ( queueLimit <= length() ) // check if capac. limit of queue is reached
968 {
969 sendDebugNote("refuses to insert "+currentProcess.getQuotedName()+
970 " in waiting queue, because the capacity limit is reached. ");
971
972 sendTraceNote("is refused to be enqueued in "+this.getQuotedName() +
973 "because the capacity limit (" + getQueueLimit() + ") of the " +
974 "queue is reached");
975
976 refused++; // count the refused ones
977
978 return false; // capacity limit is reached
979 }
980
981 // insert every process in the queue for statistical reasons
982 queue.insert (currentProcess);
983
984 // is it possible for this process to pass by?
985 if ( passBy == false )
986 {
987 // see if the SimProcess can be satisfied or has to wait in the queue
988 if ( n > avail || // not enough resources available OR
989 currentProcess != queue.first() ) // other process is first in the q
990 {
991 // tell in the trace what the process is waiting for
992 if ( traceIsOn() )
993 {
994 sendTraceNote ( "awaits " + n + " of ' " + this.getName() + " '" );
995 }
996
997 // tell in the debug output what the process is waiting for
998 if ( debugIsOn() )
999 {
1000 sendDebugNote ( "has not enough resources left to provide " + n +
1001 " unit(s) to '" + currentProcess.getName() + "'" );
1002 }
1003
1004 // check for deadlock?
1005 if ( getDeadlockCheck() )
1006 {
1007 // update the resourceDB: this SimProcess is requesting resources
1008 resourceDB.noteResourceRequest(currentProcess, this, n);
1009
1010 // check if this unsatisfied resource request has caused a deadlock
1011 deadlockDetected = resourceDB.checkForDeadlock(currentProcess);
1012 }
1013
1014 // the process is caught in this do-while loop as long as ...see while
1015 do
1016 {
1017 currentProcess.setBlocked(true); // block the process
1018 currentProcess.skipTraceNote(); // don't tell the user, that we ...
1019 currentProcess.passivate(); // passivate the current process
1020 }
1021 while ( n > avail || // not enough resources available OR
1022 currentProcess != queue.first() ); // other process is first
1023
1024 // check for deadlock?
1025 if ( getDeadlockCheck() )
1026 {
1027 // delete the request of the resources in the resourceDB
1028 resourceDB.deleteResRequest(currentProcess, this, n);
1029 }
1030
1031 } // end if
1032 }
1033 else // the process can pass by other processes in the queue, passBy = true
1034 {
1035 if ( n > avail || // not enough resources available OR
1036 currentProcess != queue.first() ) // other process is first in the q
1037 {
1038 // is the current process the first in the queue?
1039 if ( currentProcess != queue.first() ) // no it's not the first
1040 {
1041 // we have to make sure that no other process in front of this current
1042 // process in the wait queue could be satisfied, so activate
1043 // the first Process in the queue to see what he can do. He will pass
1044 // the activation on to his successors until this process will be
1045 // activated again to get his products. (hopefully)
1046 activateFirst();
1047 }
1048
1049 // only if not enough units are available the process has to wait
1050 if ( n > avail )
1051 {
1052 // tell in the trace what the process is waiting for
1053 if ( traceIsOn() )
1054 {
1055 sendTraceNote ( "awaits " + n + " of ' " + this.getName() + " '" );
1056 }
1057
1058 // tell in the debug output what the process is waiting for
1059 if ( debugIsOn() )
1060 {
1061 sendDebugNote ( "has not enough resources left to provide " + n +
1062 " unit(s) to '" + currentProcess.getName() + "'" );
1063 }
1064 } // end if not enough units are available
1065
1066 // check for deadlock?
1067 if ( getDeadlockCheck() )
1068 {
1069 // update the resourceDB: this SimProcess is requesting resources
1070 resourceDB.noteResourceRequest(currentProcess, this, n);
1071
1072 // check if this unsatisfied resource request has caused a deadlock
1073 deadlockDetected = resourceDB.checkForDeadlock(currentProcess);
1074 }
1075
1076 // the process is caught in this do-while loop as long as ...see while
1077 do
1078 {
1079 currentProcess.setBlocked(true); // block the process
1080 currentProcess.skipTraceNote(); // don't tell the user, that we ...
1081 currentProcess.passivate(); // passivate the current process
1082
1083 // activate the next process in the queue to see what he can do
1084 activateAsNext( (SimProcess)queue.succ(currentProcess) );
1085 }
1086 while ( n > avail ); // not enough resources available
1087
1088 // check for deadlock?
1089 if ( getDeadlockCheck() )
1090 {
1091 // delete the request of the resources in the resourceDB
1092 resourceDB.deleteResRequest(currentProcess, this, n);
1093 }
1094
1095 }
1096 } // end else (passBy = true)
1097
1098 // the current process has got the resources he wanted ...
1099
1100 // the Res provides all the resources the SimProcess wants
1101 queue.remove (currentProcess); // get the process out of the queue
1102 currentProcess.setBlocked(false); //we are not blocked (anymore), yeah!
1103
1104 // give the new first process in the queue a chance
1105 activateFirst();
1106
1107 // hand the resources over to the SimProcess
1108 currentProcess.obtainResources( deliver(n) );
1109
1110 updateStatistics ( -n ); // statistics will be updated
1111
1112 // check for deadlock?
1113 if ( getDeadlockCheck() )
1114 {
1115 // update the resourceDB: resources are assigned to the SimProcess now
1116 resourceDB.noteResourceAllocation(this, currentProcess, n);
1117 }
1118
1119 if ( traceIsOn() )
1120 {
1121 sendTraceNote ( "seizes " + n + " from " + this.getQuotedName() );
1122 } // tell in the trace what the process is taking from the resources
1123
1124 // a debug message is generated in the method deliver(), see some lines above
1125
1126 return true;
1127}
1128/**
1129 * Resets the statistics of this Res. The number of available
1130 * resources at this moment and the processes waiting in the queue are not
1131 * changed. But all statistic counters are reset.
1132 * The parent <code>QueueBased</code> is also reset.
1133 */
1134 public void reset ()
1135 {
1136 super.reset(); // reset the QueueBased also
1137
1138 minimum = limit; // not quite correct, but needed for changeLimit()
1139 users = 0;
1140 wSumAvail = 0.0;
1141 refused = 0;
1142 lastUsage = currentTime();
1143 }
1144/**
1145 * Sets the boolean field <code>deadlockDetected</code> to the given value.
1146 * If a deadlock for this <code>Res</code> is detected when an unsuccessfull
1147 * seize statement for a resource has taken place, then the value of
1148 * <code>deadlockDetected</code> will be set to <code>true</code>. The value
1149 * will also been shown in the report of this <code>Res</code>.
1150 * @param dlDetected boolean : the new value for the field
1151 * <code>deadlockDetected</code>. Should be <code>true</code> if this
1152 * <code>Res</code> is involved in a deadlock.
1153 */
1154protected void setDeadlockDetected(boolean dlDetected) {
1155
1156 deadlockDetected = dlDetected; // that's all
1157}
1158/**
1159 * Sets the flag passBy to a new value. PassBy is indicating whether entities can
1160 * pass by other entities which are enqueued before them in the queue.
1161 * @param newPassBy boolean : The new value of passBy. Set it to <code>true</code>
1162 * if you want entities to pass by other entities which are enqueued before them
1163 * in the queue. Set it to <code>false</code> if you don't want entities to
1164 * overtake other entities in the queue.
1165 */
1166public void setPassBy(boolean newPassBy)
1167{
1168 this.passBy = newPassBy; // that's all!
1169}
1170/**
1171 * A process is using this method to put resources it has used back in the
1172 * Res pool. The process can not put more resources back than it has
1173 * acquired once. The array of returning resources can be provided by the
1174 * method <code>returnResources()</code> of the class <code>SimProcess</code>.
1175 * @param returnedRes Resource[] : The array of resources a process is
1176 * returning to the resource pool.
1177 * Can't be more resources than it once has acquired!
1178 */
1179 public void takeBack (Resource[] returnedRes)
1180 {
1181 where = "void takeBack (Resource[] returnedRes) ";
1182
1183 SimProcess currentProcess = currentSimProcess();
1184
1185 if (!checkProcess(currentProcess, where)) //check the current process
1186 { return; } // if it is not valid just return
1187
1188 if (returnedRes.length <= 0) // if the process is releasing nothing
1189 {
1190 sendWarning ( "The array of returned resources is empty! " +
1191 "The attempted action is ignored!" ,
1192 "Res: " + this.getName() + " Method: void takeBack (Resource[] " +
1193 "returnedRes)",
1194 "It makes no sense to take back an empty array of resources." ,
1195 "Make sure to return at least one resource to the Res pool.");
1196
1197 return; // go to where you came from
1198 }
1199
1200 // the process is trying to release more resources than it holds
1201 if ( returnedRes.length > heldResources(currentProcess) )
1202 {
1203 sendWarning ( "Attempt to make the Res take back more resources than " +
1204 "the process is holding at the moment. The attempted action is " +
1205 "ignored!" ,
1206 "Res: " + this.getName() + " Method: void takeBack (Resource[] " +
1207 "returnedRes)",
1208 "A process can not release more resources than it holds." ,
1209 "Make sure not to take back more resources than the process is holding.");
1210
1211 return; // go to where you came from
1212 }
1213
1214 // put the used resources back in the unused resources pool
1215 for (int i = 0; i < returnedRes.length; i++)
1216 {
1217 unUsedResources.addElement(returnedRes[i]);
1218 }
1219
1220 // update which SimProcess is holding which Resources
1221 updateTakenBackRes (currentProcess, returnedRes);
1222
1223 updateStatistics ( returnedRes.length ); // statistics will be updated
1224 users++; // update users
1225
1226 // update the resource database / check for deadlock?
1227 if ( getDeadlockCheck() )
1228 {
1229 resourceDB.deleteResAllocation(this, currentProcess, returnedRes.length);
1230 }
1231
1232 // tell in the trace what the process is returning to the Res pool
1233 if ( traceIsOn() )
1234 {
1235 sendTraceNote ( "releases " + returnedRes.length + " to " +
1236 this.getQuotedName() );
1237 }
1238
1239 // for debugging purposes
1240 if ( debugIsOn() )
1241 {
1242 // make a string including all elements of the array of returned res.
1243 String s = "SimProcess '"+ currentProcess.getName() +
1244 "' <b>returns</b>: ";
1245
1246 for (int j = 0; j < returnedRes.length; j++)
1247 {
1248 s += "<br>" + returnedRes[j].getName();
1249 }
1250
1251 sendDebugNote( s );
1252 }
1253
1254 activateFirst(); // give the new first process in the queue a chance
1255 }
1256/**
1257 * A process is using this method to put resources it has used back in the
1258 * Res pool. The process can not put more resources back than it has
1259 * acquired once. This method can be used as an alternative to the method
1260 * <code>takeBack(Resource[] returnedRes)</code> in cases that the user
1261 * does not want to provide an array of returning resources. This method is
1262 * also compatible with older DESMO-J Versions.
1263 * @param n int : The number of resources which should be returned to the
1264 * Res pool. Can't be more than once were acquired!
1265 */
1266public void takeBack(int n)
1267{
1268 where = "void takeBack (int n) ";
1269
1270 SimProcess currentProcess = currentSimProcess();
1271
1272 if (!checkProcess(currentProcess, where)) //check the current process
1273 { return; } // if it is not valid just return
1274
1275 if (n <= 0) // if the process is releasing nothing
1276 {
1277 sendWarning ( "The number of returned resources is negative or zero! " +
1278 "The attempted action is ignored!" ,
1279 "Res: " + this.getName() + " Method: void takeBack (int n)",
1280 "It makes no sense to take back nothing or a negative number of " +
1281 "resources." ,
1282 "Make sure to return at least one resource to the Res pool.");
1283
1284 return; // go to where you came from
1285 }
1286
1287 // the process is trying to release more resources than it holds
1288 if ( n > heldResources(currentProcess) )
1289 {
1290 sendWarning ( "Attempt to make the Res take back more resources [" + n +
1291 "] than the process '" + currentProcess.getName() + "' is holding at the " +
1292 "moment [" + heldResources(currentProcess) + "]. <br>" +
1293 "The attempted action is ignored!" ,
1294 "Res: " + this.getName() + " Method: void takeBack (int n)",
1295 "A process can not release more resources than it holds." ,
1296 "Make sure not to bring back more resources than the process is holding.");
1297
1298 return; // go to where you came from
1299 }
1300
1301 // get the array of returned resources from the SimProcess
1302 Resource[] returnedRes = currentProcess.returnResources(this, n);
1303
1304 // put the used resources back in the unused resources pool
1305 for (int i = 0; i < n; i++)
1306 {
1307 unUsedResources.addElement(returnedRes[i]);
1308 }
1309
1310 // update which SimProcess is holding which Resources
1311 updateTakenBackRes (currentProcess, returnedRes);
1312
1313 updateStatistics ( n ); // statistics will be updated
1314 users++; // update users
1315
1316 // update the resource database / check for deadlock?
1317 if ( getDeadlockCheck() )
1318 {
1319 resourceDB.deleteResAllocation(this, currentProcess, n);
1320 }
1321
1322 // tell in the trace what the process is returning to the Res pool
1323 if ( traceIsOn() )
1324 {
1325 sendTraceNote ( "releases " + n + " to " + this.getQuotedName() );
1326 }
1327
1328 // for debugging purposes
1329 if ( debugIsOn() )
1330 {
1331 // make a string including all elements of the array of returned res.
1332 String s = "SimProcess '"+ currentProcess.getName() +
1333 "' <b>returns</b>: ";
1334
1335 for (int j = 0; j < returnedRes.length; j++)
1336 {
1337 s += "<br>" + returnedRes[j].getName();
1338 }
1339
1340 sendDebugNote( s );
1341 }
1342
1343 activateFirst(); // give the new first process in the queue a chance
1344}
1345/**
1346 *
1347 * Muss durch eine andere Methode in SimProcess ersetzt werden ???
1348 *
1349 * Soenke ????
1350 *
1351 *
1352 * A process is using this method to return all the resources it holds to the
1353 * Res pool. The process can not put more resources back than it has acquired
1354 * once. This method can be used if a Process is about to be terminated.
1355
1356 public void takeBackAll ()
1357 {
1358 where = "void takeBackAll ()";
1359
1360 int n = 0; // how many resources will be taken back
1361
1362 SimProcess currentProcess = currentSimProcess();
1363
1364 if (!checkProcess(currentProcess, where)) //check the current process
1365 { return; } // if it is not valid just return
1366
1367 // delete the entry of the currentSimProcess in the arrayOfUsedResources
1368
1369 // search the whole vector
1370 for ( int i = 0; i < arrayOfUsedResources.size(); i++)
1371 {
1372 // get hold of the UsedResources pair (SimProcess/number of resources)
1373 UsedResources procHoldRes =
1374 (UsedResources)arrayOfUsedResources.elementAt(i);
1375
1376 if (procHoldRes.getProcess() == currentProcess)
1377 {
1378 // number of resources held by the currentProcess
1379 n = procHoldRes.getOccupiedResources ();
1380
1381 arrayOfUsedResources.removeElementAt(i); // delete the entry
1382 }
1383 } // end for
1384
1385 updateStatistics ( n ); // statistics will be updated
1386
1387 users++; // update users
1388
1389 // tell in the trace that the process is releasing all its resources
1390 if ( traceIsOn() )
1391 {
1392 sendTraceNote ( "releases all its " + n + " " + this.getName() );
1393 }
1394
1395 activateNext(); // give waiting process in the queue a chance
1396 }
1397 */
1398
1399/**
1400 * Updates the arrayOfUsedResources for this Res whenever resources are
1401 * <code>provided</code>.
1402 * @param crntProcess SimProcess : The current SimProcess acquiring resources.
1403 * @param providedRes Resource[] : The array of resources the Res is
1404 * providing to the current SimProcess.
1405 */
1406 protected void updateProvidedRes (SimProcess crntProcess,
1407 Resource[] providedRes)
1408 {
1409 // is the SimProcess already holding resources?
1410 boolean holdsResources = false; // not yet
1411
1412 // search the whole vector
1413 for ( int i = 0; i < arrayOfUsedResources.size(); i++)
1414 {
1415 // get hold of the UsedResources pair (SimProcess/number of resources)
1416 UsedResources procHoldRes =
1417 (UsedResources)arrayOfUsedResources.elementAt(i);
1418
1419 // is the SimProcess already holding resources?
1420 if (procHoldRes.getProcess() == crntProcess)
1421 {
1422 // update the held resources of the current SimProcess
1423