337 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			337 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
.NH
 | 
						|
Implementation
 | 
						|
.PP
 | 
						|
It is now time to describe the implementation of some of the occam-specific
 | 
						|
features such as channels and \fBNOW\fP. Also the way communication with
 | 
						|
UNIX\(dg is performed must be described.
 | 
						|
.FS
 | 
						|
\(dg UNIX is a trademark of Bell Laboratories
 | 
						|
.FE
 | 
						|
For a thorough description of the library routines to simulate parallelism,
 | 
						|
which are e.g. used by the channel routines and by the \fBPAR\fP construct
 | 
						|
in Appendix B, see [6].
 | 
						|
.NH 2
 | 
						|
Channels
 | 
						|
.PP
 | 
						|
There are currently two types of channels (see Figure 1.) indicated by the type
 | 
						|
field of a channel variable:
 | 
						|
.IP -
 | 
						|
An interprocess communication channel with two additional fields:
 | 
						|
.RS
 | 
						|
.IP -
 | 
						|
A synchronization field to hold the state of an interprocess communication
 | 
						|
channel.
 | 
						|
.IP -
 | 
						|
An integer variable to hold the value to be send.
 | 
						|
.RE
 | 
						|
.IP -
 | 
						|
An outside world communication channel. This is a member of an array of
 | 
						|
channels connected to UNIX files. Its additional fields are:
 | 
						|
.RS
 | 
						|
.IP -
 | 
						|
A flags field holding a readahead flag and a flag that tells if this channel
 | 
						|
variable is currently connected to a file.
 | 
						|
.IP -
 | 
						|
A preread character, if readahead is done.
 | 
						|
.IP -
 | 
						|
An index field to find the corresponding UNIX file.
 | 
						|
.RE
 | 
						|
.LP
 | 
						|
.PS
 | 
						|
box ht 3.0 wid 3.0
 | 
						|
box ht 0.75 wid 0.75 with .nw at 1st box.nw + (0.5, -0.5) "Process 1"
 | 
						|
box ht 0.75 wid 0.75 with .ne at 1st box.ne + (-0.5, -0.5) "Process 2"
 | 
						|
box ht 0.75 wid 0.75 with .sw at 1st box.sw + (0.5, 0.5) "Process 3"
 | 
						|
box ht 0.75 wid 0.75 with .se at 1st box.se + (-0.5, 0.5) "Process 4"
 | 
						|
line right from 5/12 <2nd box.ne, 2nd box.se> to 3rd box
 | 
						|
line right from 7/12 <2nd box.ne, 2nd box.se> to 3rd box
 | 
						|
line right from 5/12 <4th box.ne, 4th box.se> to 5th box
 | 
						|
line right from 7/12 <4th box.ne, 4th box.se> to 5th box
 | 
						|
line down from 5/12 <2nd box.sw, 2nd box.se> to 4th box
 | 
						|
line down from 7/12 <2nd box.sw, 2nd box.se> to 4th box
 | 
						|
line down from 5/12 <3rd box.sw, 3rd box.se> to 5th box
 | 
						|
line down from 7/12 <3rd box.sw, 3rd box.se> to 5th box
 | 
						|
line right 1.0 from 5/12 <5th box.ne, 5th box.se> 
 | 
						|
line right 1.0 from 7/12 <5th box.ne, 5th box.se> 
 | 
						|
line left 1.0 from 5/12 <2nd box.nw, 2nd box.sw> 
 | 
						|
line left 1.0 from 7/12 <2nd box.nw, 2nd box.sw> 
 | 
						|
.PE
 | 
						|
.DS C
 | 
						|
\fIFigure 1. Interprocess and outside world communication channels\fP
 | 
						|
.DE
 | 
						|
The basic channel handling is done by \f(CWchan_in\fP and \f(CWchan_out\fP. All
 | 
						|
other routines are based on them. The routine \f(CWchan_any\fP only checks if
 | 
						|
there's a value available on a given channel. (It does not read this value!)
 | 
						|
\f(CWC_init\fP initializes an array of interprocess communication channels.
 | 
						|
.LP
 | 
						|
The following table shows Occam statements paired with the routines used to
 | 
						|
execute them.
 | 
						|
.TS H
 | 
						|
center, box;
 | 
						|
c | c | c
 | 
						|
lf5 | lf5 | lf5.
 | 
						|
Occam statement	Channel handling routine	Called as
 | 
						|
=
 | 
						|
.sp 0.5
 | 
						|
.TH
 | 
						|
T{
 | 
						|
.nf
 | 
						|
CHAN c:
 | 
						|
CHAN c[z]:
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
c_init(c, z) 
 | 
						|
chan *c; unsigned z;
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
c_init(&c, 1);
 | 
						|
c_init(&c, z);
 | 
						|
.fi
 | 
						|
T}
 | 
						|
.sp 0.5
 | 
						|
_
 | 
						|
.sp 0.5
 | 
						|
T{
 | 
						|
.nf
 | 
						|
c ? v
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
chan_in(v, c)
 | 
						|
long *v; chan *c;
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
chan_in(&v, &c);
 | 
						|
.fi
 | 
						|
T}
 | 
						|
.sp 0.5
 | 
						|
T{
 | 
						|
.nf
 | 
						|
c ? b[byte i]
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
cbyte_in(b, c)
 | 
						|
char *b; chan *c;
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
cbyte_in(&b[i], &c);
 | 
						|
.fi
 | 
						|
T}
 | 
						|
.sp 0.5
 | 
						|
T{
 | 
						|
.nf
 | 
						|
c ? a[i for z]
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
c_wa_in(a, z, c)
 | 
						|
long *a; unsigned z; chan *c;
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
c_wa_in(&a[i], z, &c);
 | 
						|
.fi
 | 
						|
T}
 | 
						|
.sp 0.5
 | 
						|
T{
 | 
						|
.nf
 | 
						|
c ? a[byte i for z]
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
c_ba_in(a, z, c)
 | 
						|
long *a; unsigned z; chan *c;
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
c_ba_in(&a[i], z, &c);
 | 
						|
.fi
 | 
						|
T}
 | 
						|
.sp 0.5
 | 
						|
_
 | 
						|
.sp 0.5
 | 
						|
T{
 | 
						|
.nf
 | 
						|
c ! v
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
chan_out(v, c)
 | 
						|
long *v; chan *c;
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
chan_out(&v, &c);
 | 
						|
.fi
 | 
						|
T}
 | 
						|
.sp 0.5
 | 
						|
T{
 | 
						|
.nf
 | 
						|
c ! a[i for z]
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
c_wa_out(a, z, c)
 | 
						|
long *a; unsigned z; chan *c;
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
c_wa_out(&a[i], z, &c);
 | 
						|
.fi
 | 
						|
T}
 | 
						|
.sp 0.5
 | 
						|
T{
 | 
						|
.nf
 | 
						|
c ! a[byte i for z]
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
c_ba_out(a, z, c)
 | 
						|
long *a; unsigned z; chan *c;
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
c_ba_out(&a[i], z, &c);
 | 
						|
.fi
 | 
						|
T}
 | 
						|
.sp 0.5
 | 
						|
_
 | 
						|
.sp 0.5
 | 
						|
T{
 | 
						|
.nf
 | 
						|
alt
 | 
						|
	c ? ....
 | 
						|
		....
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
int chan_any(c)
 | 
						|
chan *c;
 | 
						|
.fi
 | 
						|
T}	T{
 | 
						|
.nf
 | 
						|
deadlock=0;
 | 
						|
for(;;) {
 | 
						|
	if (chan_any(&c)) {
 | 
						|
		....
 | 
						|
	....
 | 
						|
.fi
 | 
						|
T}
 | 
						|
.sp 0.5
 | 
						|
.TE
 | 
						|
The code of \f(CWc_init\fP, \f(CWchan_in\fP, \f(CWchan_out\fP and \f(CWchan_any\fP
 | 
						|
can be found in Appendix A.
 | 
						|
.NH 3
 | 
						|
Synchronization on interprocess communication channels
 | 
						|
.PP
 | 
						|
The synchronization field can hold three different values indicating the
 | 
						|
state the channel is in:
 | 
						|
.IP "- \fBC\(ulS\(ulFREE\fP:" 15
 | 
						|
Ground state, channel not in use.
 | 
						|
.IP "- \fBC\(ulS\(ulANY\fP:" 15
 | 
						|
Channel holds a value, the sending process is waiting for an acknowledgement
 | 
						|
about its receipt.
 | 
						|
.IP "- \fBC\(ulS\(ulACK\fP:" 15
 | 
						|
Channel data has been removed by a receiving process, the sending process can
 | 
						|
set the channel free now.
 | 
						|
.LP
 | 
						|
A sending process cannot simply wait until the channel changes state C\(ulS\(ulANY
 | 
						|
to state C\(ulS\(ulFREE before it continues. There is a third state needed to prevent
 | 
						|
a third process from using the channel before our sending process is 
 | 
						|
acknowledged. Note, however that it is not allowed to use a channel for input
 | 
						|
or output in more than one parallel process. This is too difficult to check
 | 
						|
in practice, so we tried to smooth it a little.
 | 
						|
.NH 2
 | 
						|
NOW
 | 
						|
.PP
 | 
						|
\fBNOW\fP evaluates to the current time returned by the time(2) system call.
 | 
						|
The code is simply:
 | 
						|
.DS
 | 
						|
.ft CW
 | 
						|
.nf
 | 
						|
	long now()
 | 
						|
	{
 | 
						|
		deadlock=0;
 | 
						|
		return time((long *) 0);
 | 
						|
	}
 | 
						|
.fi
 | 
						|
.ft
 | 
						|
.DE
 | 
						|
The ``deadlock=0'' prevents deadlocks while using the clock.
 | 
						|
.NH 2
 | 
						|
UNIX interface
 | 
						|
.PP
 | 
						|
To handle the communication with the outside world the following channels are
 | 
						|
defined:
 | 
						|
.IP -
 | 
						|
\fBinput\fP, that corresponds with the standard input file,
 | 
						|
.IP -
 | 
						|
\fBoutput\fP, that corresponds with the standard output file,
 | 
						|
.IP -
 | 
						|
\fBerror\fP, that corresponds with the standard error file.
 | 
						|
.IP -
 | 
						|
\fBfile\fP, an array of channels that can be subscripted with an index
 | 
						|
obtained by the builtin named process ``\f(CWopen\fP''. Note that
 | 
						|
\fBinput\fP=\fBfile\fP[0], \fBoutput\fP=\fBfile\fP[1] and
 | 
						|
\fBerror\fP=\fBfile\fP[2].
 | 
						|
.LP
 | 
						|
Builtin named processes to open and close files are defined as
 | 
						|
.DS
 | 
						|
.nf
 | 
						|
.ft CW
 | 
						|
proc open(var index, value name[], mode[]) = ..... :
 | 
						|
proc close(value index) = ..... :
 | 
						|
.fi
 | 
						|
.ft
 | 
						|
.DE
 | 
						|
To open a file `junk', write nonsense onto it, and close it, goes as follows:
 | 
						|
.DS
 | 
						|
.ft CW
 | 
						|
.nf
 | 
						|
	var i:
 | 
						|
	seq
 | 
						|
		open(i, "junk", "w")
 | 
						|
		file[i] ! nonsense
 | 
						|
		close(i)
 | 
						|
.fi
 | 
						|
.ft
 | 
						|
.DE
 | 
						|
Errors opening a file are reported by a negative index, which is the
 | 
						|
negative value of the error number (called \fIerrno\fP in UNIX).
 | 
						|
.LP
 | 
						|
Bytes read from or written onto these channels are taken from occam variables.
 | 
						|
As these variables can hold more than 256 values, some negative values are used
 | 
						|
to control channels. These values are:
 | 
						|
.IP "- \fBEOF\fP" 9
 | 
						|
(-1): Eof from file channel is read as -1.
 | 
						|
.IP "- \fBTEXT\fP" 9
 | 
						|
(-2): A -2 written onto any channel connected to a terminal puts this
 | 
						|
terminal in the normal line oriented mode (i.e. characters typed are echoed
 | 
						|
and lines are buffered before they are read).
 | 
						|
.IP "- \fBRAW\fP" 9
 | 
						|
(-3): A -3 written onto any channel connected to a terminal puts it in raw mode
 | 
						|
(i.e. no echoing of typed characters and no line buffering).
 | 
						|
.LP
 | 
						|
To exit an Occam program, e.g. after an error, a builtin named process
 | 
						|
\f(CWexit\fP is available that takes an exit code as its argument.
 | 
						|
.NH 2
 | 
						|
Replicators and slices
 | 
						|
.PP
 | 
						|
Both the base and the count of replicators like in
 | 
						|
.DS
 | 
						|
.ft CW
 | 
						|
	par i = [ base for count ]
 | 
						|
.ft
 | 
						|
.DE
 | 
						|
may be arbitrary expressions. The count in array slices like in
 | 
						|
.DS
 | 
						|
.ft CW
 | 
						|
	c ? A[ base for count ]
 | 
						|
.ft
 | 
						|
.DE
 | 
						|
must be a constant expression however, the base is again free.
 |