JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
STREAMS Programming Guide
search filter icon
search icon

Document Information

Preface

Part I Application Programming Interface

1.  Overview of STREAMS

2.  STREAMS Application-Level Components

3.  STREAMS Application-Level Mechanisms

Message Handling

Modifying Messages

Message Types

Control of Stream Head Processing

Read Options

Write Options

Message Queueing and Priorities

Controlling Data Flow and Priorities

Accessing the Service Provider

Closing the Service Provider

Sending Data to the Service Provider

Receiving Data

Input and Output Polling

Synchronous Input and Output

Asynchronous Input and Output

signal Message

Extended Signals

Stream as a Controlling Terminal

Job Control

Allocation and Deallocation of Streams

Hungup Streams

Hangup Signals

Accessing the Controlling Terminal

4.  Application Access to the STREAMS Driver and Module Interfaces

5.  STREAMS Administration

6.  Pipes and Queues

Part II Kernel Interface

7.  STREAMS Framework - Kernel Level

8.  STREAMS Kernel-Level Mechanisms

9.  STREAMS Drivers

10.  STREAMS Modules

11.  Configuring STREAMS Drivers and Modules

12.  Multithreaded STREAMS

13.  STREAMS Multiplex Drivers

Part III Advanced Topics

14.  Debugging STREAMS-based Applications

Part IV Appendixes

A.  Message Types

B.  Kernel Utility Interface Summary

C.  STREAMS-Based Terminal Subsystem

D.  STREAMS FAQ

Glossary

Index

Input and Output Polling

This section describes the synchronous polling mechanism and asynchronous event notification in STREAMS.

User processes can efficiently monitor and control multiple streams with two system calls: poll(2) and the I_SETSIG ioctl(2) command. These calls enable a user process to detect events that occur at the stream head on one or more streams, including receipt of data or messages on the read queue and cessation of flow control on the write queue. Note that poll(2) is usable on any character device file descriptor, not just STREAMS.

To monitor streams with poll(2), a user process issues that system call and specifies the streams and other files to be monitored, the events to check, and the amount of time to wait for an event. poll(2) blocks the process until the time expires or until an event occurs. If an event occurs, it returns the type of event and the descriptor on which the event occurred.

Instead of waiting for an event to occur, a user process can monitor one or more streams while processing other data. To do so, issue the I_SETSIG ioctl(2), specifying a stream and events (as with poll(2)). This ioctl(2) does not block the process and force the user process to wait for the event, but returns immediately and issues a signal when an event occurs. The process calls one of sigaction(2), signal(3c), or sigset(3C) to catch the resulting SIGPOLL signal.

If any selected event occurs on any of the selected streams, STREAMS sends SIGPOLL to all associated requesting processes. The processes have no information on what event occurred on what stream. A signaled process can get more information by calling poll(2).

Synchronous Input and Output

poll(2) provides a mechanism to identify the 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 POLLIN, POLLRDNORM, POLLRDBAND, POLLPRI, POLLOUT, POLLWRNORM, POLLWRBAND, which are detailed in Table 3-3.

Table 3-3 Events That Can Be Polled

Event
Description
POLLIN
A message other than high-priority data can be read without blocking. This event is maintained for compatibility with the previous releases of the Solaris operating environment.
POLLRDNORM
A normal (nonpriority) message is at the front of the stream head read queue.
POLLRDBAND
A priority message (band > 0) is at the front of the stream head queue.
POLLPRI
A high-priority message is at the front of the stream head read queue.
POLLOUT
The normal priority band of the queue is writable (not flow controlled).
POLLWRNORM
The same as POLLOUT.
POLLWRBAND
A priority band greater than 0 of a queue downstream.

Some of the events may not be applicable to all file types. For example, the POLLPRI event usually is not generated when polling a non-STREAMS character device. POLLIN, POLLRDNORM, POLLRDBAND, and POLLPRI are set even if the message is of zero length.

poll(2) checks each file descriptor for the requested events and, on return, indicates which events have occurred for each file descriptor. If no event has occurred on any polled file descriptor, poll(2) blocks until a requested event or timeout occurs. poll(2) takes the following arguments:

Example 3-5 shows the use of poll(2). 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 arrive on either stream, data is read and then written back to the other stream.

Example 3-5 Polling

#include <sys/stropts.h>
#include <fcntl.h>
#include <poll.h>

#define NPOLL    2        /* number of file descriptors to poll */
int
main()
{
     struct pollfd pollfds[NPOLL];
     char buf[1024];
     int count, i;

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

The variable pollfds is declared as an array of the pollfd structure, defined in <poll.h>, and has the 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 shown below:

pollfds[0].events = POLLIN;    /* set events to poll */
pollfds[1].events = POLLIN;    /* for incoming data */
while (1) {
    /* poll and use -1 timeout (infinite) */
    if (poll(pollfds, NPOLL, -1) < 0) {
        perror("poll failed");
        exit(3);
    }
    for (i = 0; i < NPOLL; i++) {
        switch (pollfds[i].revents) {
            default:                        /* default error case */
                fprintf(stderr,"error event\n");
                exit(4);

            case 0:                        /* no events */
                break;

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

The user specifies the polled events by setting the events field of the pollfd structure to POLLIN. This request tells poll(2) 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 of poll(2) specifies the number of entries in the pollfds array (2 in this example). The third argument indicates the number of milliseconds poll(2) waits for an event if none has occurred. 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(2) returns immediately. Here, timeout is set to -1, specifying that poll(2) blocks until a requested event occurs or until the call is interrupted.

If poll(2) succeeds, the program checks 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, so all available 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. Table 3-4 shows poll error events.

Table 3-4 poll Error Events

Error
Description
POLLERR
A fatal error has occurred in a module or driver on the stream associated with the specified file descriptor. Further system calls fail.
POLLHUP
A hangup condition exists on the stream associated with the specified file descriptor. This event and POLLOUT are mutually exclusive; a stream is not writable if a hangup has occurred.
POLLNVAL
The specified file descriptor is not associated with an open stream.

These events cannot be polled for by the user but are reported in revents when they occur. 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, write(2) can block if the stream is exerting flow control. To prevent the process from blocking, the minor devices of the communications driver are opened with the O_NDELAY (or O_NONBLOCK) flag set, see note. write(2) cannot send all the data if flow control is on and O_NDELAY (O_NONBLOCK) is set. This can happen if the communications driver processes characters slower than the user transmits. If the stream becomes full, the number of bytes write(2) sends is 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 - To conform with the IEEE operating system interface standard, POSIX, new applications should use the O_NONBLOCK flag. Its behavior is the same as that of O_NDELAY unless otherwise noted.


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

Asynchronous Input and Output

poll(2) enables a user to monitor multiple streams synchronously. poll(2) normally blocks until an event occurs on any of the polled file descriptors. In some applications, however, you want to process incoming data asynchronously. For example, an application can attempt to do some local processing and be interrupted when a pending event occurs. Some time-critical applications must not block, and must have immediate success or failure indication.

The I_SETSIG ioctl(2) (see streamio(7I)) is used to request that a SIGPOLL signal be sent to a user process when a specific event occurs. Table 3-5 lists events for I_SETSIG. These are similar to those described for poll(2).

Table 3-5 I_SETSIG ioctl(2) Events

Event
Description
S_INPUT
A message other than a high-priority message has arrived on a stream head read queue. This event is maintained for compatibility with the previous releases of the Solaris operating environment.
S_RDNORM
A normal (nonpriority) message has arrived on the stream head read queue.
S_RDBAND
A priority message (band > 0) has arrived on the stream head read queue.
S_HIPRI
A high-priority message has arrived on the stream head read queue.
S_OUTPUT
A write queue for normal data (priority band = 0) is no longer full (not flow controlled). This notifies a user that there is space on the queue for sending or writing normal data downstream.
S_WRNORM
The same as S_OUTPUT.
S_WRBAND
A priority band greater than 0 of a queue downstream exists and is writable. This notifies a user that there is space on the queue for sending or writing priority data downstream.
S_MSG
A signal message sent from a module or driver has arrived on the stream head read queue.
S_ERROR
An error message reaches the stream head.
S_HANGUP
A hangup message sent from a module or driver has arrived at the stream head.
S_BANDURG
When used with S_RDBAND, SIGURG is generated instead of SIGPOLL when a priority message reaches the front of the stream head read queue.

S_INPUT, S_RDNORM, S_RDBAND, and S_HIPRI are set even if the message is of zero length. A user process can handle only high-priority messages by setting the arg to S_HIPRI.

signal Message

STREAMS enables modules and drivers to send a signal to user processes through a special signal message. If the signal specified by the module or driver is not SIGPOLL (see signal(3C)), the signal is sent to the process group associated with the stream. If the signal is SIGPOLL, the signal is only sent to processes that have registered for the signal by using the I_SETSIG ioctl(2).

Extended Signals

So that a process can obtain the band and event associated with SIGPOLL more readily, STREAMS supports extended signals. For the given events, a special code is defined in <sys/siginfo.h> that describes the reason SIGPOLL was generated. Table 3-6 describes the data available in the siginfo_t structure passed to the signal handler.

Table 3-6 Data in siginfo_t Structure

Event
si_signo
si_code
si_band
si_errno
S_INPUT

SIGPOLL
POLL_IN
Band readable
Unused
S_OUTPUT
SIGPOLL
POLL_OUT
Band writable
Unused
S_MSG
SIGPOLL
POLL_MSG
Band signaled
Unused
S_ERROR
SIGPOLL
POLL_ERR
Unused
stream error
S_HANGUP
SIGPOLL
POLL_HUP
Unused
Unused
S_HIPRI
SIGPOLL
POLL_PRI
Unused
Unused