STREAMS polling and multiplexing

Synchronous input/output

The poll system call provides a mechanism to identify those Streams over which a user can send or receive data. For each Stream of interest, users can specify one or more events about which they should be notified. The types of events that can be polled are as follows:

A message other than an M_PCPROTO is at the front of the Stream head read queue. This event is maintained for compatibility with the previous releases of the UNIX System V.

A normal (nonpriority) message is at the front of the Stream head read queue.

A priority message (band > 0) is at the front of the Stream head queue.

A high-priority message (M_PCPROTO) is at the front of the Stream head read queue.

The normal priority band of the queue is writable (not flow controlled).

The same as POLLOUT.

A priority band greater than 0 of a queue downstream exists and is writable.

Some of the events may not be applicable to all file types. For example, it is not expected that the POLLPRI event will be generated when polling a regular file. POLLIN, POLLRDNORM, POLLRDBAND, and POLLPRI are set even if the message is of zero length.

The poll system call examines each file descriptor for the requested events and, on return, shows which events have occurred for each file descriptor. If no event has occurred on any polled file descriptor, poll blocks until a requested event or timeout occurs. poll takes the following arguments:

The following example shows the use of poll. Two separate minor devices of the communications driver are opened, thereby establishing two separate Streams to the driver. The pollfd entry is initialized for each device. Each Stream is polled for incoming data. If data arrives on either Stream, it is read and then written back to the other Stream.

#include <fcntl.h>
#include <poll.h>

#define NPOLL 2 /* number of file descriptors to poll */

main() { struct pollfd pollfds[NPOLL]; char buf[1024]; int count, i;

if ((pollfds[0].fd = open("/dev/comm/01", O_RDWR|O_NDELAY)) < 0) { perror("open failed for /dev/comm/01"); exit(1); }

if ((pollfds[1].fd = open("/dev/comm/02", O_RDWR|O_NDELAY)) < 0) { perror("open failed for /dev/comm/02"); exit(2); }

The variable pollfds is declared as an array of the pollfd structure that is defined in <poll.h> and has the following format:

   struct pollfd {
   	int		fd;			/* file descriptor */
   	short	events;		/* requested events */
   	short	revents;	/* returned events */

For each entry in the array, fd specifies the file descriptor to be polled and events is a bitmask that contains the bitwise inclusive OR of events to be polled on that file descriptor. On return, the revents bitmask indicates which of the requested events has occurred.

The example continues to process incoming data as follows:

	pollfds[0].events = POLLIN;	/* set events to poll */
	pollfds[1].events = POLLIN;	/* for incoming data */
	pollfds[0].revents = 0;
	pollfds[1].revents = 0;
	while (1) {
		/* poll and use -1 timeout (infinite) */
		if (poll(pollfds, NPOLL, -1) < 0) {
			perror("poll failed");
		for (i = 0; i < NPOLL; i++) {
			switch (pollfds[i].revents) {

case 0: /* no events */ break;

case POLLIN: /* echo incoming data on "other" Stream */ while ((count = read(pollfds[i].fd, buf, 1024)) > 0) /* * the write loses data if flow control * prevents the transmit at this time. */ if (write(pollfds[(i+1)%2].fd, buf, count) != count) fprintf(stderr,"writer lost data\n"); pollfds[i].revents = 0; break;

default: /* default error case */ perror("error event"); exit(4); } } } }

The user specifies the polled events by setting the events field of the pollfd structure to POLLIN. This requested event directs poll to notify the user of any incoming data on each Stream. The bulk of the example is an infinite loop, where each iteration polls both Streams for incoming data.

The second argument to the poll system call specifies the number of entries in the pollfds array (2 in this example). The third argument is a timeout value indicating the number of milliseconds poll should wait for an event if none occurs. On a system where millisecond accuracy is not available, timeout is rounded up to the nearest value available on that system. If the value of timeout is 0, poll returns immediately. Here, the value of timeout is -1, specifying that poll should block until a requested event occurs or until the call is interrupted.

If the poll call succeeds, the program looks at each entry in the pollfds array. If revents is set to 0, no event has occurred on that file descriptor. If revents is set to POLLIN, incoming data is available. In this case, all data is read from the polled minor device and written to the other minor device.

If revents is set to a value other than 0 or POLLIN, an error event must have occurred on that Stream, because POLLIN was the only requested event. The following are poll error events:

A fatal error has occurred in some module or driver on the Stream associated with the specified file descriptor. Further system calls will fail.

A hangup condition exists on the Stream associated with the specified file descriptor. This event and POLLOUT are mutually exclusive; a Stream cannot be writable if a hangup has occurred.

The specified file descriptor is not valid

These events may not be polled by the user, but will be reported in revents whenever they occur. As such, they are only valid in the revents bitmask.

The example attempts to process incoming data as quickly as possible. However, when writing data to a Stream, the write call may block if the Stream is exerting flow control. To prevent the process from blocking, the minor devices of the communications driver were opened with the O_NDELAY (or O_NONBLOCK, see note) flag set. The write will not be able to send all the data if flow control is exerted and O_NDELAY (O_NONBLOCK) is set. This can occur if the communications driver is unable to keep up with the user's rate of data transmission. If the Stream becomes full, the number of bytes the write sends will be less than the requested count. For simplicity, the example ignores the data if the Stream becomes full, and a warning is printed to stderr.

NOTE: For conformance with the IEEE operating system interface standard, POSIX, it is recommended that new applications use the O_NONBLOCK flag, which behaves the same as O_NDELAY unless otherwise noted.

This program continues until an error occurs on a Stream, or until the process is interrupted.

Next topic: Asynchronous input/output
Previous topic: STREAMS input/output polling

© 2004 The SCO Group, Inc. All rights reserved.
UnixWare 7 Release 7.1.4 - 27 April 2004