[comp.sys.transputer] Parallel programming examples - the solution - SPOILER

andyr@inmos.com (Andy Rabagliati) (04/19/91)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  fifo.occ fifoc.c inout.occ makefile test1c.c test1o.occ
#   test2c.c test2o.occ
# Wrapped by andyr@inmos-c on Fri Apr 19 08:56:35 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'fifo.occ' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fifo.occ'\"
else
echo shar: Extracting \"'fifo.occ'\" \(1689 characters\)
sed "s/^X//" >'fifo.occ' <<'END_OF_FILE'
X--{{{  description of function
X-- fifo implements a true fifo - ready to input any time there is room, and
X-- ready to output any time there are characters in the buffer. Note that
X-- because we have no output ALT, this must be done with two processes.
X--
X-- input handles the resource of the buffer itself and the pointers into it,
X-- and services requests from two places. First, characters being input from
X-- in. Second, requests from the output process for new characters to
X-- output. These come in on channel signal. Responses to requests from
X-- signal go out on channel more.
X--
X-- There is no other way to handle this, given the CSP process model that the
X-- Transputer implements.
X--
X--}}}
XPROC fifo(CHAN OF BYTE in, out)
X  VAL max IS 256 :                     -- max buffer size
X  CHAN OF BOOL signal :
X  CHAN OF BYTE more :
X  PAR
X    --{{{  input process and buffer
X    [max] BYTE buffer :
X    INT the.front, back :
X    BOOL running :
X    SEQ
X      the.front, back, running := 0, 0, TRUE
X      WHILE running OR (the.front <> back)
X        INT front :
X        BOOL any :
X        SEQ
X          front := (the.front+1) \ max
X          ALT
X            (the.front <> back) & signal ? any -- signal for more
X              SEQ
X                more ! buffer [back]           -- send next
X                running := buffer[back] <> '~' -- end condition test
X                back := (back+1) \ max
X            (front <> back)     & in  ? buffer[the.front]
X              the.front := front
X    --}}}
X    --{{{  output process
X    BYTE datum :
X    SEQ
X      datum := ' '
X      WHILE datum <> '~'
X        SEQ
X          signal ! TRUE
X          more ? datum
X          out ! datum
X    --}}}
X:
END_OF_FILE
if test 1689 -ne `wc -c <'fifo.occ'`; then
    echo shar: \"'fifo.occ'\" unpacked with wrong size!
fi
# end of 'fifo.occ'
fi
if test -f 'fifoc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fifoc.c'\"
else
echo shar: Extracting \"'fifoc.c'\" \(2888 characters\)
sed "s/^X//" >'fifoc.c' <<'END_OF_FILE'
X#include <process.h>
X#define MAX 256
X#define NULL    ((void *) 0)
X
X /*
X  * fifo implements a true fifo - ready to input any time there is room, and
X  * ready to output any time there are characters in the buffer. Note that
X  * because we have no output ALT, this must be done with two processes. 
X  *
X  * input_p handles the resource of the buffer itself and the pointers into it,
X  * and services requests from two places. First, characters being input from
X  * *in. Second, requests from the process output_p for new characters to
X  * output. These come in on channel *signal. Responses to requests from
X  * signal go out on channel *more. 
X  *
X  * There is no other way to handle this, given the CSP process model that the
X  * Transputer implements. 
X  *
X  * output_p simply requests characters, then outputs them on channel *out. 
X  *
X  * Please note the way guards on ALTs are implemented. There are slightly more
X  * simple methods, but this is a very general mechanism. If the guard is
X  * false, we put the channel always_empty in the alt list. Having an empty
X  * channel means that the index returned by the ProcAltList function always
X  * corresponds to the same input being ready. Very handy. 
X  *
X  * Though in this case we will only be using always_empty in one place in the
X  * alt list, it can be put in many places. Thus if we have a 100-way guarded
X  * ALT, we only need one always_empty channel. 
X  *
X  */
X
Xvoid            input_p(Process * parent,
X	                     Channel * in, Channel * signal, Channel * more)
X{
X    Channel         always_empty;	/* remember to use & in refs */
X    Channel        *altlist[3];
X    char            buffer[MAX], lastchar = ' ';
X    int             the_front = 0, back = 0;
X    ChanInit(&always_empty);
X    altlist[2] = NULL;		/* terminator for ProcAltList */
X
X    while (lastchar != '~')
X    {
X	/* useful incremented version of the_front */
X	int             front = (the_front + 1) % MAX;
X	altlist[0] = (the_front != back) ? signal : &always_empty;
X	altlist[1] = (front != back) ? in : &always_empty;
X	switch (ProcAltList(altlist))
X	{
X	    case 0:
X		ChanInChar(signal);	/* must input signal !! */
X		ChanOutChar(more, lastchar = buffer[back++]);
X		back = back % MAX;
X		break;
X	    case 1:
X		buffer[the_front] = ChanInChar(in);
X		the_front = front;
X		break;
X	}
X    }
X}
X
Xvoid            output_p(Process * parent,
X	                    Channel * out, Channel * signal, Channel * more)
X{
X    char            c = ' ';
X    while (c != '~')
X    {
X	ChanOutChar(signal, '*');	/* anything */
X	ChanOutChar(out, c = ChanInChar(more));
X    }
X}
X
Xvoid            fifo(Process * parent, Channel * in, Channel * out)
X{
X    Channel         signal, more;
X    ChanInit(&signal);
X    ChanInit(&more);
X    ProcPar(
X	    ProcAlloc(input_p, 100, 3, in, &signal, &more),
X            ProcAlloc(output_p, 100, 3, out, &signal, &more),
X            NULL );
X}
END_OF_FILE
if test 2888 -ne `wc -c <'fifoc.c'`; then
    echo shar: \"'fifoc.c'\" unpacked with wrong size!
fi
# end of 'fifoc.c'
fi
if test -f 'inout.occ' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'inout.occ'\"
else
echo shar: Extracting \"'inout.occ'\" \(2002 characters\)
sed "s/^X//" >'inout.occ' <<'END_OF_FILE'
X-- The iserver routines can easily be replaced by similar ones in the hostio
X-- library. I just like to know exactly what is going on - this way nothing
X-- goes on the Transputer that I dont know about.
X-- This applies to write.char, pollkey, and so.exit.
X
XPROTOCOL SP IS INT16::[]BYTE :
X--{{{  PROC inout(CHAN OF SP fs, ts, CHAN OF BYTE out, in)
XPROC inout(CHAN OF SP fs, ts, CHAN OF BYTE out, in)
X  -- routines similar to these are in hostio.lib
X  --{{{  PROC write.char (VAL BYTE char)
X  PROC write.char (VAL BYTE char)
X    SEQ
X      ts ! 8(INT16)::[24(BYTE),                 -- length, FPutBlock
X            1(BYTE), 0(BYTE), 0(BYTE), 0(BYTE), -- StreamId = 1
X            1(BYTE), 0(BYTE),                   -- INT16 len = 1
X            char ]
X      INT16 len :
X      [8]BYTE packet :
X      fs ? len::packet
X  :
X  --}}}
X  --{{{  PROC pollkey(BYTE char, BYTE result)
X  PROC pollkey(BYTE char, BYTE result)
X    INT16 len :
X    [8]BYTE packet :
X    SEQ
X      ts ! 8(INT16)::[31(BYTE),             -- length, Pollkey
X            'x','x','x','x','x','x','x']    -- padding to 8 bytes
X      fs ? len::packet                      -- read result
X      char, result := packet[1], packet[0]
X  :
X  --}}}
X  BYTE char :
X  SEQ
X    char := ' '
X    WHILE char <> '~'
X      TIMER TIME :
X      INT now :
X      SEQ
X        TIME ? now
X        ALT
X          in ? char
X            write.char(char)
X          TIME ? AFTER now PLUS 156  -- 1/100 sec
X            BYTE key, result :
X            SEQ
X              pollkey(key, result)
X              IF
X                result = 0(BYTE)
X                  out ! (BYTE key)
X                TRUE
X                  SKIP
X:
X--}}}
X--{{{  PROC so.exit(CHAN OF SP fs, ts)
XPROC so.exit(CHAN OF SP fs, ts)
X  SEQ
X    ts ! 8(INT16)::[35(BYTE),                         -- length, Exit
X          #FF(BYTE), #C9(BYTE), #9A(BYTE), #3B(BYTE), -- Success 999999999
X          'x','x','x']                                -- padding
X    INT16 len :
X    [8]BYTE packet :
X    fs ? len::packet
X:
X--}}}
END_OF_FILE
if test 2002 -ne `wc -c <'inout.occ'`; then
    echo shar: \"'inout.occ'\" unpacked with wrong size!
fi
# end of 'inout.occ'
fi
if test -f 'makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile'\"
else
echo shar: Extracting \"'makefile'\" \(1423 characters\)
sed "s/^X//" >'makefile' <<'END_OF_FILE'
XOCCOPT=  /y /t8
XLINKOPT= /y /t8
XCONFOPT=
XOCONFOPT=
XCOLLECTOPT= /t
XCOPT= /t8
X
Xtest2c:     test2c.btl
X            iserver /se /sb test2c.btl
X
Xtest2c.btl: test2c.lku
X            icollect $(COLLECTOPT) test2c.lku
X
Xtest2c.lku: test2c.tco fifoc.tco
X            ilink $(LINKOPT) test2c.tco fifoc.tco libc.lib centry.lib /me C.ENTRY
X
Xtest2c.tco: test2c.c
X            icc $(COPT) test2c.c
X
Xfifoc.tco:  fifoc.c
X            icc $(COPT) fifoc.c
X
Xtest1c:     test1c.btl
X            iserver /se /sb test1c.btl
X
Xtest1c.btl: test1c.lku
X            icollect $(COLLECTOPT) test1c.lku
X
Xtest1c.lku: test1c.tco
X            ilink $(LINKOPT) test1c.tco libc.lib centry.lib /me C.ENTRY
X
Xtest1c.tco: test1c.c
X            icc $(COPT) test1c.c
X
Xtest2o:     test2o.btl
X            iserver /se /sb test2o.btl
X
Xtest2o.btl: test2o.lku
X            icollect $(COLLECTOPT) test2o.lku
X
Xtest2o.lku: test2o.tco inout.tco fifo.tco
X            ilink $(LINKOPT) test2o.tco inout.tco fifo.tco
X
Xtest2o.tco: test2o.occ inout.tco fifo.tco
X            oc $(OCCOPT) test2o.occ
X
Xtest1o:     test1o.btl
X            iserver /se /sb test1o.btl
X
Xtest1o.btl: test1o.lku
X            icollect $(COLLECTOPT) test1o.lku
X
Xtest1o.lku: test1o.tco
X            ilink $(LINKOPT) test1o.tco inout.tco
X
Xtest1o.tco: test1o.occ inout.tco
X            oc $(OCCOPT) test1o.occ
X
Xinout.tco:  inout.occ
X            oc $(OCCOPT) inout.occ
X
Xfifo.tco:   fifo.occ
X            oc $(OCCOPT) fifo.occ
X
END_OF_FILE
if test 1423 -ne `wc -c <'makefile'`; then
    echo shar: \"'makefile'\" unpacked with wrong size!
fi
# end of 'makefile'
fi
if test -f 'test1c.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'test1c.c'\"
else
echo shar: Extracting \"'test1c.c'\" \(1905 characters\)
sed "s/^X//" >'test1c.c' <<'END_OF_FILE'
X#include <process.h>
X#include <stdio.h>
X#include <iocntrl.h>
X
X#define MAX 100
X
Xvoid buf (Process *parent, Channel *in, Channel *out) {
X    char c = ' ';
X    while (c!='~')
X        ChanOutChar(out, c=ChanInChar(in));
X}
X
Xvoid buffer (Process *parent, Channel *in, Channel *out) {
X    Channel pipe[MAX];          /* we are declaring the channels themselves,
X                                 * so remember to use & address-of */
X    Process *list[MAX+2];       /* will be MAX+1 processes */
X    int i;
X
X    for (i=0; i < (MAX-1); i++) {
X        ChanInit(&pipe[i]);                 /* clear channel */
X        list[i] = ProcAlloc(buf, 80, 2, &pipe[i], &pipe[i+1]);
X                                            /* 80 bytes seems to be enough */
X    }
X    ChanInit(&pipe[MAX-1]);           /* last pipe - not hit by loop above */
X
X    list[MAX-1] = ProcAlloc(buf, 80, 2, in, &pipe[0]);
X    list[MAX]   = ProcAlloc(buf, 80, 2, &pipe[MAX-1], out);
X    list[MAX+1] = NULL;              /* end of list for ProcParList */
X
X    ProcParList(list);
X}
X
Xvoid inout(Process *parent, Channel *out, Channel *in) {
X    int key;
X    char c = ' ';
X    while (c!='~') {
X        switch (ProcTimerAlt(ProcTimePlus(ProcTime(), 156), in, NULL)) {
X            case -1:
X                key = pollkey();
X                if (key != -1)
X                    ChanOutChar(out, (char) key);
X                break;
X            case 0:
X                putchar(c = ChanInChar(in));
X                fflush(stdout);
X                break;
X        }
X    }
X}
X
Xint main(void) {
X    Channel to_buf, from_buf;   /* we are declaring the channels themselves,
X                                 * so remember to use & address-of */
X    ChanInit(&to_buf);
X    ChanInit(&from_buf);
X    ProcPar(
X        ProcAlloc(inout, 4096, 2, &to_buf, &from_buf),
X        ProcAlloc(buffer, 4096, 2, &to_buf, &from_buf), NULL );
X
X    return (999999999);     /* success */
X}
X
END_OF_FILE
if test 1905 -ne `wc -c <'test1c.c'`; then
    echo shar: \"'test1c.c'\" unpacked with wrong size!
fi
# end of 'test1c.c'
fi
if test -f 'test1o.occ' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'test1o.occ'\"
else
echo shar: Extracting \"'test1o.occ'\" \(458 characters\)
sed "s/^X//" >'test1o.occ' <<'END_OF_FILE'
XPROTOCOL SP IS INT16::[]BYTE :
X#USE "inout.tco"
XPROC exercise1(CHAN OF SP fs, ts, []INT memory)
X  SEQ
X    VAL MAX IS 10 :
X    [MAX+1]CHAN OF BYTE pipe :
X    PAR
X      inout(fs, ts, pipe[0], pipe[MAX])
X      PAR i = 0 FOR MAX
X        --{{{  little buffer processes
X        BYTE char :
X        SEQ
X          char := ' '
X          WHILE char <> '~'
X            SEQ
X              pipe[i] ? char
X              pipe[i+1] ! char
X        --}}}
X    so.exit(fs, ts)
X:
END_OF_FILE
if test 458 -ne `wc -c <'test1o.occ'`; then
    echo shar: \"'test1o.occ'\" unpacked with wrong size!
fi
# end of 'test1o.occ'
fi
if test -f 'test2c.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'test2c.c'\"
else
echo shar: Extracting \"'test2c.c'\" \(1301 characters\)
sed "s/^X//" >'test2c.c' <<'END_OF_FILE'
X#include <process.h>
X#include <stdio.h>
X#include <iocntrl.h>
X
Xvoid            fifo(Process *, Channel *, Channel *, Channel *);
X
X /*
X  * inout is functionally equivalent to two parallel processes, one taking
X  * keys from the keyboard and outputting them to *out, the other reading
X  * characters from *in and writing them to the screen. It is in fact
X  * implemented as an ALT, because both pseudo-processes need both iserver
X  * channels. 
X  */
X
Xvoid            inout(Process * parent, Channel * out, Channel * in)
X{
X    int             key;
X    char            c = ' ';
X    while (c != '~')
X    {
X	switch (ProcTimerAlt(ProcTimePlus(ProcTime(), 156), in, NULL))
X	{
X	    case -1:		/* timeout - poll keyboard */
X		key = pollkey();
X		if (key != -1)
X		    ChanOutChar(out, (char) key);
X		break;
X	    case 0:		/* in is ready - read it */
X		putchar(c = ChanInChar(in));
X		fflush(stdout);
X		break;
X	}
X    }
X}
X
Xint             main(void)
X{
X    Channel         to_buf, from_buf;	/* we are declaring the channels
X					 * themselves, so remember to use &
X					 * address-of */
X    ChanInit(&to_buf);
X    ChanInit(&from_buf);
X    ProcPar(
X	    ProcAlloc(inout, 4096, 2, &to_buf, &from_buf),
X            ProcAlloc(fifo, 4096, 2, &to_buf, &from_buf),
X            NULL );
X
X    return (999999999);		/* success */
X}
END_OF_FILE
if test 1301 -ne `wc -c <'test2c.c'`; then
    echo shar: \"'test2c.c'\" unpacked with wrong size!
fi
# end of 'test2c.c'
fi
if test -f 'test2o.occ' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'test2o.occ'\"
else
echo shar: Extracting \"'test2o.occ'\" \(251 characters\)
sed "s/^X//" >'test2o.occ' <<'END_OF_FILE'
XPROTOCOL SP IS INT16::[]BYTE :
X#USE "inout.tco"
X#USE "fifo.tco"
XPROC exercise2(CHAN OF SP fs, ts, []INT memory)
X  SEQ
X    CHAN OF BYTE to.buf, from.buf :
X    PAR
X      inout(fs, ts, to.buf, from.buf)
X      fifo(to.buf, from.buf)
X    so.exit(fs, ts)
X:
END_OF_FILE
if test 251 -ne `wc -c <'test2o.occ'`; then
    echo shar: \"'test2o.occ'\" unpacked with wrong size!
fi
# end of 'test2o.occ'
fi
echo shar: End of shell archive.
exit 0