.\" format with troff or nroff using the -ms macro package
.so common.ms
.Nm RUNTIME
.TL
The SR Run-Time System Interface
.AU
Amy Morgenstern
Vicraj Thomas
Gregg Townsend
.AI
Department of Computer Science
The University of Arizona
.sp 1
October 12, 1994
.I
.\"
.\"	\*C -- for code use Courier-Bold if "psroff", else use standard bold
.ds C \\&\\fB
.if 1i=576u .ds C \\&\\f(CB
.\"
.\"	.Ss <title> -- begin subsection with italicized heading
.de Ss
.sp 1
.ne 5
.in 0
\\fI\\$1\\fP
.LP
..
.\"
.\"	.Fn <prototype> -- begin function definition
.\"	Typesets the prototype in CB, then starts an indented
.\"	paragraph for the description.
.de Fn
.sp .6
.ne 4
.in 0
.nf
\*C\\$1\fP
.fi
.IP "" 8n
..
.\"	.Cs -- start code listing
.\"	.Ce -- end code listing
.de Cs
.in 0
.nf
\*C
.sp -.6
..
.de Ce
.fi
.ft R
.sp .65
..
.\"	
.\"	--- begin text ---
.LP
The SR book (\fIThe SR Programming Language: Concurrency in Practice\fP,
by Gregory Andrews and Ronald Olsson) presents an overview of the SR
run-time system (RTS) in its Appendix E.
This document describes details of the interface to the run-time system
and is aimed at the reader who wishes to modify the system or the
generated code that calls it.
.PP
The RTS provides \fIprimitives\fP that are
used by the code generated by the SR compiler to access services provided by
the RTS.
The C files that implement these primitives may be found in the \*Crts\fP
subdirectory of the SR distribution.
.PP
Multiprocessor SR (MultiSR) uses locks to avoid interference among processes.
These locks are mentioned briefly in some of the function descriptions
and are described more completely in the appendix.
.SH
General Conventions
.LP
Identifiers beginning with an initial capital, such as
\*CArray\fP, \*COcap\fP, and \*CFunc\fP,
are the names of types defined in \*Csr.h\fP.
.PP
Several functions have an initial \*Clocn\fP parameter encoding the source
file and line number of the SR statement that generated the function call.
This information is printed in trace messages or
when an error is detected.
The decoding of a \*Clocn\fP value is done by \*Csr_fmt_locn\fP.
.PP
Several source files contain initialization functions
having names that begin with \*Csr_init_\fP.
Each is called once, before any of the other related functions.
Because these initialization functions are trivial, they are not
listed in this document.
.SH
Memory Management Primitives
.LP
The memory management primitives are used to allocate and free storage
at run time.
.Fn "char *sr_new (char *locn, int len)"
Allocates memory for a
\*Cnew(\fItype\fP)\fR statement.
This function is independent of the other allocation functions because
failure is returned to the programmer and because the region can only
be freed on explicit request.
.Fn "void sr_dispose (char *locn, Ptr addr)"
Deallocates a block of memory that was allocated by \*Csr_new\fP.
.Fn "Ptr sr_alloc (int size)"
Allocates a region of memory, by calling \*Cmalloc()\fP,
and checks for success.
The program is aborted if memory cannot be obtained.
This function is used by all other allocation functions except \*Csr_new\fP.
.Ss "Resource-owned memory"
The RTS records the ownership of certain allocated regions.
A region may be owned by one particular resource or by none.
Memory owned by a resource is freed when that resource is destroyed.
.Fn "Ptr sr_alloc_rv (int size)"
Allocates memory for a new resource instance.
This is called by resource initialization code immediately after entry.
.Fn "Ptr sr_alc (int size, int need_rmutex)"
Allocates a region of contiguous memory and remembers which resource,
if any, is to be considered its owner.
If \*Csize\fP is positive, the current resource becomes the owner;
if it is negative, no resource is associated with the region.
The parameter \*Cneed_res_mutex\fP is true unless the resource lock
is already held.
.Fn "String *sr_alc_string (int maxlength)"
Allocates a string and initializes its header.
Ownership is set to the current resource.
.Fn "void sr_free (Ptr addr)"
Frees a region previously allocated by \*Csr_alc\fP or \*Csr_alc_string\fP.
Used when not holding the resource lock.
.Fn "void sr_locked_free (Ptr addr)"
Frees a region previously allocated by \*Csr_alc\fP or \*Csr_alc_string\fP.
Used when the caller already holds the resource lock.
.Fn "void sr_res_free (Rinst r)"
Frees all memory owned by the resource \*Cr\fP.
.Ss "Memory Pool Primitives"
Some data structures are grouped into \fIpools\fP.
A pool is a set of memory regions of a particular type.
Regions are allocated and freed using the functions below;
freed memory remains in the pool for reuse.
Pool memory is not owned by any resource.
.LP
The pool routines themselves use no externally visible locks;
however, they may call user routines that use such locks.
.Fn "Pool sr_makepool (char *name, int size, int max, Func init, Func re_init)"
Initializes a pool of descriptors.
Parameter \*Cname\fP is used in error messages.
Each descriptor is of size \*Csize\fP;
a maximum of \*Cmax\fP descriptors are allowed.
Function \*Cinit\fP is called when a pool element needs to be initialized
for its first use;
function \*Cre_init\fP is called upon destruction to prepare the element
for later reuse.
Either function parameter may be null if no function is needed.
.Fn "Ptr sr_addpool (Pool p)"
Allocates a new descriptor from pool \*Cp\fP and returns a pointer to it.
.Fn "void sr_delpool (Pool p, Ptr el, int have_mutex)"
Returns element \*Cel\fP to pool \*Cp\fP.
Parameter \*Chave_mutex\fP is true if the lock \*Cpl->pmutex\fP
is already held.
.Fn "void sr_eachpool (Pool p, Func f)"
Calls the function \*Cf\fP once for each currently allocated member of
pool \*Cp\fP.
The single argument passed to function \*Cf\fP is a pointer to a descriptor.
Function \*Cf\fP must not allocate or deallocate items from pool \*Cp\fP.
.SH
Resource Management Primitives
.LP
The resource management primitives are used to create and destroy resources
and to inform the RTS when the initial or final code has been executed.
There are three major data structures associated with these primitives:
the operation capability (\*COcap\fP),
the resource capability (\*CRcap\fP)
and the creation request block (\*CCRB\fP).
The \*CCRB\fP includes a packet header used for remote creation;
the only field of the packet header
that is used by the generated code is the \*Csize\fP field.
These data structures are defined in \*Csr.h\fP.
.Fn "Ptr sr_create_resource (char *locn, int rpat, Vcap vm, CRB c, int rsize)"
Called by the generated code to create a new resource instance.
\*Crp\fP is the resource pattern number,
\*Cv\fP is the target virtual machine,
\*Cc\fP is the address of the creation request block,
and \*Crsize\fP is the size of the resource capability.
The parameters are placed in the CRB and \*Csr_create_res\fP is called.
.Fn "void sr_create_res (CRB *crbp)"
Actually creates a new resource instance.
Various data structures are created or updated
and a process is spawned to execute the initialization code.
The caller blocks until the initialization code completes or replies.
A pointer to the new resource capability is returned.
.Fn "void sr_create_global (char *locn, int rpatid)"
Creates a new instance of a global in a manner similar to resource creation.
If the global is already running, the call is ignored.
.Fn "void sr_destroy (char *locn, Rcap rcp, int have_rid_mutex)"
Destroys the resource \*Crcp\fP.
A process is created to execute the final code of the resource.
The current process blocks until the final code is executed.
All memory owned by the resource
is freed and all processes executing in the resource are killed.
The primitive does not return if called from the resource being
destroyed; in this case, the calling process is killed.
The argument \*Chave_rid_mutex\fP
is true if the caller holds the lock for \*Cres_pool->pmutex\fP.
.Fn "void sr_dest_all ()"
Destroys all the resource instances, but not the globals,
on the current machine.
.Fn "void sr_destroy_globals ()"
Destroys all the globals on the current virtual machine
in a hierarchical order based on what other globals they import.
.Fn "void sr_finished_init ()"
Signals that the resource initialization code has completed.
The resource creator is awakened if it was not awakened earlier by a reply.
This primitive does not return; instead, the calling process is killed.
.Fn "void sr_finished_final ()"
Signals that the resource final code has completed.
The destroying process is awakened.
This primitive does not return; instead, the calling process is killed.
.SH
Process Management and Scheduling Primitives
.LP
This section describes the primitives that
create, destroy and schedule processes.
.Fn "void sr_init_proc (Func start_code)"
Initializes the process management system.
The free list of process descriptors is set up.
The job servers are created.
The calling process is killed and execution continues by calling
\*Cstart_code\fP in a new SR process context.
.Fn "Proc sr_spawn (Func pc, int pri, Rinst r, int have_lock, a1, a2, a3, a4)"
Creates a new process that will begin by calling
\*Cpc(a1,a2,a3,a4)\fP.
A new process descriptor is allocated and initialized.
Stack space is allocated and set up for process initiation.
The process is added to the list for the specified resource,
but not placed on the ready list.
Parameter \*Chave_lock\fP is true if the caller holds the resource lock.
.Fn "void sr_activate (Proc pr)"
Places a process \*Cpr\fP created by \*Csr_spawn\fP on the ready list.
.Fn "void sr_kill (Proc pr, Rinst res_mutex_held)"
Kills an SR process.
The parameter \*Cres_mutex_held\fP points to \*Cpr->res\fP
if the caller holds the lock \*Cpr->res->mutex\fP
and is null otherwise.
.Fn "void sr_scheduler ()"
Requests a context switch to the next eligible process.
The caller must hold the lock \*Csr_queue_mutex\fP.
Before calling \*Csr_scheduler\fP, the caller must requeue
its own process on the appropriate queue.
.Fn "void sr_loop_resched (char *locn)"
Reschedules the current process to let another process execute.
It checks to see if any napping or I/O-blocked jobs can be awakened.
It is called by the generated code every time \*Csr_max_loops\fP
loop iterations have occurred.
.Fn "void sr_reschedule (Proc pr)"
Reschedules process \*Cpr\fP on the appropriate ready or idle list.
The caller must hold the lock \*Csr_queue_mutex\fP.
.Fn "void sr_setpri (int newpri)"
Sets the priority of the current process to \*Cnewpri\fP.
If this is a decrease in priority,
a context switch to another process may result.
.SH
Remote Request Processing Primitives
.LP
The following primitives service requests for a remote machine.
.Fn "Pach sr_remote (Vcap dest, enum ms_type type, Pach ph, int size)"
Passes a message of type \*Ctype\fP for execution on
virtual machine \*Cdest\fP,
waits for the reply,
and returns a pointer to that reply.
Parameters \*Cdest\fP, \*Ctype\fP, and \*Csize\fP,
plus the current VM and priority, are stored in the
message's packet header \*Cph\fP before sending the message.
.LP
.Cs
void sr_rmt_callme (Pach ph)
void sr_rmt_create (Pach ph)
void sr_rmt_destroy (Pach ph)
void sr_rmt_destop (Pach ph)
void sr_rmt_destvm (Pach ph)
void sr_rmt_invk (Pach ph)
void sr_rmt_query (Pach ph)
void sr_rmt_receive (Pach ph)
.Ce
.in 8n
Each of these processes a particular type of request from a remote VM
and then sends back an acknowledgement.
.in 0
.Fn "void sr_rcv_call (Pach ph)"
Processes a \*Ccall\fP invocation that was returned in response to a
remote receive request.
The packet is in the form of an invocation block,
which is then passed to the original receiver.
When a reply is sent to the invocation,
it is caught here and passed back to the invoking machine.
.LP
.Cs
void sr_net_start (char abuf[])
void sr_net_connect (int n, char *address)
Bool sr_net_known (int n)
void sr_net_more (Pach ph)
enum ms_type sr_net_recv (Pach ph)
void sr_net_send (int dest, enum ms_type type, Pach ph, int size)
.Ce
.in 8n
These primitives service network requests.
.in 0
.SH
RTS Support for Synchronization Primitives
.LP
This section describes the RTS primitives required by SR's
synchronization statements.
.Ss Invocations
All invocations are made using the \*Csr_invoke\fP
primitive.
The generated code provides an invocation block that describes the invocation.
.Fn "Ptr sr_invoke (char *locn, invb ibp)"
Invokes an operation.
The caller must initialize the \*Csize\fP,
\*Copc\fP, and \*Ctype\fP fields of the invocation block \*Cibp\fP.
The arguments for the invocation are located
immediately beyond the fixed portion of \*Cibp\fP,
and the return values will be returned in this same area.
A pointer to the invocation block is returned;
the block may have been moved if it called an operation on a remote machine.
.Fn "invb sr_reply (char *locn, invb ibp)"
Sends an early reply to the invoker of an operation.
A copy of the invocation block is retained by the current process
and the original is returned to the invoker.
A reply in the initialization code of a resource
is treated very much like an \*Csr_finished_init\fP:
the creator process is awakened but the current process is not killed.
(The compiler ignores reply statements in a final block.)
The address of the new copy of the invocation block is returned.
.Fn "Ptr sr_forward (char *locn, Invb obp, Invb ibp)"
Forwards an argument list and responsibility for a reply
to another operation.
The packet header of the old invocation block, \*Cobp\fP,
is copied into the packet header of a new invocation block, \*Cibp\fP.
A new process is spawned to execute the operation specified in \*Cibp\fP.
.Fn "void sr_make_proc (Ocap *ocap, enum op_type type, Func ept)"
Adds a new resource proc operation.
Called during resource initialization.
.Fn "void sr_kill_resops (Rinst res)"
Kills all operations of resource \*Cres\fP.
Any pending input invocations are purged.
This is called by \*Csr_destroy\fP.
.Fn "void sr_finished_proc (invb ibp)"
Called by the generated code when a \*Cproc\fP operation has finished.
If the operation was called, the invoker is notified.
This primitive does not return; instead, the current process is killed.
.Ss "The Concurrent Invocation Statement"
This section describes the commands that are used to execute the \*Cco\fP
statement.
.Fn "void sr_co_start (char *locn)"
Creates a \*Cco\fP block for the start of the \*Cco\fP statement.
The new block is linked to the current process.
.Fn "Ptr sr_co_wait (char *locn)"
Blocks until an arm of a \*Cco\fP
terminates and returns a pointer to the
invocation block used in the original invocation.
The generated code can use the invocation block to find out
which arm of the \*Cco\fP terminated.
To be able to do this, the generated code sets the
\*Cco.arm_num\fP field in each invocation block
before making the invocations inside the \*Cco\fP.
A pointer to the original invocation block is returned so that
the generated code can copy result parameters and find out
which arm terminated.
\*CNULL\fP is returned after all arms of the \*Cco\fP have terminated.
.Fn "void sr_co_call (Invb ibp)"
Handles a call within a \*Cco\fP statement.
.Fn "void sr_co_call_done (Invb ibp)"
Signals that a call invocation from a \*Cco\fP statement has returned.
If the invoker is still interested in the event, it is notified.
.Fn "void sr_co_send (Invb ibp)"
Handles a send within a \*Cco\fP statement.
The invocation block is copied and returned to the invoker.
.Fn "void sr_co_end (char *locn)"
Indicates the end of a \*Cco\fP statement.
The \*Cco\fP block is freed.
.Ss "The Input Statement"
An important concept while dealing with the input statement is that of a
.I class.
The compiler groups operations in an input statement into a class.
A class is the transitive closure of the relation
``serviced by the same input statement.''
The generated code, however, does not have to concern itself with the
structure of a class, and as far as it is concerned, a
pointer to a class is just a character pointer.
.Fn "Ptr sr_make_class ()"
Makes a new operation class and returns a pointer to it.
.Fn "Ptr sr_make_semop (char *locn)"
Creates an operation implemented by a semaphore and returns a pointer to it.
.Fn "void sr_init_semop (char *locn, Ptr sems, Ptr initvals, int ndim)"
Initializes an unoptimized semaphore or array of semaphores
by issuing a series of send operations.
.Fn "Ocap sr_new_op (char *locn, Class clap)"
Creates and returns a single new dynamic operation for \*Cnew(op...)\fP.
.Fn "void sr_make_inops (Ptr addr, Class clap, int ndim, int type)"
Creates one or more input operations and stores their capabilities at
\*Caddr\fP.
The parameter \*Cndim\fP gives the number of dimensions for an array of ops
or is zero for a simple op;
\*Ctype\fP is either \*CINPUT_OP\fP or \*CDYNAMIC_OP\fP.
.ne 6
.LP
.Cs
void sr_dest_op (char *locn, Ocap opc)
void sr_dest_array (char *locn, Ptr addr)
.Ce
.in 8n
Destroys a single dynamic operation or an array of them.
.in 0
.Fn "void sr_kill_inops (Ptr addr, int ndim)"
Removes local operations from the operation table
and purges any pending invocations.
As with the preceding function, \*Cndim\fP gives the dimensionality
of an operation array.
.Fn "void sr_iaccess (Class clap, Bool else_present)"
Reserves access to an input operation class
for a sequence of calls to \*Csr_get_anyinv\fP, \*Csr_get_myinv\fP,
or \*Csr_chk_myinv\fP.
Exclusive access is lost when the any of those calls block the process
or when the process calls \*Csr_rm_iop\fP.
The calling process blocks if another process already has access to the class.
Parameter \*Celse_present\fP
is true if the input statement has an \*Celse\fP
clause and is false otherwise.
.IP
When an input statement has a synchronization statement,
the generated code reserves the class and then iterates through
the queue until it finds an acceptable invocation,
which it then accepts by calling \*Csr_rm_iop\fP.
Parameter values in the invocation blocks can be used in the
evaluation of the synchronization expression.
.IP
When the input statement has a scheduling expression, the generated code
inspects all the pending invocations and evaluates the scheduling expression
for each.
Again, the parameter values can be used.
.Fn "invb sr_get_anyinv (char *locn, Class clap)"
Returns a pointer to the next uninspected invocation block
of operation class \*Cclap\fP.
The process must have previously reserved the class 
by calling \*Csr_iaccess\fP.
If the class is empty and the \*Csr_iaccess\fP call specified no
\*Celse\fP clause, the process blocks until an invocation appears.
If the class is empty and there is an \*Celse\fP clause, a null is returned.
.Fn "invb sr_chk_myinv (Ocap opc)"
Returns a pointer to the next uninspected invocation of operation \*Copc\fP,
leaving the invocation in the queue.
The process must have previously reserved the operation's class 
by calling \*Csr_iaccess\fP.
If no invocation is found, a null pointer is returned.
.Fn "Bool sr_cap_ck (char *locn, Ptr oentry, Ocap opc)"
Checks whether the operation entry \*Coentry\fP matches the capability
\*Copc\fP given in an input statement, and returns \*CTRUE\fP if so.
.Fn "void sr_rm_iop (char *locn, char *cp, Invb ibp)"
Removes an invocation block from a class queue and
releases access to the class.
If \*Cibp\fP is null, access is released but no operation is dequeued.
.Fn "void sr_finished_input (char *locn, Invb ibp)"
Signals the exit from the body of an input statement.
The invocation block is freed if the block if it is no longer needed.
.Fn "Ptr sr_receive (char *locn, Ocap opc, Bool else_present)"
Unconditionally dequeues the next invocation from an operation class
and returns a pointer to its invocation block.
If no invocation is available and an \*Celse\fP clause is present,
a null pointer is returned; otherwise, the process blocks.
\*Csr_receive\fP combines the functions of \*Csr_iaccess\fP,
\*Csr_get_anyinv\fP, \*Csr_cap_ck\fP, and \*Csr_rm_iop\fP,
and is additionally the only entry point providing for
input from a remote machine.
.Fn "int sr_query_iop (char *locn, Ocap *opc)"
Returns the pending invocation count for an input operation.
This implements the \*C?\fP operator.
.SH
Semaphore Primitives
.LP
Semaphores are really pointers to structures, but as far as the
generated code is concerned they are just pointers to characters.
.Fn "Ptr sr_make_sem (int init_val)"
Creates a semaphore with a specified initial value and returns a pointer to it.
.Fn "void sr_kill_sem (Sem sp)"
Destroys a semaphore.
.Fn "void sr_P (char *locn, Sem sp)"
Does a P on semaphore \*Csp\fP.
.Fn "void sr_V (char *locn, Sem sp)"
Does a V on semaphore \*Csp\fP.
.SH
Input/Output Primitives
.LP
This section describes primitives that do input and output.
.Fn "File sr_open (char *fname, int mode)"
Opens the file named by \*Cfname\fP.
Files can be opened in one of three modes:
\*CREAD\fP (0), \*CWRITE\fP (1), or \*CREADWRITE\fP (2).
A file pointer is returned on a successful open;
\*CNULL\fP is returned if the open fails.
.Fn "void sr_flush (char *locn, File fp)"
Flushes the buffers of the file \*Cfp\fP.
The file remains open.
.Fn "void sr_close (char *locn, File fp)"
Closes the file \*Cfp\fP.
.Fn "int sr_read (char *locn, File fp, char *at, arg1, ...)"
Reads zero or more variables from file \*Cfp\fP,
returning the number of items read.
Argument \*Cat\fP gives the type and number of the arguments that follow.
If no items are read and EOF is encountered, \*CEOF\fP is returned.
.Fn "void sr_printf (char *locn, File fp, String sp, String fmt, char *at, ...)"
Generates output for any of the predefined functions
\*Cprintf\fP, \*Csprintf\fP, \*Cwrite\fP, or \*Cput\fP.
Either \*Cfp\fP, a file pointer, or \*Csp\fP, a string pointer,
is null to select printf or sprintf behavior.
The argument \*Cat\fP gives the type and number of the arguments that follow.
.Fn "int sr_scanf (char *locn, File fp, String sp, String fmt, char *at, ...)"
Reads formatted input from the file \*Cfp\fP or the string \*Csp\fP,
whichever is not null.
Argument \*Cat\fP gives the type and number of the arguments that follow.
The function \*Csr_scanf\fP returns the number of items read.
If no items are read and EOF is encountered, \*CEOF\fP is returned.
.Fn "int sr_get_string (char *locn, File fp, String *s)"
Reads a string value for \*Cget(s)\fP.
The number of characters read is returned.
.Fn "int sr_get_carray (char *locn, File fp, String *s)"
Reads a character array for \*Cget(a)\fP.
The number of characters read is returned.
.Fn "int sr_seek (char *locn, File fp, int seektype, int offset)"
Moves the file pointer to be \*Coffset\fP bytes from the
beginning, current position, or end of the file \*Cfp\fP,
depending on whether \*Cseektype\fP is
\*CABSOLUTE\fP (0), \*CRELATIVE\fP (1), or \*CEXTEND\fP (2), respectively.
The new offset relative to the beginning of the file is returned.
.Fn "int sr_where (char *locn, File fp)"
Returns the current position in the file \*Cfp\fP
relative to the beginning of the file.
.Fn "Bool sr_remove (char *fname)"
Removes the file given by \*Cfname\fP.
Returns true if successful.
.SH
Primitives dealing with Virtual Machines
.LP
This section describes primitives that manipulate virtual machines.
The first call to any of these on the main virtual machine
initiates execution of
.B srx ,
the central VM coordinator, in a separate Unix process.
All of these routines function by sending their parameters to
.B srx
for processing.
.Fn "void sr_locate (char *locn, int n, String *host, String *exe)"
Implements the \*Clocate\fP statement.
.Fn "Vcap sr_crevm (char *locn, int physm)"
Creates a new virtual machine on physical machine \*Cphysm\fP,
returning a VM capability.
.Fn "Vcap sr_crevm_name (char *locn, String *host)"
Creates a new virtual machine on the computer named \*Chost\fP,
returning a VM capability.
.Fn "void sr_destvm (char *locn, int vm)"
Destroys the virtual machine \*Cvm\fP.
.SH
Clock Functions
.LP
These functions deal with the system clock.
.Fn "int sr_age ()"
Returns the age in milliseconds (elapsed time during execution)
of the current virtual machine.
.Fn "void sr_nap (char *locn, int msec)"
Delays the calling process for \*Cmsec\fP milliseconds.
If \*Cmsec\fP is nonpositive, the caller is rescheduled with no delay
behind any other ready processes of the same priority.
.SH
Termination Processes
.LP
These functions are called to end a program in various ways.
.Fn "void sr_stop (int exitcode, int report_blocked)"
Terminates the execution of the SR program.
Output streams of all VMs are flushed and the VMs are terminated.
The VMs exit with the specified exit code.
.Fn "void sr_abort (char *msg)"
Prints an fatal error message and aborts the program.
.Fn "void sr_net_abort (char *s)"
Identical to \*Csr_abort\fP but called by the network routines.
.Fn "void sr_loc_abort (char *locn, char *msg)"
Aborts the program giving source line information.
.Fn "void sr_malf (char *msg)"
Aborts the program indicating a run-time malfunction.
Only called in ``cannot happen'' situations.
.Fn "void sr_message (char *label, char *msg)"
Prints a run-time message preceded by a label such as \*C"warning"\fP.
.Fn "int sr_runerr (locn, errno, args ... )"
Aborts the program giving source line information and a
message selected by the index \*Cerrno\fP from the list in \*Crunerr.h\fP.
Additional arguments may be inserted in the message \fIa la\fP printf.
.Cs
void sr_stk_corrupted ()
void sr_stk_overflow ()
void sr_stk_underflow ()
.Ce
.in 8n
Issues an error message and aborts the program due to a problem
detected by the context switch routines.
.in 0
.SH
Conversion Functions
.LP
The following functions convert an SR string to the requested type,
returning the converted value:
.Cs
int     sr_boolval (int locn, String *s)
int     sr_charval (String *s)
int     sr_intval (int locn, String *S)
Ptr     sr_ptrval (int locn, String *S)
Real    sr_realval (int locn, String *s)
Array*  sr_chars (String *s)
.Ce
.LP
The following functions convert a C string to boolean or integer,
returning success or failure:
.Cs
int     sr_cvbool (char *sp, Bool *bp)
int     sr_cvint (char *sp, int *ip)
.Ce
.LP
The following functions each convert a particular type to an SR string,
returning a pointer to a newly allocated string:
.Cs
Ptr     sr_fmt_arr (Array *a)
Ptr     sr_fmt_bool (Bool b)
Ptr     sr_fmt_char (Char c)
Ptr     sr_fmt_int (int n)
Ptr     sr_fmt_ptr (Ptr p)
Ptr     sr_fmt_real (Real r)
.Ce
.LP
The following functions implement the \*Cgetarg\fP predefined function.
Each returns 1 if successful, 0 if the conversion fails, or
\*CEOF\fP if \*Cn\fP is out of range.
.Cs
int     sr_arg_bool (int n, Bool *p)
int     sr_arg_carray (int n, Array *a)
int     sr_arg_char (int n, Char *p)
int     sr_arg_int (int n, Int *p)
int     sr_arg_ptr (int n, Ptr *p)
int     sr_arg_real (int n, Real *p)
int     sr_arg_string (int n, String *s)
.Ce
.SH
Miscellaneous Utilities
.LP
Many functions are so small and straightforward that no detailed
description is needed.
.Ss "Math Functions"
These functions implement some arithmetic operations and predefined functions.
(Most arithmetic operations require no run-time functions;
most predefined math functions are implemented by direct calls to the
C library.)
.ta 60n
.de Cf
\\*C\\$1\\fP	\\fI\\$2\\fP
..
.Cs
.Cf "int   sr_imin (int nargs, int v, ...)" "integer minimum"
.Cf "int   sr_imax (int nargs, int v, ...)" "integer maximum"
.Cf "int   sr_rmin (int nargs, Real v, ...)" "real minimum"
.Cf "int   sr_rmax (int nargs, Real v, ...)" "real maximum"
.sp .6
.Cf "Real  sr_rtor (char *locn, Real x, Real y)" "real \*C**\fP real"
.Cf "Real  sr_rtoi (char *locn, Real x, int y)" "real \*C**\fP int"
.Cf "int   sr_itoi (char *locn, int x, int y)" "int \*C**\fP int"
.sp .6
.Cf "Real  sr_round (char *locn, Real x)" "\*Cround(\fPreal\*C)\fP"
.Cf "Real  sr_rmod (char *locn, Real x, Real y)" "real \*Cmod\fP real"
.Cf "Real  sr_imod (char *locn, int x, int y)" "int \*Cmod\fP int"
.sp .6
.Cf "void  sr_seed (Real x)" "\*Cseed(\fPx\*C)\fP"
.Cf "Real  sr_random (Real x, Real y)" "\*Crandom(\fPx,y\*C)\fP"
.Ce
.Ss "String Functions"
These functions implement string comparison, concatenation, slicing,
slice assignment, and swapping.
.Cs
int     sr_strcmp (String *l, String *r)
Ptr     sr_cat (char *addr1, int len1, ... , NULL, 0)
Ptr     sr_sslice (char *locn, String s, int i, int j)
String* sr_chgstr (char *locn, String *s, int i, int j, String *v)
String* sr_sswap (char *locn, String *lside, String *rside)
.Ce
.Ss "Array Functions"
These functions implement several operations involving arrays.
.Cs
Array*  sr_acopy (char *locn, Array *dest, Array *src)
int     sr_acount (Array *a)
Ptr     sr_astring (Array *a)
Array*  sr_aswap (char *locn, Array *lside, Array *rside)
Ptr     sr_clone (char *locn, Ptr addr, int len, int n)
Array*  sr_init_array (locn, addr, esize, initv, ndim, lb1, ub1, ...)
Ptr     sr_slice (locn, a1, a2, esize, nbounds, lb1, ub1, ...)
Array*  sr_strarr (char *locn, Array *dest, int lb, int ub, Array *src)
.Ce
.Ss "Tracing and Debugging Functions"
These functions trace significant events and assist in debugging the
run-time system.
.Cs
int   sr_trace (char *action, char *locn, Ptr addr)
int   sr_bugout (char *f, int v1, int v2, int v3, int v4, int v5)
void  sr_debug (char *fmt, inv v1, int v2, int v3)
int   sr_get_debug ()
void  sr_set_debug (int n)
.Ce
.Ss "Context Switch Functions"
The following system-dependent functions implement SR's underlying
lightweight threads package.
They are described in detail in
.I "Porting the SR Programming Language" .
The actual code is located in the \*Ccsw\fP directory.
.Cs
void  sr_build_context ()
void  sr_chg_context ()
void  sr_chk_stack ()
.Ce
.Ss "MultiSR Functions"
The following system-dependent functions support MultiSR.
They are also described in
.I "Porting the SR Programming Language" .
The actual code is located in the \*Cmulti\fP directory.
.Cs
void  sr_init_multiSR ()
void  sr_jobserver_first ()
void  sr_create_jobservers (Func code, int n )
.Ce
.SH
References
.LP
Gregory R. Andrews and Ronald A. Olsson,
.I "The SR Programming Language:  Concurrency in Practice"
Benjamin/Cummings, Redwood City, CA, 1993.
.LP
G.R. Andrews, R.A. Olsson, M.A. Coffin, M. Elshoff, I. Nilsen, T. Purdin,
and G. Townsend,
.I "An Overview of the SR Language and Implementation."
ACM Transactions on Programming
Languages and Systems, vol. 10, no. 1, Jan. 1988, pp. 51-86.
.LP
Gregg M. Townsend and Dave Bakken,
.I "Porting the SR Programming Language."
Department of Computer Science, The University of Arizona, 1993.
Distributed with the SR system.
.bp
.ce 99
.sp 2
.B "Appendix:  Lock Usage"
.sp .4
.I "Dave Bakken"
.ce 0
.sp 2
.LP
Multiprocessor SR (MultiSR) requires several locks for proper synchronization.
This appendix describes the purpose of each lock
and the relationships of the locks to each other.
.PP
The defined type \*CMutex\fP is used to declare a lock;
\*CMutex\fP variables are accessed only through the macros \*CINIT_LOCK\fP,
\*CLOCK\fP, and \*CUNLOCK\fP.
In uniprocessor versions of SR these macros have no effect.
.PP
Code that concurrently reserves multiple locks
must follow nesting rules to avoid deadlock.
Interdependencies with other locks are identified for each lock.
A linear ordering reflecting these interdependencies
appears at the end of the appendix.
Terms such as ``first'' and ``last'' refer to the order of acquisition.
.PP
SR assumes machine-word atomicity.
Locks are not used to protect variables that are a single word,
such as the global \*Cmsclock\fP or the individual elements of the
array \*Cfp_table\fP.
.Ss "Individual Locks"
.LP
Locks indicated with \*C->\fP as part of the name are components of structures.
Locks whose names begin with \*Csr_\fP are global.
Other locks are local to a single source file.
The defining file name is indicated for each lock.
.Fn "cob_st->cobmutex [oper.h]"
This lock protects all the elements of a concurrent statement block structure
\*Ccob_st\fP.
The lock is nested once, in \*Csr_co_end\fP,
and is acquired after \*Ccob_pool->pmutex\fP.
In \*Csr_co_wait\fP, if the \*Cco\fP block has not terminated, the lock
is released until the \*Cco\fP statement has terminated.
\*Ccobmutex\fP is then re-acquired.
.Fn "mem_mutex [alloc.c]"
This lock protects \*Call_mem\fP, the linked list of owned memory regions.
This lock is taken after the appropriate \*Cres->rmutex\fP
has been acquired.
.Fn "sr_exec_up_mutex [globals.h]"
This lock protects \*Csr_exec_up\fP,
the variable that tells if \fBsrx\fP has been started.
It is not nested.
.Fn "alloc_mutex [misc.c]"
This lock protects the variables \*Clow_alloc\fP and \*Chigh_alloc\fP,
which are used by RTS Primitives \*Csr_new\fP and \*Csr_dispose\fP.
It is not nested.
.Fn "class_pool->pmutex [oper.c]"
This lock protects the memory allocation pools.
It is not nested.
.Fn "class_st->clmutex [oper.h]"
This lock protects a class structure.
Except for
.hy 0
\*Crmutex\fP, \*Cres_pool->pmutex\fP,
and \*Csr_main_res_mutex\fP,
.hy 1
it is obtained before all other locks.
.Fn "cob_pool->pmutex [co.c]"
This lock protects the memory allocation pool for the \*Cco\fP statement.
The only nesting for this lock is in \*Csr_co_end()\fP,
where it is acquired before \*Ccobp->cobmutex\fP.
.Fn "cre_mutex [vm.c]"
This protects \*Cnum_crevm_name\fP,
which assigns a unique serial number for each VM
created using a text string (instead of a machine number).
It is never held while another lock is acquired.
.Fn "currfd_mutex [socket.c]"
This protects \*Ccurrfd\fP, the current file that \*Csr_net_recv\fP
is checking.
It is never held while acquiring another lock.
.Fn "send_mutex [socket.c]"
Large messages sent to other virtual machines may be broken into parts.
This lock ensures that the parts
are sent consecutively with no other messages interspersed.
\*Csend_mutex\fP also protects the outgoing message counters.
It is not nested.
.Fn "debug_mutex [debug.c]"
This synchronizes debug outputs and is acquired and freed
(indirectly) inside the \*CDEBUG\fP macro.
This lock is always acquired last.
.Fn "final_mutex [main.c]"
This protects \*Cfinals_started\fP and \*Cshutdown_started\fP
to ensure that finalization and shutdown are done no more than once.
It is always acquired last.
.Fn "maxfd_mutex [socket.c]"
This protects the variable \*Cmaxfd\fP, the highest file descriptor
checked by \*Csr_net_recv\fP.
It is acquired after \*Cwait_ready_set_mutex\fP
and is never held while another lock is acquired.
.Fn "mfd_fdm_mutex [socket.c]"
This lock protects the variables that maintain mappings
between machines and file descriptors,
\*Cmfd[n]\fP and \*Cfdm[n]\fP.
It is nested inside \*Cwait_ready_set_mutex\fP
and is never held when another lock is acquired.
.Fn "oper_st->omutex [oper.h]"
This protects an operation table entry.
The lock is acquired before \*Csr_queue_mutex\fP but after \*Cclmutex\fP
and \*Crmutex\fP.
The most complex nesting occurs in \*Csr_kill_resops\fP.
It acquires \*Crmutex\fP, \*Cclmutex\fP, and \*Comutex\fP.
Then it calls \*Csr_kill_sem\fP, which acquires
\*Csr_queue_mutex\fP and \*Csem_pool->pmutex\fP.
.Fn "oper_pool->pmutex [oper.c]"
This lock protects the run-time operation pool.
It is not nested.
.Fn "proc_pool->pmutex [pool.c]"
This lock is used to protect the process memory allocation pool.
It must be acquired after \*Csr_queue_mutex\fP.
A given proc will
either be on a protected queue or be served by only one job server,
so simultaneous access is not possible.
.Fn "random_mutex [math.c]"
This protects the variables used by \*Csr_random\fP.
It is not nested.
.Fn "remote_mutex [remote.c]"
This lock protects the arrays
\*Cstarted[MAX_VM]\fP and \*Cwaiting[MAX_VM]\fP
used in function \*Ccontact\fP.
It is acquired before the queue mutex.
.Fn "res_pool->pmutex [res.c]"
This lock protects the resource memory allocation pool.
The only nesting is with \*Crmutex\fP in the function \*Csr_dest_all\fP,
and here \*Cres_pool->pmutex\fP is acquired
.I first .
Function \*Csr_dest_all\fP is called during VM
destruction, and it must hold \*Cres_pool->pmutex\fP
the entire time so no other resources can be created.
.Fn "rin_st->rmutex [res.h]"
This protects a resource instance descriptor.
Only the locks \*Cres_pool->pmutex\fP and \*Csr_main_res_mutex\fP
are acquired earlier.
.Fn "sem_pool->pmutex [semaphore.c]"
This lock protects the semaphore memory allocation pool.
It is never held when another lock is acquired.
.Fn "sr_main_res_mutex [globals.h]"
This protects \*Csr_main_res\fP, which is the capability
for the main resource.
It is interlocked only with \*Crmutex\fP, and is acquired first.
.Fn "sr_queue_mutex [globals.h]"
This protects the I/O list, the nap list, and all queues.
It interacts with a number of locks but is acquired
before all others except \*Cclmutex\fP, \*Crmutex\fP,
and \*Comutex\fP.
Some functions that need the lock do not know whether it is already held.
To handle this situation, the macros \*CLOCK_QUEUE\fP and \*CUNLOCK_QUEUE\fP
are used in nested pairs to access it.
The first call to \*CLOCK_QUEUE\fP acquires the lock
and subsequent calls do nothing but increment a private counter.
Calls to  \*CUNLOCK_QUEUE\fP just decrement the counter;
when it reaches zero, the lock is released.
Except for \*Csr_scheduler\fP, 
which requires that its caller lock the queue,
the pairs are contained in the same function.
.Fn "sr_fd_lock[n] [globals.h]"
This array of locks protects files.
It is indexed by file descriptor.
Only one file lock is held at any time.
Except for \*Cdebug_mutex\fP, file locks acquired last.
.Fn "proc_st->stack_mutex [sr.h]"
This protects \*Cpr->stack\fP.
Routine \*Csr_scheduler\fP finds the next \*Cpr\fP on some queue,
then sets \*Cold_cur_proc\fP to itself and the \*Csr_cur_proc\fP to \*Cpr\fP.
It then does a context switch to the job server's private
context, which is just an infinite loop in \*Cswitch_proc\fP.
Routine \*Cswitch_proc\fP does four things:
.DS
1) releases \*Cold_cur_proc->stack_mutex\fP
2) acquires \*Csr_cur_proc->stack_mutex\fP
3) calls \*Csr_chg_context(sr_cur_proc->stack)\fP
4) if (\*Cold_cur_proc->status == FREE)\fP
       \*Cfree_proc(old_cur_proc)\fP
.DE
.IP
Since the job server holds no other locks while acquiring \*Cstack_mutex\fP,
it is acquired before all other locks.
.Fn "wait_ready_set_mutex [socket.c]"
This protects \*Cwaitset\fP, the set of file descriptors checked for input,
and incoming message counters.
It is acquired before \*Cmfd_fdm_mutex\fP,
but other than that it is never held when another lock is acquired.
.br
.ne 40
.Ss "Linear Ordering"
A linear ordering of lock classes is presented below.
When two locks are needed concurrently, the one in the lower numbered
class is acquired first.
There are no nestings between locks in the same class.
In other words, while a lock from class \fIn\fP is held, no other
lock from a class \fIm\fP may be obtained if \fIm\fP\(<=\fIn\fP.
.sp 1
.nf
.ta 10n
Class 0	stack_mutex  \fI(always held by the current proc)\fP
Class 1	res_pool->pmutex
Class 2	sr_main_res_mutex
Class 3	rmutex
Class 4	clmutex
Class 5	omutex
	remote_mutex
Class 6	sr_queue_mutex
	wait_ready_set_mutex
Class 7	alloc_mutex
	class_pool->pmutex
	cob_pool->pmutex
	cre_mutex
	currfd_mutex
	send_mutex
	final_mutex
	mem_mutex
	oper_pool->pmutex
	proc_pool->pmutex
	random_mutex
	sr_exec_up_mutex
Class 8	cobmutex
Class 9	maxfd_mutex
	mfd_fdm_mutex
	sem_pool->pmutex
	started_mutex
Class 10	sr_fd_lock[]
Class 11	debug_mutex
.fi
