Family: PipeRing
Authors: KSB Braunsdorf
Mail: [email protected]
Version: 1.6
Bugs: None known.

Introduction

This module provides a function that starts a ring of process connected together by pipes (see pipe(2)). On some systems these are actually implemented as pairs of connected sockets (see socketpair(2))

Configuration

#define PIPERING_STALL 20
When a fork(2) system call returns EAGAIN the ring-builder sleep(3)'s for a Fibonacci number of seconds in the hopes that some system resources may come available. This stall value is the longest allowed sleep.

In the default case of 20, the code sleeps for 1, 2, 3, 5, 8, and 13 seconds for a total delay of 32 seconds before it failes. (The next sleep value would be 21, which exceeds the stall parameter.)

Description

A ring of processes connected by pipes is a very useful abstraction. Since modern (BSD and post SYSVr3) pipes are actually bi-directional the peers can send short messages "up stream" and long messages "down stream" to synchronize protocols and actions.

This is cool for double-buffered I/O, rendering of tiled data (such as maps, or video frames), or finite element analysis. Any problem that requires synchronization with a fixed, repeated order will fit the pipe-ring gang paradigm.

Scaling a ring when you find more processors on a host just makes the ring a little bigger, no code changes.

Provides

extern int PipeRing(int (*pfiTask)(), int iCount, void *pvData, int *piRet, char *pcStart);
This function builds the ring, forking Count child processes with pipes between them. The C function Task is declared (in detail) as
int (*pfiTask)(int iWorker, int iFdIn, int iFdOut, void *pvData);
Where FdIn is a descriptor on the "up stream" process, and FdOut is a descriptor on the "down stream" process. In the case where there is a gang-of-1 these are two ends of the same pipe. The Worker interger represents the workers position in the ring, it is an interger from 0 to (iCount-1).

The Data pointer is passed as a parameter to each worker as presented to the ring-builder. This could be a vector which might be indexed in the worker. It is strongly suggested that an explicit (void *)0 be passed if the parameter is unused in the Task function.

If the ring-build fails each Worker will see an EOF on the first read of the FdIn pipe. This only happens when the builder process ran out of resources (viz. pipes or processes). As a best practice, the Task code should send some token around the pipe ring (once) to be certian a stable gang has been established. This is why the Start string is injected into the ring by the builder, after a successful ring construction.

extern int PipePump(int iWorker, int fdIn, int fdOut, void *pvData);
An example function to "double buffer" stdin to stdout. If the Data pointer is not (void *)0 it must be a (int *) to the number of bytes to copy in each worker.

EXAMPLE

See the test driver embedded in the module, via:
explode -s pipering.h
explode pipering.c
more piperingtest.c

Diagnostics

None.

See Also

read(2), write(2), pipe(2), socketpair(2).

To Do List

None.
$Id: pipering.html,v 1.8 2012/03/21 16:15:05 ksb Exp $