STREAMS Programming Guide

Driver Flush Handling

The write put procedure in Example 9-5, lpwput, illustrates driver M_FLUSH handling. Note that all drivers are expected to incorporate flush handling.

If FLUSHW is set, the write message queue is flushed, and (in this example) the leading message (lp->msg) is also flushed. lp_lock protects the driver's per-instance data structure.

In most drivers, if FLUSHR is set, the read queue is flushed. However, in this example, no messages are ever placed on the read queue, so it is not necessary to flush it. The FLUSHW bit is cleared and the message is sent upstream using qreply(9F). If FLUSHR is not set, the message is discarded.

The Stream head always performs the following actions on flush requests received on the read side from downstream. If FLUSHR is set, messages waiting to be sent to user space are flushed. If FLUSHW is set, the Stream head clears the FLUSHR bit and sends the M_FLUSH message downstream. In this manner, a single M_FLUSH message sent from the driver can reach all queues in a Stream. A module must send two M_FLUSH messages to have the same effect.

lpwput queues M_DATA and M_IOCTL messages and, if the device is not busy, starts output by calling lpout. Message types that are not recognized are discarded (in the default case of the switch).


Example 9-5

static int lpwput(
	queue_t *q,	/* write queue */
	mblk_t *mp)	/* message pointer */
{
	struct lp *lp;

	lp = (struct lp *)q->q_ptr;

	switch (mp->b_datap->db_type) {
	default:
		freemsg(mp);
		break;

	case M_FLUSH: /* Canonical flush handling */
		if (*mp->b_rptr & FLUSHW) {
			flushq(q, FLUSHDATA);
			mutex_enter(&lp->lp_lock); /* lock any access to lp */

			if (lp->msg) {
				freemsg(lp->msg);
				lp->msg = NULL;
			}

			mutex_exit(&lp->lp_lock);

		}

		if (*mp->b_rptr & FLUSHR) {
			*mp->b_rptr &= ~FLUSHW;
			qreply(q, mp);
		} else
			freemsg(mp);

		break;

	case M_IOCTL:
	case M_DATA:
		(void) putq(q, mp);
		mutex_enter(&lp->lp_lock);

		if (!(lp->flags & BUSY))
			lpout(lp);

		mutex_exit(&lp->lp_lock);

	}
	return (0);
}