STREAMS Programming Guide

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.