# The Pipe interface

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

    INTERFACE Pipe;

    IMPORT File, OSError;

    TYPE T <: File.T;

    VAR (*CONST*) FileType: File.Type;

Equal to `Atom.FromText(*Pipe*).`

    PROCEDURE Open(VAR (*OUT*) hr, hw: T) RAISES {OSError.E};

Create a new channel allowing bytes written to `hw` to be read from `hr`.

    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.