muxlrput receives messages from the linked stream. In this case, it is acting as a stream head and handles M_FLUSH messages. The code is the reverse of a driver, handling M_FLUSH messages from upstream. There is no need to flush the read queue because no data is ever placed in it.
muxlrput also handles M_ERROR and M_HANGUP messages. If one is received, it locks up the upper streams by setting muxerr.
M_DATA messages are routed by checking the first data byte of the message. This byte contains the minor device of the upper stream. Several checks examine whether:
The device is in range
The upper stream is open
The upper stream is full
This multiplexer does not support flow control on the read side; it is merely a router. If the message passes all checks, it is put to the proper upper queue. Otherwise, the message is discarded.
The upper stream close routine clears the mux entry so this queue will no longer be found. Outstanding bufcalls are not cleared.
/* * Upper queue close */ static int muxclose(queue_t *q, int flag, cred_t *credp) { struct mux *mux; mux = (struct mux *) q->q_ptr; qprocsoff(q); if (mux->bufcid != 0) unbufcall(mux->bufcid); mux->bufcid = 0; mux->ptr = NULL; q->q_ptr = NULL; WR(q)->q_ptr = NULL; return(0); } |
Persistent Links
Keeping a process running merely to hold the multiplexer configuration together is not always desirable, 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.
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.
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 driver and the second file descriptor, fd1, must reference the stream to be connected below the multiplexer. The persistent link can be created as follows:
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 */ exit(0); |
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 MUX driver and send data to Driver1 since the persistent link to Driver1 remains intact.
The I_PUNLINK ioctl(2) is used to dismantle the persistent link. Its format is:
ioctl(fd0, I_PUNLINK, muxid) |
where 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. I_PUNLINK removes the persistent link between the multiplexer referenced by 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 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); exit(0); |
Do not use the I_PLINK and I_PUNLINK ioctls with I_LINK and I_UNLINK. Any attempt to unlink a regular link with I_PUNLINK or to unlink a persistent link with the I_UNLINK ioctl(2) causes the errno value of EINVAL to be returned.
Because multilevel multiplexing configurations are allowed in STREAMS, persistent links could 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:
Creating a persistent link of multiplexer 2 below multiplexer 1
Closing the controlling file descriptor associated with the multiplexer 2
Reopening the file descriptor again
Linking the multiplexer 1 below the multiplexer 2
Design Guidelines
The following are general multiplexer design guidelines:
The upper half of the multiplexer acts like the end of the upper stream. The lower half of the multiplexer acts like the head of the lower stream. Service procedures are used for flow control.
Message routing is based on multiplexer-specific criteria.
When one stream is being fed by many streams, flow control may have to take place. Then all feeding streams on the other end of the multiplexer have to be enabled when the flow control is relieved.
When one stream is feeding many streams, flow control may also have to take place. Be careful not to starve other streams when one becomes flow controlled.
Upper and lower multiplexers share the same perimeter type and concurrency level. (See "MT STREAMS Perimeters" for information about perimeters.)