STREAMS Programming Guide

Flush 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 that can have values described in Table 8-1.

Table 8-1 M_FLUSH Arguments and bi_flag Values




Flush read side of Stream 


Flush write queue  


Flush both, read and write, queues 


Flush a specified priority band only 

Flushing 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 is used to indicate 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. In the figures, dotted boxes indicate flushed queues.

Figure 8-1 Flushing the Write-Side of a Stream


The following takes place (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


    The events taking place are:

  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 flush handling.

    static int
     	queue_t *q,						/* pointer to read/write queue */
     	mblk_t *mp)						/* pointer to message being passed */
     	switch (mp->b_datap->db_type) {
     			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 */

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.

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.

Note that modules and drivers are not required to treat messages as flowing in separate bands. Modules and drivers can view the queue 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.

One use of the field b_flag of the msgb structure is provided to give the Stream head a way 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


The set of STREAMS utilities available to drivers are listed in Appendix B, STREAMS Utilities. 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 system 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. It is intended that driver source code include a header file that picks up function declarations while the core operating system source includes 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. Since 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.