STREAMS Programming Guide

Exit Print View

Updated: July 2014
 
 

put Procedure

The put procedure is the mechanism that other modules use to pass messages into this module. This procedure is called via the putor putnext routines on behalf of other modules. The queue's put procedure is invoked by the preceding module to process a message immediately (see put(9F) and putnext(9F)). Most modules will have a put routine. The common exception is on the read-side of drivers because there will not typically be a module downstream to the driver.


Note - Hardening Information. putnext is used by adjoining modules to ensure that the next module's queue is intact. Use of put cannot guarantee that the queue being called is currently valid and inserted into a stream; you must ensure that the queue is valid when using put.

A driver's put procedure must do one of the following:

  • Process and free the message.

  • Process and route the message back upstream.

  • Queue the message to be processed by the driver's service procedure.

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 Figure 7–10:

  • Process and free the message.

  • Process the message and pass it to the next module or driver.

  • Queue the message to be processed later by the module's service procedure.

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.

Figure 7-10  Flow of put Procedure

image:Flow diagram shows how a module processes messages using the put procedure.

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.


Note - Hardening Information. canput and canputnext operate similar to put and putnext; that is the next functions verify the integrity of the next queue. Not using the next functions can cause panics as the queue being referenced might have already been closed.

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, processing them immediately in the put procedure is better. (See the stub code in Example 7–3.) Place ordinary or priority-band messages on the service queue (putq(9F)) if:

  • The stream has been flow controlled; that is, canput fails.

  • There are already messages on the service queue, that is, q_first is not NULL.

  • Deferred processing is desired.

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 7-3  Example of a Module put Procedure
/*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);
}

Put procedures must never call putq, putbq, or qenable if the module does not have a service procedure.


Note - Hardening Information. Once a message is passed using a putq, put, putnext, as well as the perimeter function qwriter, it cannot be accessed again because the use of this message has been given to the new routine. If a reference needs to be retained by the module, it should copy it by using copyb, copymsg, dupb, or dupmsg.

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 for more information).


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, do not assume that a module's put procedure has been called just because put(9F), putnext(9F), or qreply(9F) has returned.