.sh 1 "Procedures and Processes"
.sh 2 "Procs"
.(b
proc  ::=  |1@proc@  operation_identifier  (  formal_identifier  @,@{{*}}  )\
 return_part{{o}}
           /1     block
           /1@end@  operation_identifier{{o}}
.)b
.(b
return_part  ::=  @returns@  result_identifier
.)b
.lp
A @proc@ defines a pattern,
instances of which implement the named operation.
When the operation is invoked, a new process is
(at least conceptually) created to service the operation.
If the operation was invoked by @send@,
this process executes concurrently with the invoker.
However, if the operation was implicitly or explicitly called,
the invoker waits for this process to terminate or to execute @reply@.
Thus, sending to an operation that is implemented by a @proc@
is analogous to forking a process.
Calling an operation that is implemented by a @proc@ is analogous to
executing a possibly remote, possibly recursive procedure call.
.pp
Instances of @proc@s may execute in parallel on a multiprocessor.
Execution of @proc@s on a single processor is interleaved.
The underlying SR scheduler is fair in the sense that every @proc@
that is not blocked eventually gets a chance to execute.
Thus, if one @proc@ executes a permanent loop or
spins while waiting for a variable to change value, it does not
preclude other processes from executing.
However, busy waiting is inefficient on a single processor.
.pp
The number of formal identifiers must equal the number of formal
parameters in the corresponding operation declaration.
If the @proc@ implements a function,
it must also contain a return part.
Within a @proc@,
the formal and result identifiers are the names by which
formals are referenced and the return value is constructed.
These identifiers will often be the same as the corresponding
identifiers in the op declaration, but need not be.
.pp
The optional identifier at the end of a @proc@
must be the same as the identifier of the @proc@.
.PS L
%Examples:
.sp .5
	# Determine first place at which strings s1 and s2 differ.
	# Return 0 if the strings are the same.
	proc differ(s1,s2) returns place
	  var i := 1, len := min(length(s1),length(s2))
	  do i<=len & s1[i]=s2[i] -> i++ od
	  if i>len & length(s1)=length(s2) -> place := 0
	  [] else -> place := i
	  fi
	end differ

	# compute the left neighbor of philosopher i, 1 <= i <= 5
	proc left(i) returns lft
	  if i=1 -> lft := 5 [] else -> lft := i-1 fi
	end
.PE
.sh 2 "Processes"
.(b
process  ::=  |1@process@  process_name
              /1     block
              /1@end@  process_identifier{{o}}
.)b
.(b
process_name  ::=  process_identifier  process_quantifier{{o}}
.)b
.(b
process_quantifier  ::=  ( quantifier @,@{{+}} )
.)b
.lp
A @process@ declaration defines both an operation and its implementation.
Syntactically,
@process@ is an abbreviation for an operation declaration
and the @proc@ that implements it.
A @process@ declaration also specifies that instances
of the @process@ be created as part of resource creation;
i.e., it defines background processes.
The number of such instances, and the exact meaning of
the process declaration,
depend on whether a process quantifier is present.
.pp
Without a process quantifier,
one instance of the @process@ is created as part of resource creation.
The process identifier is treated as though it had been declared as
a parameterless @op@ with a @send@ restriction, e.g.,
.PS
op process_identifier() {send}
.PE
Because of this implicit declaration,
a @process@ cannot be used to implement a previously declared operation.
The operation implicitly declared by a @process@ can be used
subsequent to its declaration
in the same ways as any other operation:
It can be invoked and assigned to capability variables.
However, it would be clearer in this case to declare
the operation explicitly rather than to use a @process@ declaration.
.pp
One instance of each background process in a resource
is created as the last step in resource creation (see Sec. 5.2.3).
Specifically,
it is as though the statement
.PS
send process_identifier()
.PE
is executed just before the initial component returns or terminates;
if there is no initial component,
it is as though @send@ is executed as part of an implicit
initial component.\**
.(f
\**
Note that the implicit @send@ statement in the initialization component
would not usually be legal if the initialization component
preceded the process because the process_identifier
would not yet have been declared.
Also, if a resource contains multiple processes,
the order in which they are invoked as part of initialization
is nondeterministic.
This is not really significant, however,
because the order in which
the processes would service their operations
and the order in which they would execute are not
predictable in any case.
.)f
.pp
A process quantifier is used to specify an array of processes.
This form of declaration generalizes the simpler form
described above.
The process identifier is treated as though it has been declared
as an @op@ with a @send@ restriction.
The declaration contains one (value) parameter
for each quantifier;
the parameters appear in the same order as the quantifier variables.
Each parameter's type is the same
as that of the corresponding quantifier variable.
One instance of the process is created for each different
set of values of the bound variables in the quantifier.
(See the for-all statement in section 5.5 for details on quantifiers.)
Specifically,
a @send@ statement is used (similar to the above)
to create each instance,
passing it the values of its bound variables.
Within each instance, the bound variables
serve as formal parameters whose values can be used to distinguish
the instances from each other.
For example, given the process heading
.PS
process foo(i := 1 to 10)
.PE
ten instances of @foo@ are implicitly created as part of initialization
of the enclosing resource.
Within each instance, @i@ has a different one of the values from 1 to 10.
.pp
The optional identifier at the end of a @process@
must be the same as the identifier of the @process@.
.PS L
%Examples:
.sp .5
	# Allocate forks to Dining Philosophers
	# uses proc left(i) defined in the previous section
	process ForkManager
	  var eating[1:5] : bool := ([5] false)
	  do true ->
	    in getforks(i) & not eating[i%5 + 1]
                 & not eating[left(i)] ->
	                          eating[i] := true
	    [] releaseforks(i) -> eating[i] := false
	    ni
	  od
	end ForkManager
.PE
.PS L
	# multiply n by n matrices a and b in parallel
	# place result in matrix c
	# all matrices are global to multiply
	process multiply(i := 1 to n, j := 1 to n)
	  var inner_prod := 0
	  fa k := 1 to n ->
	      inner_prod := inner_prod + a[i,k]*b[k,j]
	  af
	  c[i,j] := inner_prod
	end
.PE
