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.
 |