.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 5/12 <3nd box.nw, 3nd box.sw> line right from 7/12 <2nd box.ne, 2nd box.se> to 7/12 <3nd box.nw, 3nd box.sw> line right from 5/12 <4th box.ne, 4th box.se> to 5/12 <5nd box.nw, 5nd box.sw> line right from 7/12 <4th box.ne, 4th box.se> to 7/12 <5nd box.nw, 5nd box.sw> line down from 5/12 <2nd box.sw, 2nd box.se> to 5/12 <4nd box.nw, 4nd box.ne> line down from 7/12 <2nd box.sw, 2nd box.se> to 7/12 <4nd box.nw, 4nd box.ne> line down from 5/12 <3rd box.sw, 3rd box.se> to 5/12 <5nd box.nw, 5nd box.ne> line down from 7/12 <3rd box.sw, 3rd box.se> to 7/12 <5nd box.nw, 5nd box.ne> 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.