When an entity makes a request to the simulation – such as set a timer, use a facility, etc – the simulator returns backs a Request object. The entity can use this Request object to further modify the original request.
The Request object is returned when an entity makes any of the following requests:
The Request object can then be used to modify the request in the following ways:
Except for cancel(), all other functions return the Request object back, therefore, these functions can be chained together. For example:
// Example of chained function calls
this.putBuffer(buffer, 10)
.done(fnWhenSatisfied)
.done(fnAlsoWhenSatisfied)
.waitUntil(10, fnCouldNotAllocIn10Sec)
.unlessEvent(event1, fnEvent1Happened)
.unlessEvent(event2, fnEvent2Happened)
.setData('give me this data when ANY callback function is called');
The following table summarizes the various outcomes of a request and which callback functions are called in each case:
Outcome of Request | callback in done() | callback in waitUntil() | callback in unlessEvent() |
---|---|---|---|
Request is satisfied | Yes | No | No |
Timeout occurs | No | Yes | No |
Event is fired | No | No | Yes |
cancel() called | No | No | No |
Note
The Request constructor should be considered as a private API. Application code should not explicitly create objects of this class.
callback is a function (named or anonymous) that must be called when the request is satisfied.
context is the object in whose context the function will be called. The behavior is therefore equivalent to: callback.call(context). If context argument is not provided or is set to a value that evaluates to false, it is assumed to be the calling entity object.
argument are the optional arguments that are passed to the callback function. If argument is an array then the simulator will execute callback.apply(context, argument), otherwise the simulator will execute callback.call(context, argument).
Note 1: This function can be called multiple times for the same request object, in which case all the callback functions will be called. The simulator guarantees that the the ordering of callback functions will be same as the order in which they were added.
Note 2: If this function is not applied for a request object, then the simulator will still schedule this request and handle it appropriately. Other callback functions defined in waitUntil() or unlessEvent() may still be called. This is useful when the application is interested in error conditions only, for example:
// done() function is not applied to the request object.
// The simulator will schedule and process this request appropriately,
// and may call the other callback functions.
this.putBuffer(buffer, 10)
.unlessEvent(event, handleEvent)
.waitUntil(event, handleTimeout);
Note 3: Even if the request is immediately satisfied (for example, buffer has enough free space for the put request), the callback function will still be called after the function scope that made this request has finished. That is:
start: function() {
// Adding 0 units.. should always succeed immediately
this.putBuffer(buffer, 0).done(function () {
document.write("I will be printed as second line.");
});
document.write("I will be printed as first line.");
}
Set a timeout value to the request. If the request is not satisfied within the duration time interval, it will be terminated and the callback function will be called.
context is the object in whose context the function will be called. The behavior is therefore equivalent to: callback.call(context). If context argument is not provided or is set to value that evaluates to false, it is assumed to be the calling entity object.
argument are the optional arguments that are passed to the callback function. If argument is an array then the simulator will execute callback.apply(context, argument), otherwise the simulator will execute callback.call(context, argument).
As noted in the table above, if the timeout occurs then no other callback function (for example, in done() or unlessEvent()) will be called.
Note: The API does not prevent calling this function multiple times, however, note that only one callback function (the one with smallest timeout value) is effectively useful.
event is either:
Puts the request in the wait queue of one or more events. If any of those events are fired, the request will be terminated and the callback function will be called.
context is the object in whose context the function will be called. The behavior is therefore equivalent to: callback.call(context). If context argument is not provided or is set to value that evaluates to false, it is assumed to be the calling entity object.
argument are the optional arguments that are passed to the callback function. If argument is an array then the simulator will execute callback.apply(context, argument), otherwise the simulator will execute callback.call(context, argument).
As noted in the table above, if the timeout occurs then no other callback function (for example, in done() or waitUntil()) be called.
Note: This function can be called multiple times for the same request object. Note that if one event appears in more than one waitUntil() function, even then only one callback functions will be called. The simulator will non-deterministically select which callback function to call. The following table summarizes the semantics of the callback behavior of this function. Assume ev1 and ev2 are two events, and request is the Request object.
Code | ev1 fired | ev2 fired |
---|---|---|
request.unlessEvent(ev1, fn1).unlessEvent(ev2, fn2) | fn1 called | fn2 called |
request.unlessEvent([ev1, ev2], fn1) | fn1 called | fn1 called |
request.unlessEvent(ev1, fn1).unlessEvent(ev1, fn2) | one of f1 or fn2 called |
data can be any data type (primitive type, arrays, objects etc) which will be returned back when the simulator notifies the entity about the request.
From within the callback function, this data can be accessed through the this.callbackData attribute. This attribute is defined only during the scope of the callback function, and only during the time when the callback function is executing.
This function can be called multiple times for the same request object, but each new invocation will overwrite the data from previous calls.
The data, once set, will be returned to all callback function (if they are called).
For example:
var Entity = {
start: function () {
this.putBuffer(buffer, 10)
.done(this.fn1)
.unlessEvent(e, this.fn2)
.setData('my data');
// this.userData is undefined outside the callback functions
assert(this.callbackData === undefined);
},
fn1: function () {
assert(this.callbackData === 'my data');
},
fn2: function () {
// this.userData is visible in all callback functions
assert(this.callbackData === 'my data');
}
};
Cancel a request. After this call, no callback function will be called.
Note
Special case with facilities.
In case of facilities with FIFO queuing discipline, the requesting entities go through two stages: (1) wait for the facility to become free (this may be zero duration if the facility is already free), and (2) use the facility for specified duration. The waitUntil(), unlessEvent() and cancel() functions are applicable in the first stage only. In order words, if an entity has started using the facility, then it cannot be dislodged and these function calls will have no effect.
In case of facilities with LIFO and Processor Sharing disciplines, the requesting entities obtain an immediate access to the facility resource. Therefore, waitUntil(), unlessEvent() and cancel() functions will have no effect for these facilities.
Request class has three functions that accept callback functions: done(), waitUntil() and unlessEvent(). Before calling the callback functions, the simulator may assign one or more of these attributes in the context object:
this.callbackData. User defined data through setData().