\begindata{text, 268755860}
\textdsversion{12}
\template{default}
\define{italic
menu:[Font,Italic]
attr:[FontFace Italic Int Set]}
\define{bold
menu:[Font,Bold]
attr:[FontFace Bold Int Set]}
\define{chapter
menu:[Title,Chapter]
attr:[Justification Centered Point 0]
attr:[FontSize PreviousFontSize Point 4]}
\define{section
menu:[Title,Section]
attr:[Justification Centered Point 0]
attr:[FontSize PreviousFontSize Point 4]}
\define{subsection
menu:[Title,Subsection]
attr:[Justification LeftJustified Point 0]
attr:[FontSize PreviousFontSize Point 4]}
\define{paragraph
menu:[Title,Paragraph]
attr:[Justification LeftJustified Point 0]
attr:[FontSize PreviousFontSize Point 4]}
\define{bigger
menu:[Font,Bigger]
attr:[FontSize PreviousFontSize Point 2]}
\define{indent
menu:[Region,Indent]
attr:[LeftMargin LeftMargin Inch 32768]
attr:[RightMargin RightMargin Inch 32768]}
\define{typewriter
menu:[Font,Typewriter]
attr:[FontFace FixedFace Int Set]
attr:[FontFamily AndyType Int 0]}
\define{display
menu:[Region,Display]
attr:[LeftMargin LeftMargin Inch 32768]
attr:[RightMargin RightMargin Inch 32768]
attr:[Justification LeftJustified Point 0]}
\define{example
menu:[Region,Example]
attr:[LeftMargin LeftMargin Inch 32768]
attr:[Justification LeftJustified Point 0]
attr:[FontFace FixedFace Int Set]
attr:[FontFamily AndyType Int 0]}
\define{description
menu:[Region,Description]
attr:[LeftMargin LeftMargin Inch 32768]
attr:[Indent LeftEdge Inch -32768]}
\define{quotation
menu:[Region,Quotation]
attr:[LeftMargin LeftMargin Inch 32768]
attr:[RightMargin RightMargin Inch 32768]
attr:[FontFace Italic Int Set]}
\define{subscript
menu:[Font,Subscript]
attr:[Script PreviousScriptMovement Point 131072]
attr:[FontSize PreviousFontSize Point -2]}
\define{superscript
menu:[Font,Superscript]
attr:[Script PreviousScriptMovement Point -393216]
attr:[FontSize PreviousFontSize Point -2]}
\define{smaller
menu:[Font,Smaller]
attr:[FontSize PreviousFontSize Point -2]}
\define{heading
menu:[Title,Heading]
attr:[LeftMargin LeftMargin Inch -13107]
attr:[Justification LeftJustified Point 0]
attr:[FontFace Bold Int Set]}
\define{majorheading
menu:[Title,MajorHeading]
attr:[Justification Centered Point 0]
attr:[FontSize PreviousFontSize Point 4]}
\define{formatnote
menu:[Region,FormatNote]
attr:[Flags PassThru Int Set]}
\define{subheading
menu:[Title,Subheading]
attr:[Justification LeftJustified Point 0]
attr:[FontFace Bold Int Set]}
\define{center
menu:[Justify,Center]
attr:[Justification Centered Point 0]}
\define{flushleft
menu:[Justify,FlushLeft]
attr:[Justification LeftJustified Point 0]}
\define{flushright
menu:[Justify,FlushRight]
attr:[Justification RightJustified Point 0]}
\define{leftindent
menu:[Region,LeftIndent]
attr:[LeftMargin LeftMargin Inch 32768]}
\define{article
menu:[Title,Article]
attr:[Justification Centered Point 0]
attr:[FontSize ConstantFontSize Point 24]}
\define{subpara
menu:[Title,Subpara]
attr:[Justification LeftJustified Point 0]
attr:[FontFace Bold Int Set]}
\define{subsubpara
menu:[Title,Subsubpara]
attr:[Justification LeftJustified Point 0]
attr:[FontFace Italic Int Set]}

\subsection{Lightweight Process Package}



\paragraph{Introduction}


This document describes several packages of programs to allow multiple threads 
of control to coexist and cooperate within one Unix process.  Each such thread 
of control is referred to as a \italic{lightweight} process, in contrast to 
the traditional Unix (heavyweight) processes.  Except for the limitations of a 
fixed stack size and nonpreemptive scheduling, these lightweight processes 
possess all the properties usually associated with full fledged processes in 
typical operating systems.


The code described in this document runs entirely at user-level on a Unix 
4.2BSD system.  No kernel changes are necessary.  The packages are all based 
on the LWP package, which is a suite of lightweight process functions usable 
from a C program.  The LWP package is described first, followed by sections 
for each of the additional utilities.



\paragraph{Description}


The LWP package implements primitive functions that provide basic facilities 
to enable procedures written in C to proceed in an unsynchronized fashion. 
 These separate threads of control may effectively progress in parallel and 
more or less independently of each other.  This facility is meant to be 
general purpose with a heavy emphasis on simplicity.  Interprocess 
communication facilities can be built on top of this basic mechanism and in 
fact, many different IPC mechanisms could be implemented.  The LWP package was 
originally developed by Larry Raper  for use in implementing the SNA network 
protocol on the Sun.


In order to set up the environment needed by the lightweight process support, 
a one-time invocation of the \bold{LWP_InitializeProcessSupport} function must 
precede the use of the facilities described here.  The initialization function 
carves an initial process out of the currently executing C procedure and 
returns the process id of this initial process.  For symmetry a 
\bold{LWP_TerminateProcessSupport} function may be used explicitly to release 
any storage allocated by its initial counterpart.  If used, it must be issued 
from the process created by the \italic{LWP_InitializeProcessSupport} 
function.


When any of the lightweight process functions complete, an integer value is 
returned to indicate whether error conditions were encountered.


Macros, typedefs, and manifest constants for error codes needed by the 
lightweight process mechanism reside in the file 
\bold{/usr/andy/include/lwp.h}.  A process is identified by an object of type 
\bold{PROCESS}, which is defined in the include file.


The process model supported by the operations described here is based on a 
non-preemptive priority dispatching scheme.  (A priority is an integer in the 
range [0..LWP_MAX_PRIORITY], where 0 is the lowest priority.)  Once a given 
lightweight process is selected and dispatched, it remains in control until it 
voluntarily relinquishes its claim on the CPU.  Relinquishment may be either 
explicit (\bold{LWP_DispatchProcess}) or implicit (through the use of certain 
other LWP operations).  In general, all LWP operations that may cause a higher 
priority process to become ready for dispatching preempt the process 
requesting the service.  When this occurs, the priority dispatching mechanism 
takes over and dispatches the highest priority process automatically. 
 Services in this category (where the scheduler is guaranteed to be invoked in 
the absence of errors) are


\quotation{LWP_CreateProcess


LWP_WaitProcess


LWP_MwaitProcess


LWP_SignalProcess


LWP_DispatchProcess


LWP_DestroyProcess}


The following services are guaranteed not to cause preemption (and so may be 
issued with no fear of losing control to another lightweight process):


\quotation{LWP_InitializeProcessSupport


LWP_NoYieldSignal


LWP_CurrentProcess


LWP_ActiveProcess


LWP_StackUsed


LWP_NewRock


LWP_GetRock}


The symbol \bold{LWP_NORMAL_PRIORITY} provides a good default value to use for 
process priorities.


A global variable \bold{lwp_debug} can be set to activate or deactivate 
debugging messages tracing the flow of control within the LWP routines.  To 
activate debugging messages, set \italic{lwp_debug} to a non-zero value.  To 
deactivate, reset it to zero.  All debugging output from the LWP routines is 
sent to \italic{stdout}.


The LWP package checks for stack overflows at each context switch.  The 
 \bold{lwp_overflowAction} variable controls the action of the package when an 
overflow occurs.  If it is set to \bold{LWP_SOMESSAGE}, then LWP will print a 
message on stderr telling of the overflow and will then be quiet.  If it is 
set to \bold{LWP_SOABORT}, LWP will call the \italic{abort}() subroutine. 
 Finally, if it is set to \bold{LWP_SOQUIET}, LWP will ignore the errors.  The 
\italic{LWP_SOABORT} setting is the default.


Here is a simple example:


\example{#include "lwp.h"


static read_process(id)

    int *id;

\{

    LWP_DispatchProcess();		/* Just relinquish control for now */


    for (;;) \{

	/* Wait until there is something in the queue */

	while (empty(q)) LWP_WaitProcess(q);

	/* Process queue entry */

	LWP_DispatchProcess();

    \}

\}


static write_process()

\{

    . . .


    /* Loop & write data to queue */

    for (mesg=messages; *mesg!=0; mesg++) \{

	insert(q, *mesg);

	LWP_SignalProcess(q);

    \}

\}


main(argc, argv)

   int argc; char **argv;

\{

    PROCESS *id;


    LWP_InitializeProcessSupport(0, &id);

    /* Now create readers */

    for (i=0; i< nreaders; i++)

	LWP_CreateProcess(read_process, STACK_SIZE, 0, i, "Reader", &readers[i]);

    LWP_CreateProcess(write_process, STACK_SIZE, 1, 0, "Writer", &writer);

    /* Wait for processes to terminate */

    LWP_WaitProcess(&done);

    for (i=nreaders-1; i>=0; i--) LWP_DestroyProcess(readers[i]);

\}}


The lock package contains a number of routines and macros that allow C 
programs using LWP abstraction to place read and write locks on data 
structures shared by several lightweight processes.  Like the LWP package, the 
lock package was written with simplicity in mind; there is no protection 
inherent in the model.


In order to use the locking mechanism for an object, an object of type 
\bold{struct Lock} must be associated with the object.  After being 
initialized, with a call to \bold{LockInit}, the lock is used in invocations 
of the macros \bold{ObtainReadLock}, \bold{ObtainWriteLock}, 
\bold{ReleaseReadLock}, \bold{ReleaseWriteLock}, \bold{ObtainSharedLock}, 
\bold{ReleaseSharedLock}, and \bold{BoostSharedLock}.


The semantics of a lock is such that any number of readers may hold a lock. 
 But only a single writer (and no readers) may hold the clock at any time. 
 The lock package guarantees fairness: each reader and writer will eventually 
have a chance to obtain a given lock.  However, this fairness is only 
guaranteed if the priorities of the competing processes are identical.  Note 
that no ordering is guaranteed by the package.


Shared locks are read locks that can be boosted into write locks.  They have a 
strange locking matrix:  normal shared locks are compatible with read locks, 
incompatible with write locks, and incompatible with other shared locks.  In 
essence, holding a shared lock says that you have a read lock, but can boost 
it to a write lock without allowing other writers into the critical region. 
 Once you boosts a shared lock, it turns into a write lock.  You are 
guaranteed that when you boost a shared lock into a write lock, no other 
writers will enter the critical region before you get the write lock.


In addition, it is illegal for a process to request a particular lock more 
than once without first releasing it.  Failure to obey this restriction may 
cause deadlock.


Here is a simple example:


\example{#include "lock.h"


struct Vnode \{

    . . .

    struct Lock	lock;	/* Used to lock this vnode */

    . . .

\};


#define READ	0

#define WRITE	1


struct Vnode *get_vnode(name, how)

    char *name;

    int how;

\{

    struct Vnode *v;


    v = lookup(name);

    if (how == READ)

	ObtainReadLock(&v-> lock);

    else

	ObtainWriteLock(&v-> lock);

\}}


The IOMGR package allows light-weight processes to wait on various Unix 
events.  IOMGR_Select allows a light-weight process to wait on the same set of 
events that the Unix @b[select] call waits on.  The parameters to these 
routines are the same.  IOMGR_Select puts the caller to sleep until no user 
processes are active.  At this time the IOMGR process, which runs at the 
lowest priority, wakes up and coaleses all of the select request together.  It 
then performs a single @b[select] and wakes up all processes affected by the 
result.


The IOMGR_Signal call allows a lightweight process to wait on delivery of a 
Unix signal.  The IOMGR installs a signal handler to catch all deliveries of 
the Unix signal.  This signal handler posts information about the signal 
delivery to a global data structure.  The next time that the IOMGR process 
runs, it delivers the signal to any waiting light-weight processes.


Here is an example:


\example{void rpc2_SocketListener()

\{

    int ReadfdMask, WritefdMask, ExceptfdMask, rc;

    struct timeval *tvp;


    while(TRUE) \{

	. . .

	ExceptfdMask = ReadfdMask = (1 << rpc2_RequestSocket);

	WritefdMask = 0;

	rc = IOMGR_Select(8*sizeof(int), &ReadfdMask, &WritefdMask, &ExceptfdMask, 
tvp);


	switch(rc) \{

	    case 0:	/* timeout */

		    continue;	/* main while loop */

		    

	    case -1:	/* error */

		    SystemError("IOMGR_Select");

		    exit(-1);

		    

	    case 1:	/* packet on rpc2_RequestSocket */

		    . . . process packet . . .

		    break;


	    default:	/* should never occur */

	\}

    \}

\}}


The timer package contains a number of routines that assist in manipulating 
lists of objects of type \bold{struct TM_Elem}.  \italic{TM_Elem}s (timers) 
are assigned a timeout value by the user and inserted in a package-maintained 
list.  The time remaining to timeout for each timer is kept up to date by the 
package under user control.  There are routines to remove a timer from its 
list, to return an expired timer from a list, and to return the next timer to 
expire.


A timer is used commonly by inserting a field of type \italic{struct TM_Elem} 
into a structure.  After inserting the desired timeout value the structure is 
inserted into a list, by means of its timer field.


Here is a simple example:


\example{static struct TM_Elem *requests;


. . .


    TM_Init(&requests);        /* Initialize timer list */

    . . .

    for (;;) \{

        TM_Rescan(requests);   /* Update the timers */

        expired = TM_GetExpired(requests);

        if (expired == 0) break;

        . . . process expired element . . .

    \}}


The Fast Time package allows the caller to find out the current time of day 
without incurring the expense of a kernel call.  It works by mapping the page 
of the kernel that has the kernel's time-of-day variable and examining it 
directly.  Currently, this package only works on Suns.  You may call the 
routines on other machines, but they will run more slowly.


The initialization routine for this package is fairly expensive since it does 
a lookup of a kernel symbol via nlist().  If you have a program which runs for 
only a short time, you may wish to call \italic{FT_Init} with the 
\bold{notReally} parameter true to prevent the lookup from taking place.  This 
is useful if you are using another package that uses Fast Time.


The preemption package provides a mechanism by which control can pass between 
lightweight processes without the need for explicit calls to 
LWP_DispatchProcess.  This effect is achieved by periodically interrupting the 
normal flow of control to check if other (higher priority) procesess are ready 
to run.


The package makes use of the interval timer facilities provided by 4.2BSD and 
so will cause programs that make their own use of these facilities to 
malfunction.  In particular, use of \italic{alarm(3)} or explicit handling of 
\italic{SIGALRM} is disallowed.  Also, calls to \italic{sleep(3)} may return 
prematurely.


Care should be taken that routines are re-entrant where necessary.  In 
particular, note that \italic{stdio(3)} is not re-entrant in general, and 
hence light-weight processes performing I/O on the same FILE structure may 
function incorrectly.


Key design choices:  the package should not affect the nonpreemptive 
scheduling behavior of processes which do not use it;


It must be simple and \italic{fast}, with a minimum of extra system overhead;


It must support nested critical regions;


Processes using the package are assumed to be co-operating.


\example{#include <sys/time.h>

#include "preempt.h"


	...


	struct timeval tv;


	LWP_InitializeProcessSupport( ... );

	tv.tv_sec = 10;

	tv.tv_usec = 0;

	PRE_InitPreempt(&tv);

	PRE_PreemptMe();


	...


	PRE_BeginCritical();


	...


	PRE_EndCritical();


	...


	PRE_EndPreempt();}



\paragraph{Module hierarchy

}
This package is comprised of modules at two levels.  At the lowest level is 
the basic lightweight process package: all those routines starting with the 
preifx LWP.


Above this layer are a set of routines that only make sense in the context of 
the lightweight process package: an I/O manager package, a preemption package, 
a timer package and a fast-time of day package.  The combination of all of 
these packages gives a very powerful light-weight process facility.



\paragraph{Interface specification

}
\subpara{The lightweight process package:}


\bold{LWP_InitializeProcessSupport} (priority, pid)

int priority;

PROCESS *pid;


Initializes the LWP package.  In addition, this routine turns the current 
thread of control into the initial process with the specified priority.  The 
process id of this initial process will be returned in parameter \italic{pid}. 
This routine must be called to ensure proper initialization of the LWP 
routines.  This routine will not cause the scheduler to be invoked.  This 
function returns 0 if it succeeds, and LWP_EBADPRI if the priority is negative 
or too large.


\bold{LWP_TerminateProcessSupport}()


Terminates the LWP process support and cleans up by freeing any auxiliary 
storage used.  This routine must be called from within the procedure and 
process that invoked LWP_InitializeProcessSupport.  After 
LWP_TerminateProcessSupport has been called, LWP_InitializeProcessSupport may 
be called again to resume LWP process support.


\bold{LWP_CreateProcess} (ep, stacksize, priority, parm, name, pid)

int (*ep)();

int stacksize;

int priority;

char *parm;

char *name;

PROCESS *pid;


Used to create and mark as runnable a new light-weight process.  This routine 
will cause the scheduler to be called.  Note that the new process will begin 
execution before this call returns only if the priority of the new process is 
greater than the creating process.  \bold{Ep} is the procedure to invoke 
initially in the newly-created process.  \bold{Stacksize} is the number of 
bytes to allocate for the new process's stack.  \bold{Priority} gives the 
priority of the newly-created process.  \bold{Parm} is a parameter passed to 
the ep as its first parameter when \italic{ep} is called initially. 
 \bold{Name} is a \italic{char *} identifier used by LWP when printing 
diagnostics concerning a process.  Finally, \bold{pid} provides a place for 
LWP to place the newly-created process's identifier.  This call returns 
LWP_ENOMEM if it can not allocate all of its structures, LWP_EBADPRI if an 
illegal priority is specified, and LWP_EINIT if LWP_InitializeProcessSupport 
has not been called.


\bold{LWP_DestroyProcess}(pid)

PROCESS pid;


Destroys the specified process.  The specified process will be terminated 
immediately and its internal storage will be freed.  A process is allowed to 
destroy itself (of course, it will only get to see the return code if the 
destroy fails).  Note that a process may also destroy itself by executing a 
\italic{return} from the C routine.  This routine calls the scheduler.  This 
call returns LWP_EINIT if LWP has not been initialized.


\bold{LWP_WaitProcess} (event)

char *event;


Puts the calling process to sleep until another process does a call of 
LWP_SignalProcess or LWP_NoYieldSignal with the specified event.  Note that 
signals of events are not queued: if a signal occurs and no process is 
awakened, the signal is lost.  This routine invokes the scheduler.  This 
routine returns LWP_EINIT if LWP has not been initialized and LWP_EBADEVENT if 
it is passed a null (0) event.


\bold{LWP_MwaitProcess} (wcount, evlist)

int wcount;

char *evlist[];


Allows a process to wait for wcount signals of any of the signals in evlist. 
 Any number of signals of a particular event are only counted once.  The 
parameter evlist is a null-terminated list of events to wait for.  The 
scheduler will be invoked.  This routine returns LWP_EBADCOUNT if a bad number 
of events are waited for and LWP_EINIT if LWP has not been initialized.


\bold{LWP_SignalProcess}(event)

char *event;


Causes event to be signaled.  This will mark all processes waiting for only 
this event as runnable.  The scheduler will be invoked.  Signals are not 
queued: if no process is waiting for this event, the signal will be lost and 
LWP_ENOWAIT will be returned.  This routine returns LWP_EBADEVENT if a null 
(0) event is provided.  It returns LWP_EINIT if LWP has not been initialized.


\bold{LWP_NoYieldSignal} (event)

char *event;


Causes event to be signaled.  This will mark all processes waiting for only 
this event as runnable.  This call is identical to LWP_SignalProcess except 
that the scheduler will not be invoked; control will remain with the 
signalling process.  Signals are not queued: if no process is waiting for this 
event, the signal will be lost and LWP_ENOWAIT will be returned.  See 
LWP_SignalProcess for error return codes.


\bold{LWP_DispatchProcess} ()


Yields voluntarily to the LWP scheduler.  It returns LWP_EINIT if LWP has not 
been initialized.


\bold{LWP_CurrentProcess} (pid)

PROCESS *pid;


Places the current process id in the parameter pid.  It returns LWP_EINIT if 
LWP has not been initialized.


\bold{LWP_ActiveProcess}


A macro that yields the current process id.  If LWP_InitializeProcessSupport 
has not been called.   The invocation yields 0.  It exists because people may 
find it more convenient than LWP_CurrentProcess.


\bold{LWP_StackUsed} (pid, max, used)

PROCESS pid;

int *max;

int *used;


Returns the amount of stack space allocated to the process and the amount 
actually used by the process so far.  It works by initializing the stack to a 
special pattern at process creation time and checking to see how much of the 
pattern is still there when \bold{LWP_StackUsed} is called.  The stack of the 
process is only initialized to the special true when the process is created. 
 This variable is initially true.  If \bold{lwp_stackUseEnabled} was false at 
the time the process was created, then \bold{*used} will be set to zero and 
the routine will return LWP_NO_STACK.  LWP_NO_STACK is returned if stack stack 
counting is not enabled for this process.


\bold{LWP_NewRock} (tag, value)

int tag;

char *value;


The rock is exactly what its name implies: a place to squirrel away 
application-specific information associated with an LWP.  The Tag is any 
unique integer.  Users of the LWP package must coordinate their choice of Tag 
values.  Note that you cannot change the value associated with Tag.  To obtain 
a mutable data structure, use one level of indirection.  The error code 
LWP_EBADROCK is returned if the rock called \italic{tag} already exists.  The 
error code LWP_ENOROCKS is returned if all rocks are already in use.  No 
kidding.


\bold{LWP_GetRock} (tag, value)

int tag;

char **value;


Recovers information hidden by a LWP_NewRock call.  Returns LWP_EBADROCK if 
the rock was not defined.


\subpara{The lock package:}


\bold{LockInit} (lock)

struct Lock *lock;


Must be called to initialize a lock before it is used.  The parameter lock is 
the address of the lock to be initialized.


\bold{ObtainReadLock} (lock)

struct Lock *lock;


Obtains a read lock on the specified lock.  Note that this is a macro and not 
a routine.  Thus, results are not guaranteed if the lock argument is a 
side-effect producing expression.


\bold{ObtainWriteLock} (lock)

struct Lock *lock;


Obtains a write lock on the specified lock.  Note that this is a macro and not 
a routine.  Thus, results are not guaranteed if the lock argument is a 
side-effect producing expression.


\bold{ObtainSharedLock}(lock)

struct Lock *lock;


Obtains a shared lock on the specified lock.  Note that this is a macro, not a 
routine.  Thus the results are not guaranteed if the lock argument contains 
side-effects.


\bold{ReleaseReadLock} (lock)

struct Lock *lock;


Releases the specified lock.  This macro requires that the lock must have been 
previously read-locked.  Note that this is a macro and not a routine.  Thus, 
results are not guaranteed if the lock argument is a side-effect producing 
expression.


\bold{ReleaseWriteLock}(lock)

struct Lock *lock;


Releases the specified lock.  This macro requires that the lock must have been 
previously write-locked.  Note that this is a macro and not a routine.  Thus, 
results are not guaranteed if the lock argument is a side-effect producing 
expression.


\bold{ReleaseSharedLock}(lock)

struct Lock *lock;


Releases the specified lock.  This macro requires that the lock must have been 
previously share-locked.  Note that this is a macro and not a routine.  Thus, 
results are not guaranteed if the lock argument is a side-effect producing 
expression.  A shared lock can be released in either its boosted or unboosted 
form.


\bold{CheckLock}(lock)

struct Lock *lock;


Yields an integer that specifies the status of the indicated lock.  The value 
will be -1 if the lock is write-locked, 0 if unlocked, or a positive integer 
that indicates the numer of readers with read locks.  Note that this is a 
macro and not a routine.  Thus, results are not guaranteed if the lock 
argument is a side-effect producing expression.


\bold{BoostSharedLock}(lock)

struct Lock *lock;


Converts a boosts a shared lock into a write lock.  It is a macro and thus 
cannot be used with side-effect producing parameters.


\bold{UnboostSharedLock}(lock)

struct Lock *lock;


Converts a boosted shared lock, or a write lock into a normal shared lock.  It 
can only be called on write locks or boosted shared locks.  It is a macro and 
thus can't be used with side-effect producing parameters.


\subpara{The IOMGR package:}


\bold{IOMGR_Initialize}()


Initializes the IOMGR package.  Its main task is to create the IOMGR process, 
which runs at priority 0, the lowest priority.  The remainder of the processes 
must be running at priority 1 or greater for the IOMGR package to function 
correctly.


\bold{IOMGR_Finalize} ()


Cleans up when the IOMGR package is no longer needed.  It releases all storage 
and destroys the IOMGR process.


\bold{IOMGR_Select}(numfds, rfds, wfds, xfds, timeout)

int numfds;

int *rfds;

int *wfds;

int *xfds;

struct timeval *timeout;


Performs an LWP version of Unix \italic{select}.  The parameters have the same 
meanings as the Unix call.  However, the return value will only be -1 (an 
error occurred), 0 (a timeout occurred), or 1 (some number of file descriptors 
are ready).  If this is a polling select, it is done and IOMGR_Select returns 
to the user with the results.  Otherwise, the calling process is put to sleep. 
 If at some point the IOMGR process is the only runnable process, it will 
awaken and collect all select requests.  It will then perform a single select 
and awaken the appropriate processes.  This will cause return from the 
affected IOMGR_selects.


\bold{IOMGR_Signal}(signo, event)

int signo;

char *event;


Associates an LWP signal with a Unix signal.  When the Unix signal \bold{signo} 
is delivered to the process, the IOMGR process will deliver an LWP signal to 
the event \bold{event} via LWP_NoYieldSignal, waking any lightweight processes 
waiting on that event.  Multiple deliveries of the signal may be coalesed into 
one LWP wakeup.  The call to LWP_NoYieldSignal will happen synchronously.  It 
is safe for an LWP to check for some condition and then go to sleep waiting 
for a Unix signal without having to worry about delivery of the signal 
happening between the check and the call to LWP_WaitProcess.  This routine 
returns LWP_EBADSIG if \italic{signo} is out of range and LWP_EBADEVENT if the 
event is null.


\bold{IOMGR_CancelSignal} (signo)

int signo;


Cancels the association of a Unix signal and an LWP event.  After calling this 
function, the Unix signal \italic{signo} will be handled however it was 
handled before the corresponding call to LWP_Signal.


\bold{IOMGR_Sleep}(seconds)

unsigned seconds;


Calls IOMGR_Select with zero file descriptors and a timeout specified to wait 
\bold{seconds} seconds, then returns.  It is designed to be compatible with 
the Unix \italic{sleep(3)}.  No value is returned.


\subpara{The timer package:}


\bold{TM_Init}(list)

struct TM_Elem **list;

The specified list will be initialized so that it is an empty timer list. 
 This routine must be called before any other operations are applied to the 
list.  This routine returns 0 if it succeeds, non-zero otherwise.


\bold{TM_Final}(list)

struct TM_Elem **list;


Call this routine when you are finished with a timer list and the list is 
empty.  This routine releases any auxiliary storage associated with the list. 
 It returns 0 if and only if it succeeds.


\bold{TM_Insert}(list, elem)

struct TM_Elem *list;

struct TM_Elem *elem;


Initializes the element \italic{elem} so that the \italic{TimeLeft} field is 
equal to the \italic{TotalTime} field.  (The \italic{TimeLeft} field may be 
kept current by use of TM_Rescan.)  The element is then inserted into the 
list.


\bold{TM_Rescan}(list)

struct TM_Elem *list;


Updates the \italic{TimeLeft} fields of all timers on \italic{list}.  (This is 
done by checking the time of day clock in Unix.)  This routine returns a count 
of the number of expired timers on the list.  This is the only routine 
(besides TM_Init that updates the \italic{TimeLeft} field.


struct TM_Elem *\bold{TM_GetExpired}(list)

struct TM_Elem *list;


Searches the specified list and returns a pointer to an expired timer.  0 is 
returned if there are no expired timers.  An expired timer is one whose 
\italic{TimeLeft} field is less than or equal to 0.


struct TM_Elem *\bold{TM_GetEarliest}(list)

struct TM_Elem *list;


Returns a pointer to the timer that will be next to expire, the one with a 
smallest \italic{TimeLeft} field.  If there are no timers on the list, 0 is 
returned.


\bold{TM_eql}(t1, t2)

struct timeval *t1;

struct timeval *t2;


Returns 0 if and only if \italic{t1} and \italic{t2} are not equal.


\bold{FT_Init}(printErrors, notReally)

int printErrors;

int notReally;


Mmaps the kernel page with the time of day variable. If the routine returns 
-1, calls to FT_GetTimeOfDay will still work properly but will make a kernel 
call.  The notReally parameter tells FT_Init not to really do the 
initialization this time.


\bold{FT_GetTimeOfDay}(tv, tz)

struct timeval *tv;

struct timezone *tz;


This function has the same calling sequence as the kernel's 
\italic{gettimeofday} routine.  If the \italic{tz} parameter is not zero, or 
if initialization failed, or if the \italic{notReally} parameter in the 
initialization was true, then this routine calls \italic{gettimeofday}. 
 Otherwise, it looks in the mapped page of the kernel to get the time of day. 
 It returns 0 if and only if it succeeded.


\bold{PRE_InitPreempt}(slice)

struct timeval *slice;


Must be called to initialize the package after the call to 
LWP_InitializeProcessSupport).  It returns 0 if and only if it succeeds.


\bold{PRE_EndPreempt}()


Finalizes use of the preemption package.  No further preemptions will be made. 
 Note that it is not necessary to make this call before exit; the call is 
provided only for those applications that wish to continue after turning off 
preemption.


\bold{PRE_PreemptMe}()


Marks the current process as a candidate for preemption.  It is erroneous to 
invoke PRE_PreemptMe() if LWP_InitializeProcessSupport has not been called. 
 This macro returns 0 if and only if it succeeds.


\bold{PRE_BeginCritical}()


Places the current LWP in a Critical Section.  Upon return, involuntary 
preemptions of this process will no longer occur.  Note that this is a macro 
and that LWP_InitializeProcessSupport must have been previously invoked.


\bold{PRE_EndCritical}()


Leaves a critical section previously entered with PRE_BeginCritical().  If 
involuntary preemptions were possible before the matching PRE_BeginCritical(), 
they are once again possible. Note that this is a macro and that 
LWP_InitializeProcessSupport must have been previously invoked.

\formatnote{.bp}

\enddata{text,268755860}
