Implementation

It is now time to describe the implementation of some of the occam-specific features such as channels and NOW. Also the way communication with UNIX† is performed must be described. † UNIX is a trademark of Bell Laboratories For a thorough description of the library routines to simulate parallelism, which are e.g. used by the channel routines and by the PAR construct in Appendix B, see [6]. Channels

There are currently two types of channels (see Figure 1.) indicated by the type field of a channel variable:

-   An interprocess communication channel with two additional fields:

    -   A synchronization field to hold the state of an interprocess communication channel.

    -   An integer variable to hold the value to be send.

-   An outside world communication channel. This is a member of an array of channels connected to UNIX files. Its additional fields are:

    -   A flags field holding a readahead flag and a flag that tells if this channel variable is currently connected to a file.

    -   A preread character, if readahead is done.

    -   An index field to find the corresponding UNIX file.

Figure 1. Interprocess and outside world communication channels The basic channel handling is done by chan_in and chan_out. All other routines are based on them. The routine chan_any only checks if there's a value available on a given channel. (It does not read this value!) C_init initializes an array of interprocess communication channels.

The following table shows Occam statements paired with the routines used to execute them.
Occam statement | Channel handling routine | Called as
CHAN c: CHAN c[z]: | c_init(c, z) chan *c; unsigned z; | c_init(&c, 1); c_init(&c, z);
c ? v | chan_in(v, c) long *v; chan *c; | chan_in(&v, &c);
c ? b[byte i] | cbyte_in(b, c) char *b; chan *c; | cbyte_in(&b[i], &c);
c ? a[i for z] | c_wa_in(a, z, c) long *a; unsigned z; chan *c; | c_wa_in(&a[i], z, &c);
c ? a[byte i for z] | c_ba_in(a, z, c) long *a; unsigned z; chan *c; | c_ba_in(&a[i], z, &c);
c ! v | chan_out(v, c) long *v; chan *c; | chan_out(&v, &c);
c ! a[i for z] | c_wa_out(a, z, c) long *a; unsigned z; chan *c; | c_wa_out(&a[i], z, &c);
c ! a[byte i for z] | c_ba_out(a, z, c) long *a; unsigned z; chan *c; | c_ba_out(&a[i], z, &c);
alt c ? .... .... | int chan_any(c) chan *c; | deadlock=0; for(;;) { if (chan_any(&c)) { .... ....
The code of c_init, chan_in, chan_out and chan_any can be found in Appendix A. Synchronization on interprocess communication channels

The synchronization field can hold three different values indicating the state the channel is in:

- C_S_FREE:
    Ground state, channel not in use.

- C_S_ANY:
    Channel holds a value, the sending process is waiting for an acknowledgement about its receipt.

- C_S_ACK:
    Channel data has been removed by a receiving process, the sending process can set the channel free now.

A sending process cannot simply wait until the channel changes state C_S_ANY to state C_S_FREE 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. NOW

NOW evaluates to the current time returned by the time(2) system call. The code is simply:
	long now()
	{
		deadlock=0;
		return time((long *) 0);
	}
The ``deadlock=0'' prevents deadlocks while using the clock. UNIX interface

To handle the communication with the outside world the following channels are defined:

-   input, that corresponds with the standard input file,

-   output, that corresponds with the standard output file,

-   error, that corresponds with the standard error file.

-   file, an array of channels that can be subscripted with an index obtained by the builtin named process ``open''. Note that input=file[0], output=file[1] and error=file[2].

Builtin named processes to open and close files are defined as
proc open(var index, value name[], mode[]) = ..... :
proc close(value index) = ..... :
To open a file `junk', write nonsense onto it, and close it, goes as follows:
	var i:
	seq
		open(i, "junk", "w")
		file[i] ! nonsense
		close(i)
Errors opening a file are reported by a negative index, which is the negative value of the error number (called errno in UNIX).

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:

- EOF
    (-1): Eof from file channel is read as -1.

- TEXT
    (-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).

- RAW
    (-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).

To exit an Occam program, e.g. after an error, a builtin named process exit is available that takes an exit code as its argument. Replicators and slices

Both the base and the count of replicators like in
    par i = [ base for count ] may be arbitrary expressions. The count in array slices like in
    c ? A[ base for count ] must be a constant expression however, the base is again free.