Unix |
Unix v6 |
|
 |
cr(7) |
 |
crfork, crexit, crread, crwrite, crexch, crprior
coroutine scheme
int crfork( [ stack, nwords ] )
int stack[];
int nwords;
crexit()
int crread(connector, buffer, nbytes)
int *connector[2];
char *buffer;
int nbytes;
crwrite(connector, buffer, nbytes)
int *connector[2];
char *buffer;
int nbytes;
crexch(conn1, conn2, i)
int *conn1[2], *conn2[2];
int i;
#define logical char *
crprior(p)
logical p;
These functions are named by analogy to (II). They establish
and synchronize ‘coroutines’, which behave in
many respects like a set of processes working in the same
address space. The functions live in Coroutines are placed
on queues to indicate their state of readiness. One
coroutine is always distinguished as ‘running’.
Coroutines that are runnable but not running are registered
on a ‘ready queue’. The head member of the ready
queue is started whenever no other coroutine is specifically
caused to be running. Each connector heads two queues: is
the queue of unsatisfied outstanding on the connector. is
the queue of All queues must start empty, with heads set to
zero. is normally called with no arguments. It places the
running coroutine at the head of the ready queue, creates a
new coroutine, and starts the new one running. returns
immediately in the new coroutine with value 0, and upon
restarting of the old coroutine with value 1. stops the
running coroutine and does not place it in any queue. copies
characters from the of the at the head of the write queue to
the of If the write queue is empty, copying is delayed and
the running coroutine is placed on the read queue. The
number of characters copied is the minimum of and the number
of characters remaining in the write and is returned as the
value of After copying, the location of the write and the
corresponding are updated appropriately. If zero characters
remain, the coroutine of the is moved to the head of the
ready queue. If the write queue remains nonempty, the head
member of the read queue is moved to the head of the ready
queue. queues the running coroutine on the write queue, and
records the fact that (zero or more) characters in the
string are available to If the read queue is not empty, its
head member is started running. exchanges the read queues of
connectors and if i=0; and it exchanges the write
queues if i=1. If a nonempty read queue that had been
paired with an empty write queue becomes paired with a
nonempty write queue, moves the head member of that read
queue to the head of the ready queue. sets a priority on the
running coroutine to control the queuing of and When queued,
the running coroutine will take its place before coroutines
whose priorities exceed its own priority and after others.
Priorities are compared as logical, unsigned, quantities.
Initially each coroutine’s priority is set as large as
possible, so default queuing is FIFO. The old and new
coroutine share the same activation record in the function
that invoked so only one may return from the invoking
function, and then only when the other has completed
execution in that function. The activation record for each
function execution is dynamically allocated rather than
stacked; a factor of 3 in running time overhead can result
if function calls are very frequent. The overhead may be
overcome by providing a separate stack for each coroutine
and dispensing with dynamic allocation. The base (lowest)
address and size of the new coroutine’s stack are
supplied to as optional arguments and Stacked allocation and
dynamic allocation cannot be mixed in one run. For stacked
operation, obtain the coroutine functions from instead of
/usr/lib/cr.a
/usr/lib/scr.a ‘rsave doesn’t work’ an old
C compilation has called ‘rsave’. It must be
recompiled to work with the coroutine scheme. Under
/usr/lib/cr.a each function has just 12 words of anonymous
stack for hard expressions and arguments of further calls,
regardless of actual need. There is no checking for stack
overflow.
Under /usr/lib/scr.a stack overflow checking is not
rigorous.
 |
cr(7) |
 |