| 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 |