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