While a method is being executed it is called a frame. The
frame is relevant only to the current method. Each frame has a limited
amount of time that it can execute in, also known as ticks. If
a frame runs out of ticks before it is finished executing, the
~ticks error is thrown.
Multiple methods calling each other in succession is called a task. Tasks usually originate from either a connection, a heartbeat, or by being forked from another task. There is no restriction on how long a task can execute, other than that imposed upon each frame.
It is possible to pause an executing frame and refresh the ticks it
has by calling the function pause(). When this occurs the frame stops executing and it's task
is placed behind all other current tasks. When all other current tasks
are completed executing the paused task will resume with a new tick pool.
This behavior is called preempting.
If you are unsure about the amount of ticks left in a method, you can
call the function ticks_left(). Or, you can call refresh() instead of pause(). refresh() will
only preempt if the current frame is nearly out of ticks.
You can also suspend a task indefinitely, by using the function
suspend(). The
function resume()
will resume a suspended task. The function cancel() will cancel a suspended task.
An example of suspending a task is for reading an indefinite amount of input from a connection. Input arrives through the parse method on an object (see Networking), which we define as follows, assuming the object variables reading, read, buffer and lines. reading is used to store a boolean value of true or false, depending upon if we are reading input or not. read is used to store what we have already read from the connection. buffer is used to store incoming information which is not yet parsable by the function buf_to_strings() (i.e. there is no carriage return yet). lines is used to buffer lines converted by buf_to_strings() from the connection which we have not parsed yet. It is important to use an object variable for both buffer and lines, because if the task suspends all information stored in either variable would be suspended along with that instance of the task.
driver method .parse() {
arg incoming;
var line;
lines = buf_to_strings(buffer + incoming));
buffer = lines[listlen(lines)];
lines = delete(lines, listlen(lines));
// now parse the lines
for line in (buf_to_strings(incoming)) {
if (reading) {
if (line == ".")
.done_reading();
else
read += [line];
} else {
.parse_line(line);
}
}
}
We will not define the method parse_line, just assume that it parses the line as a command. When an object wishes to start reading from the connection it calls the method .read() on the connection object:
public method .read() {
// reading just has to be true, so lets save space and store the task
// id there as well, instead of storing it in another variable.
reading = task_id();
// make sure this is an empty list
read = [];
// suspend the task, have our return value be the return value of suspend
// (which is whatever resume() sends)
return suspend();
}
When a period is found as the line being read, the connection is done reading (the period is insignificant, you can terminate your reading any way you desire), and the method done_reading is called:
protected method .done_reading() {
var info, task;
// get a local copy of what we read, and the task id
info = read;
task = reading;
// reset the object variables first
read = [];
reading = 0;
// resume the task, send what we read as the return value for suspend()
resume(task, info);
}
Now, all that has to happen to read input from a connection is to call the method .read() on the connection object, and the input read is returned from the method call.
It is possible to set a task as atomic. Atomic tasks cannot
be preempted or suspended. If an attempt is made to preempt or suspend
an atomic task the error ~atomic is thrown instead. However,
calling refresh() while executing atomically will always
refresh the current frame's ticks. A task's atomic state is toggled using
the function atomic().
Note: be very cautious when using atomic tasks. Atomic tasks can easilly disrupt the regular integrity of an online environment. See the section on Security.
Last Modified on Feb 25 1996
Copyright © 1995, 1996, Brandon Gillespie