One of the most powerful features of IC is its multi-tasking facility. Processes can be created and destroyed dynamically during run-time.
Any C function can be spawned as a separate task. Multiple tasks running the same code, but with their own local variables, can be created.
Processes communicate through global variables: one process can set a global to some value, and another process can read the value of that global.
Each time a process runs, it executes for a certain number of ticks, defined in milliseconds. This value is determined for each process at the time it is created. The default number of ticks is five; therefore, a default process will run for 5 milliseconds until its "turn" ends and the next process is run. All processes are kept track of in a process table; each time through the table, each process runs once (for an amount of time equal to its number of ticks).
Each process has its own program stack. The stack is used to pass arguments for function calls, store local variables, and store return addresses from function calls. The size of this stack is defined at the time a process is created. The default size of a process stack is 256 bytes.
Processes that make extensive use of recursion or use large local arrays will probably require a stack size larger than the default. Each function call requires two stack bytes (for the return address) plus the number of argument bytes; if the function that is called creates local variables, then they also use up stack space. In addition, C expressions create intermediate values that are stored on the stack.
It is up to the programmer to determine if a particular process requires a stack size larger than the default. A process may also be created with a stack size smaller than the default, in order to save stack memory space, if it is known that the process will not require the full default amount.
When a process is created, it is assigned a unique process identification number or pid. This number can be used to kill a process.
The function to create a new process is start_process
.
start_process
takes one mandatory argument--the function call to be
started as a process. There are two optional arguments: the process's
number of ticks and stack size. (If only one optional argument is
given, it is assumed to be the ticks number, and the default stack size is
used.)
start_process
has the following syntax:
int start_process(function-call(...),[TICKS],[STACK-SIZE])
start_process
returns an integer, which is the process ID
assigned to the new process.
The function call may be any valid call of the function used. The
following code shows the function main
creating a process:
void check_sensor(int n) { while (1) printf("Sensor %d is %d\n", n, digital(n)); } void main() { start_process(check_sensor(2)); }
Normally when a C functions ends, it exits with a return value or the
"void" value. If a function invoked as a process ends, it "dies,"
letting its return value (if there was one) disappear. (This is okay,
because processes communicate results by storing them in globals, not by
returning them as return values.) Hence in the above example, the
check_sensor
function is defined as an infinite loop, so as to run
forever (until the board is reset or a kill_process
is
executed).
Creating a process with a non-default number of ticks or a non-default
stack size is simply a matter of using start_process
with optional
arguments; e.g.
start_process(check_sensor(2), 1, 50);
will create a check_sensor
process that runs for 1 milliseconds
per invocation and has a stack size of 50 bytes (for the given
definition of check_sensor
, a small stack space would be
sufficient).
The kill_process
function is used to destroy processes. Processes
are destroyed by passing their process ID number to kill_process
,
according to the following syntax:
int kill_process(int pid);
kill_process
returns a value indicating if the operation was
successful. If the return value is 0
, then the process was
destroyed. If the return value is 1
, then the process was not
found.
The following code shows the main
process creating a
check_sensor
process, and then destroying it one second later:
void main() { int pid; pid= start_process(check_sensor(2)); sleep(1.0); kill_process(pid); }
IC has two commands to help with process management. The commands only work when used at the IC command line. They are not C functions that can be used in code.
kill_all
ps
The following functions are implemented in the standard C library.
void hog_processor()
hog_processor()
. Only a system reset will
unwedge from this state. Needless to say, this function should be
used with extreme care, and should not be placed in a loop, unless
wedging the machine is the desired outcome.
void defer()
defer()
is implemented as a C built-in function.