A Pipe.T, or pipe, is a file handle that provides access to one
   endpoint of a unidirectional channel that is typically used to
   communicate between a parent and a child process or two sibling
   processes.  (See Process.Create.) 
INTERFACEPipe ; IMPORT File, OSError; TYPE T <: File.T; VAR (*CONST*) FileType: File.Type;
Equal to {\tt Atom.FromText("Pipe").}
PROCEDURE Open(VAR (*OUT*) hr, hw: T) RAISES {OSError.E};
Create a new channel allowing bytes written tohwto be read fromhr.
END Pipe.Like every
File.T, a pipe h has the components
      type(h)      an atom, equal to FileType
      readable(h)  a boolean
      writable(h)  a boolean
   Exactly one of readable(h) and writable(h) is true (until the
   pipe is closed).
   A pipe h also has the component
      channel(h)   a channel
   If there are pipes hw and hr with channel(hw) = channel(hr),
   writable(hw), and readable(hr), then a process holding hw can
   send information to a process holding hr.
   A channel c has the components
      seq(c)  a sequence of bytes
      w(c)    a non-negative integer, the index of the next byte to write
      r(c)    a non-negative integer, the index of the next byte to read
      nw(c)   a non-negative integer, the number of pipes writing c
      nr(c)   a non-negative integer, the number of pipes reading c
   It is possible (but not very useful) for a channel to have values of
   nw(c) or nr(c) other than zero or one (see Process.Create).
   Open creates a channel c with
      w(c) = r(c) = 0
      nw(c) = nr(c) = 1
   and two pipes hr and hw with
      type(hr) = type(hw) = FileType
      readable(hr) = writable(hw) = TRUE
      writable(hr) = readable(hw) = FALSE
      channel(hr) = channel(hw) = c
The meaning of the call
      h.read(b, mayBlock)
   is given by the specification of File.T.read together with these
   definitions, where c = channel(h):
      src(h)    = seq(c)
      srcCur(h) = r(c)
      srcEof(h) = (nw(c) = 0)
   Note that end-of-file is not reported until after the last pipe
   that can write on the channel is closed; subsequent reads are legal
   but always report end-of-file.
The meaning of the call
      h.write(b)
   is given by the specification of File.T.write together with these
   definitions, where c = channel(h):
      snk(h)    = seq(c)
      snkCur(h) = w(c)
   In some implementations, a channel has a bounded buffer, so write
   may have to block.  If nr(channel(h)) = 0, that is, no pipe can
   read h's channel, write raises OSError.E.
The call
      h.status(stat)
   assigns FileType to stat.type.  Its effect on
   stat.modificationTime and stat.size is undefined.
The call
      h.close()
   is equivalent to
      IF readable(h) THEN
        DEC(nr(channel(h)))
      ELSE
        DEC(nw(channel(h)))
      END;
      readable(h) := FALSE;
      writable(h) := FALSE
   The channel connecting a pair of pipes is necessarily monitored,
   since the purpose of the channel is to allow asynchronous
   communication via the pipes.  Nevertheless, an individual pipe
   should be treated as unmonitored, thus avoiding the question of the
   unit of atomicity for reads and writes.