![]() |
![]() |
| |||||||||
close RoutineThe close routine of devices is called only during the last close of the device. Module close routines are called during the last close or if the module is popped. The prototype for the close entry point is:
Like open, the close entry point has user context and can block. Likewise, the blocking routines should return in the event of a signal. Device drivers must take into consideration that interrupts are not blocked during close. The close routine must cancel all pending and qbufcall callbacks, and process any remaining messages on its service queue. The open and close procedures are only used on the read side of the queue and can be set to NULL in the write-side qinit structure initialization. Example 7-2 shows an example of a module close routine. Example 7-2 Example of a Module Close
qprocsoff does the inverse operation shown in Figure 7-9. This supports the need for cancelling callbacks before a qprocsoff. qprocsoff is typically called at the begining of the close routine. The module can no longer receive messages from adjoining modules. The queue, however, still has pointers to it's adjoining modules and can putnext. However, as the queue is no longer inserted into the stream, these messages may be out of order from other messages in the stream, so it is best to process these messages before qprocsoff. qwait is used because a module needs to get some response from another module or driver in the STREAM (i.e. a DLPI disconnect message sent downstream). qwait and qwait_sig must also be called before qprocsoff because once the queue is removed from the stream, there will be no way for the reply message to reach the queue. put ProcedureThe 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:
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:
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 ![]() 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:
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
| |||||||||
| |||||||||