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

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

ioctl Processing

Message Allocation and Freeing

Recovering From No Buffers

Read Device Interrupt Handler

Write Service Procedure

Releasing Callback Requests

Extended STREAMS Buffers

esballoc(9F) Example

General ioctl Processing

STREAMS ioctl Issues

I_STR ioctl Processing

Transparent ioctl

Transparent ioctl Messages

Transparent ioctl Examples

M_COPYIN Example

M_COPYOUT Example

Bidirectional Data Transfer Example

I_LIST ioctl(2)Example

M_FLUSH Message Handling

Flushing According to Priority Bands

Flushing Priority Band

Driver and Module Service Interfaces

Service Interface Library Example

Module Service Interface Example

Message Type Change Rules

Common ioctl Interfaces

FIORDCHK

FIONREAD

I_NREAD

signal Message

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

M_FLUSH Message Handling

All modules and drivers are expected to handle M_FLUSH messages. An M_FLUSH message can originate at the stream head or from a module or a driver. The user can cause data to be flushed from queued messages of a stream by submiting an I_FLUSH ioctl(2). Data can be flushed from the read side, write side, or both sides of a stream.

ioctl(fd,I_FLUSH, arg);

The first byte of the M_FLUSH message is an option flag. The following table describes the possible values for this flag.

Table 8-1 M_FLUSH Arguments and bi_flag Values

Flag
Description
FLUSHR
Flush read side of stream
FLUSHW
Flush write queue
FLUSHRW
Flush both, read and write, queues
FLUSHBAND
Flush a specified priority band only

Flushing According to Priority Bands

In addition to being able to flush all the data from a queue, a specific band can be flushed using the I_FLUSHBAND ioctl(2).

ioctl(fd, I_FLUSHBAND, bandp); 

The ioctl(2) is passed a pointer to a bandinfo structure. The bi_pri field indicates the band priority to be flushed (from 0 to 255). The bi_flag field indicates the type of flushing to be done. The legal values for bi_flag are defined in Table 8-1. bandinfo has the following format:

struct bandinfo {
        unsigned char       bi_pri;
        in                  bi_flag;
};

See M_FLUSH for details on how modules and drivers should handle flush band requests.

Figure 8-1 and Figure 8-2 further demonstrate flushing the entire stream due to a line break. Figure 8-1 shows the flushing of the write side of a stream, and Figure 8-2 shows the flushing of the read side of a stream.

Figure 8-1 Flushing the Write Side of a Stream

Diagram shows how the write side of a stream is flushed.

The following discussion describes the sequence of events shown in Figure 8-1 (dotted lines mean flushed queues):

  1. A break is detected by a driver.

  2. The driver generates an M_BREAK message and sends it upstream.

  3. The module translates the M_BREAK into an M_FLUSH message with FLUSHW set, then sends it upstream.

  4. The stream head does not flush the write queue (no messages are ever queued there).

  5. The stream head turns the message around (sends it down the write side).

  6. The module flushes its write queue.

  7. The message is passed downstream.

  8. The driver flushes its write queue and frees the message.

Figure 8-2 shows flushing the read side of a stream.

Figure 8-2 Flushing the Read Side of a Stream

Diagram shows how the read side of a stream is flushed.

The following discussion describes the sequence of events.

  1. After generating the first M_FLUSH message, the module generates an M_FLUSH with FLUSHR set and sends it downstream.

  2. The driver flushes its read queue.

  3. The driver turns the message around (sends it up the read side).

  4. The module flushes its read queue.

  5. The message is passed upstream.

  6. The stream head flushes the read queue and frees the message.

The following code shows line discipline module for flush handling.

Example 8-14 Line Discipline Module for Flush Handling

static int
ld_put(
     queue_t *q,                    /* pointer to read/write queue */
     mblk_t *mp)                    /* pointer to message being passed */
{
     switch (mp->b_datap->db_type) {
         default:
             putq(q, mp); /* queue everything */
            return (0);                     /* except flush */

         case M_FLUSH:
             if (*mp->b_rptr & FLUSHW)                  /* flush write q */
                     flushq(WR(q), FLUSHDATA);

             if (*mp->b_rptr & FLUSHR)                  /* flush read q */
                     flushq(RD(q), FLUSHDATA);

             putnext(q, mp);                              /* pass it on */
             return(0);
     }
}

The above example uses FLUSHDATA as the argument to flushq. This code will flush data type messages (M_DATA, M_DELAY, M_PROTO and M_PCPROTO) only. Flushing non-data messages, such as M_IOCTL, M_IOCACK, and M_IOCNAK, might flush messages that contain critical state in the stream. If an M_IOCACK message is flushed, a thread waiting at the stream head for a non-data message response will never receive it. Care should be taken when using flushq.

The stream head turns around the M_FLUSH message if FLUSHW is set (FLUSHR is cleared). A driver turns around M_FLUSH if FLUSHR is set (should mask off FLUSHW).

Flushing Priority Band

The bi_flag field is one of FLUSHR, FLUSHW, or FLUSHRW.

The following example shows flushing according to the priority band.

Example 8-15 Priority Band Data Flush Handling

queue_t *rdq;                                /* read queue */
queue_t *wrq;                                /* write queue */

    case M_FLUSH:
        if (*bp->b_rptr & FLUSHBAND) {
            if (*bp->b_rptr & FLUSHW)
                flushband(wrq, FLUSHDATA, *(bp->b_rptr + 1));
            if (*bp->b_rptr & FLUSHR)
                flushband(rdq, FLUSHDATA, *(bp->b_rptr + 1));
        } else {
            if (*bp->b_rptr & FLUSHW)
                flushq(wrq, FLUSHDATA);
            if (*bp->b_rptr & FLUSHR)
                flushq(rdq, FLUSHDATA);
        }
        /*
         * modules pass the message on;
         * drivers shut off FLUSHW and loop the message
         * up the read-side if FLUSHR is set; otherwise,
         * drivers free the message.
         */
        break;

Note that modules and drivers are not required to treat messages as flowing in separate bands. Modules and drivers can view the queue as having only two bands of flow, normal and high priority. However, the latter alternative flushes the entire queue whenever an M_FLUSH message is received.

The field b_flag of the msgb structure provides a way for the stream head to stop M_FLUSH messages from being reflected forever when the stream is used as a pipe. When the stream head receives an M_FLUSH message, it sets the MSGNOLOOP flag in the b_flag field before reflecting the message down the write side of the stream. If the stream head receives an M_FLUSH message with this flag set, the message is freed rather than reflected.

Figure 8-3 Interfaces Affecting Drivers

Diagram shows the interfaces used by a device driver to communicate with the kernel, the device, and the configuration software.

The set of STREAMS utilities available to drivers are listed in Appendix B, Kernel Utility Interface Summary. No system-defined macros that manipulate global kernel data or introduce structure-size dependencies are permitted in these utilities. So, some utilities that have been implemented as macros in the prior Solaris operating environment releases are implemented as functions in the SunOS 5 system. This does not preclude the existence of both macro and function versions of these utilities. Driver source code should include a header file that picks up function declarations while the core operating system source should include a header file that defines the macros. With the DKI interface, the following STREAMS utilities are implemented as C programming language functions: datamsg(9F), otherq(9F), putnext(9F), RD(9F), and WR(9F).

Replacing macros such as RD with function equivalents in the driver source code allows driver objects to be insulated from changes in the data structures and their size, increasing the useful lifetime of driver source code and objects. Multithreaded drivers are also protected against changes in implementation-specific STREAMS synchronization.

The DKI defines an interface suitable for drivers and there is no need for drivers to access global kernel data structures directly. The kernel function drv_getparm(9F) fetches information from these structures. This restriction has an important consequence. Because drivers are not permitted to access global kernel data structures directly, changes in the contents/offsets of information within these structures will not break objects.