4. Communication Streams

There are two ways to communicate in Athapascan-0: messages and buffers. The messages are not copied into any buffer and are sent/received directly from/to their storage memory. Buffers allow the programmer to pack several little data into a single message, to avoid the transmission of small messages and to make possible the transfer of complex data.

Athapascan-0 Formats proposes a mixed tool to transfer data, the pipes. A pipe works as a buffered communication stream, where one node puts data into and another node gets data from. A connexion must be done before any data transfer, to specify the port and tag to use and to create its buffer. The function a0NewPipe() creates a new pipe and connects it.

Normally every stream has a secondary thread to listen or talk in the pipe, with a priority selected on creation time. Put/get requests are stored in a queue and the secondary thread packes/unpackes the requests into/from the buffer. If the buffer is full/empty, the secondary thread blocks to send/receive the buffer. After serving the request, the secondary thread marks it as completed, in order to the primary thread test or wait it.

There are two protocols of operation of a pipe. In the normal operating protocol, the pipe has a buffer to stock small data, which is sent only when it's full. Big data are cut to fit in the buffer, allowing the program to use a different number of requests to send and to receive it. The second protocol only allows blocking puts and gets, so no secondary thread has to be created. They are implemented in such a way that different protocols can be used in each side of the same pipe.

The put and get functions are a0FPut() and a0FGet() and they have non blocking versions (a0IFPut() and a0IFGet()). Any basic or user-defined format can be used to put data to and get data from pipes.

  /* in one site */
  a0tPipe pipe;
  int table[10];
  a0NewPipe(&pipe, &port, node, tag,
            A0DefaultPipeSize, A0OutputPipe,
            A0InheritPriority);
  a0FPut(&pipe, &request, A0FInt, &table, 10);
  ...
  /* in another site */
  a0tPipe pipe;
  int value;
  a0NewPipe(&pipe, &port, node, tag,
            A0DefaultPipeSize, A0InputPipe,
            A0InheritPriority);
  for (n=0; n<10; n++) {
    a0FGet(&pipe, &request, A0FInt, &value, 1);
    ...
  }

To guarantee that the data in the buffer pipe are sent, the function a0Flush() must be called. It blocks the calling thread until all the previous requests are processed, even in the input side of the pipe. In the output side, after processing all requests, it sends the buffer if it contains some data in. The function

a0DisposePipe() (or at least a0Flush()) should be called to every output pipe before terminating the program. It would avoid the receiving side to starve trying to receive the last data stored in the send buffer, which is not sent automatically by a0Terminate()