STREAMS Programming Guide

Exit Print View

Updated: July 2014
 
 

close Routine

The 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:

int prefix_close (queue *q, int flag, cred_t * cred_p)
q

is a pointer to the read queue of the module.

flag

is analogous to the oflag parameter of the open entry point. If FNBLOCK or FNDELAY is set, then the module should attempt to avoid blocking during the close.

cred_p

is a pointer to the user credential structure.

Like open, the close entry point has user context and can block. The blocking routines should return in the event of a signal. Device drivers must take into consideration that interrupts are not blocked during close.

close might be called in a context where a thread cannot receive signals, such as calling close during exit closure of open file descriptors. The system does not reawaken the thread when a user-level process attempts to send a signal, including SIGKILL, to the process.

Use ddi_can_receive_sig to determine whether a thread can receive user-level signals. ddi_can_receive_sig returns B_TRUE if the current thread can receive user-level signals, and B_FALSE if the thread cannot. In this case, qwait_sig behaves exactly like qwait. Use qtimeout or other facilities to prevent close from blocking indefinitely when a thread cannot receive signals.

In particular, asynchronous serial drivers should use caution when draining output data after calling close. Under most conditions, the driver must attempt to wait as long as possible to drain all output data and to discard the data only when a signal is received. However, if ddi_can_receive_sig returns B_FALSE and output flow control is asserted indefinitely by the peer, the driver must abort the drain operation after a reasonable time period has elapsed. Otherwise, the device could remain unusable until the next system boot.

The close routine must cancel all pending and qbufcall callbacks, and process any remaining messages on its service queue. In Example 7–2, 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  Example of a Module Close
/* example of a module close */
static int
xx_close(queue_t *, *rq, int flag, cred_t *credp)
{
		struct xxstr   *xxp;
  
   /*
    * Disable xxput() and xxsrv() procedures on this queue.
    */
		qprocsoff(rq);
		xxp = (struct xxstr *) rq->q_ptr;

   /*
    * Cancel any pending timeout.
    * This example assumes that the timeout was issued
    * against the write queue.
    */

		if (xxp->xx_timeoutid != 0) {
			(void) quntimeout(WR(rq), xxp->xx_timeoutid);
			xxp->xx_timeoutid=0;
    }
   /*
    * Cancel any pending bufcalls.
    * This example assumes that the bufcall was issued
    * against the write queue.
    */
		if (xxp->xx_bufcallid !=0) {
			(void) qunbufcall(WR(rq), xxp->xx_bufcallid);
 		xxp->xx_bufcallid = 0;
		}
		rq->q_ptr = WR(rq)->q_ptr = NULL;

   /*
    * Free resources allocated during open
    */
		kmem_free (xxp, sizeof (struct xxstr));
		return (0);
}

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 beginning 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.