STREAMS Programming Guide

Persistent Links

With I_LINK and I_UNLINK ioctl(2) the file descriptor associated with the stream above the multiplexer used to set up the lower multiplexer connections must remain open for the duration of the configuration. Closing the file descriptor associated with the controlling stream dismantles the whole multiplexing configuration. It is not always desirable to keep a process running merely to hold the multiplexer configuration together, so, "free standing" links below a multiplexer are needed. A persistent link is such a link. It is similar to a STREAMS multiplexer link, except that a process is not needed to hold the links together. After the multiplexer has been set up, the process may close all file descriptors and exit, and the multiplexer remains intact.

Two ioctl(2)s, I_PLINK and I_PUNLINK, are used to create and remove persistent links that are associated with the stream above the multiplexer. close(2) and I_UNLINK are not able to disconnect the persistent links (see strconf(1) and strchg(1)).

The format of I_PLINK is:

ioctl(fd0, I_PLINK, fd1)

The first file descriptor, fd0, must reference the stream connected to the multiplexing drive,r and the second file descriptor, fd1, must reference the stream to be connected below the multiplexer. The persistent link can be created in the following way:

upper_stream_fd = open("/dev/mux", O_RDWR);
lower_stream_fd = open("/dev/driver", O_RDWR);
muxid = ioctl(upper_stream_fd, I_PLINK, lower_stream_fd);
 * save muxid in a file

The persistent link can still exist even if the file descriptor associated with the upper stream to the multiplexing driver is closed. The I_PLINK ioctl(2) returns an integer value, muxid, that can be used for dismantling the multiplexing configuration. If the process that created the persistent link still exists, it may pass the muxid value to some other process to dismantle the link, if the dismantling is desired, or it can leave the muxid value in a file so that other processes may find it later.

Several users can open the MUXdriver and send data to the Driver1 since the persistent link to the Driver1 remains intact.

The I_PUNLINK ioctl(2) is used to dismantle the persistent link. Its format is:

ioctl(fd0, I_PUNLINK, muxid)

where the fd0 is the file descriptor associated with stream connected to the multiplexing driver from above. The muxid is returned by the I_PLINK ioctl(2) for the stream that was connected below the multiplexer. The I_PUNLINK removes the persistent link between the multiplexer referenced by the fd0 and the stream to the driver designated by the muxid. Each of the bottom persistent links can be disconnected individually. An I_PUNLINK ioctl(2) with the muxid value of MUXID_ALL will remove all persistent links below the multiplexing driver referenced by the fd0.

The following code example shows how to dismantle the previously given configuration:

fd = open("/dev/mux", O_RDWR);
 * retrieve muxid from the file
ioctl(fd, I_PUNLINK, muxid);

Do not use the I_PLINK and I_PUNLINK ioctl(2) with the I_LINK and I_UNLINK. Any attempt to unlink a regular link with the I_PUNLINK or to unlink a persistent link with the I_UNLINK ioctl(2) causes the errno value of EINVAL to be returned.

Since multilevel multiplexing configurations are allowed in STREAMS, it is possible to have a situation where persistent links exist below a multiplexer whose stream is connected to the above multiplexer by regular links. Closing the file descriptor associated with the controlling stream will remove the regular link but not the persistent links below it. On the other hand, regular links are allowed to exist below a multiplexer whose stream is connected to the above multiplexer with persistent links. In this case, the regular links will be removed if the persistent link above is removed and no other references to the lower streams exist.

The construction of cycles is not allowed when creating links. A cycle could be constructed by:

This is not allowed. The operating system prevents a multiplexer configuration from containing a cycle to ensure that messages cannot be routed infinitely, thus creating an infinite loop or overflowing the kernel stack.