STREAMS Programming Guide

The put Procedure

The put procedure passes messages from the queue of a module to the queue of the next module. The queue's put procedure is invoked by the preceding module to process a message immediately (see put(9F) and putnext(9F)). Almost all modules and drivers must have a put routine. The exception is that the read-side driver does not need a put routine because there can be no downstream component to call the put.

A driver's put procedure must do one of:

All M_IOCTL type messages must be acknowledged through M_IOACK or rejected through M_IOCNACK. M_IOCTL messages should not be freed. Drivers must free any unrecognized message.

A module's put procedure must do one of the following as shown in Example 7-3:

Unrecognized messages are passed to the next module or driver. The Stream operates more efficiently when messages are processed in the put procedure. Processing a message with the service procedure imposes some latency on the message.


Example 7-3 Flow of put Procedure

Graphic

If the next module is flow controlled (see canput(9F) and canputnext(9F)), the put procedure can queue the message for processing by the next service procedure (see putq(9F)). The put routine is always called before the component's corresponding srv(9E) service routine, so always use put for immediate message processing.

The preferred naming convention for a put procedure reflects the direction of the message flow. The read put procedure is suffixed by r (rput), and the write procedure by w (wput). For example, the read-side put procedure for module xx is declared as int xxrput (queue_t *q, mblk_t *mp). The write-side put procedure is declared as: int xxwput(queue_t *q, mblk_t *mp), where q points to the corresponding read or write queue and mp points to the message to be processed.

Although high-priority messages can be placed on the service queue, it is better to process them immediately in the put procedure. Place ordinary or priority-band messages on the service queue (putq(9F)) if:

If other messages already exist on the queue, and the put procedure does not queue new messages (provided they are not high-priority), messages are reordered. If the next module is flow controlled (see canput(9F) and canputnext(9F)). the put procedure can queue the message for processing by the service procedure (see putq(9F)).


/*example of a module put procedure */
int
xxrput(queue_t *,mblk_t, *mp)
{
   /*
    * If the message is a high-priority message or
    * the next module is not flow controlled and we have not
    * already deferred processing, then:
    */

    if (mp->b_datap->db_type >= QPCTL ||
             (canputnext(q) && q->q_first == NULL)) {
        /*
         * Process message
         */

         .
         .
         .
         putnext(q,mp);
    } else {
         /*
          * put message on service queue
          */
          putq(q,mp);
     }
     return (0);
}

A module need not process the message immediately, and can queue it for later processing by the service procedure (see putq(9F)).

The SunOS STREAMS framework is multithreaded. Unsafe (nonmultithreaded) modules are not supported. To make multithreading of modules easier, the SunOS STREAMS framework uses perimeters (see "MT STREAMS Perimeters" in Chapter 12, MultiThreaded STREAMS for information). Perimeters are a facility fore specifing that the framework provide exclusive access for the entire module, queue pair, or an individual queue. Perimeters make it easier to deal with multithreaded issues, such as message ordering and recursive locking.


Caution - Caution -

Mutex locks must not be held across a call to put(9F), putnext(9F), or qreply(9F).


Because of the asynchronous nature of STREAMS, don't assume that a module's put procedure has been called just because put(9F), putnext(9F), or qreply(9F) has returned.