338 lines
7.2 KiB
Plaintext
338 lines
7.2 KiB
Plaintext
.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.
|