Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
7.  STREAMS Framework - Kernel Level Entry Points Queue service Procedure  Previous   Contents   Next 
   
 

A service procedure usually processes all messages on its queue (getq(9F)) or takes appropriate action to ensure it is re-enabled (qenable(9F)) at a later time. Figure 7-11 shows the flow of a service procedure.


Caution - High-priority messages (db_type and MSG_HIPRI)must never be placed back on a service queue (putbq(9F)); this can cause an infinite loop.


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

Figure 7-11 Flow of service Procedure

Example 7-4 shows the stub code for a module service procedure.


Example 7-4 Module service Procedure

/*example of a module service procedure */
int
xxrsrv(queue_t *q)
{
		mblk_t *mp;
   /*
    * While there are still messages on our service queue
    */
		while ((mp = getq(q) != NULL) {
			/*
       * We check for high priority messages, but
       * none is ever seen since the put procedure
       * never queues them.
       * If the next module is not flow controlled, then
       */
      if (mp->b_datap->db_type >= QPCTL || (canputnext (q)) {
				/*
				 * process message
				 */
				.
				.
				.
				putnext (q, mp);
			} else {
				/*
          * put message back on service queue
          */
				putbq(q,mp);
				break;
			}
		}
		return (0);
}

qband Structure

The queue flow information for each band, other than band 0, is contained in a qband(9S) structure. This structure is not visible to other modules. For accessible information see strqget(9F) and strqset(9F). qband is defined as follows:

typedef struct qband {
		struct  qband    *qb_next;   /* next band's info */
		size_t  qb_count;            /* number of bytes in band */
		struct  msgb     *qb_first;  /* beginning of band's data */
		struct  msgb     *qb_last;   /* end of band's data */
		size_t  qb_hiwat;            /* high-water mark for band */
		size_t  qb_lowat;            /* low-water mark for band */
		uint    qb_flag;             /* see below */
} qband_t;

The structure contains pointers to the linked list of messages in the queue. These pointers, qb_first and qb_last, denote the beginning and end of messages for the particular band. The qb_count field is analogous to the queue's q_count field. However, qb_count only applies to the messages in the queue in the band of data flow represented by the corresponding qband structure. In contrast, q_count only contains information regarding normal and high-priority messages.

Each band has a separate high and low watermark, qb_hiwat and qb_lowat. These are initially set to the queue's q_hiwat and q_lowat respectively. Modules and drivers can change these values through the strqset(9F) function. The QB_FULL flag for qb_flag denotes that the particular band is full.

The qband(9S) structures are not preallocated per queue. Rather, they are allocated when a message with a priority greater than zero is placed in the queue using putq(9F), putbq(9F), or insq(9F). Since band allocation can fail, these routines return 0 on failure and 1 on success. Once a qband(9S) structure is allocated, it remains associated with the queue until the queue is freed. strqset(9F) and strqget(9F) cause qband(9S) allocation. Sending a message to a band causes all bands up to and including that one to be created.

Using qband Information

The STREAMS utility routines should be used when manipulating the fields in the queue and qband(9S) structures. strqget(9F) and strqset(9F) are used to access band information.

Drivers and modules can change the qb_hiwat and qb_lowat fields of the qband structure. Drivers and modules can only read the qb_count, qb_first, qb_last, and qb_flag fields of the qband structure. Only the fields listed previously can be referenced.


Caution - There are fields in the qband structure that are reserved and are not documented. These fields are subject to undocumented, unnotified change at any time.


Figure 7-12 shows a queue with two extra bands of flow.

Figure 7-12 Data Structure Linkage

Several routines are provided to aid you in controlling each priority band of data flow. These routines are

  • flushband(9F)

  • bcanputnext(9F)

  • strqget(9F)

  • strqset(9F)

flushband(9F) is discussed in "Flushing Priority Band". bcanputnext(9F) is discussed in "Flow Control in Service Procedures", and the other two routines are described in the following section. Appendix B, Kernel Utility Interface Summary also has a description of these routines.

Message Processing Procedures

Typically, put procedures are required in pushable modules, but service procedures are optional. If the put routine queues messages, a corresponding service routine must be present to handle the queued messages. If the put routine does not queue messages, the service routine is not required.

Figure 7-10 shows typical processing flow for a put procedure which works as follows:

  • A message is received by the put procedure associated with the queue, where some processing can be performed on the message.

  • The put procedure determines if the message can be sent to the next module by the use of canput(9F) or canputnext(9F).

  • If the next module is flow controlled, the put procedure queues the message using putq(9F).

  • putq(9F) places the message in the queue based on its priority.

  • Then, putq(9F) makes the queue ready for execution by the STREAMS scheduler, following all other queues currently scheduled.

  • If the next module is not flow controlled, the put procedure does any processing needed on the message and sends it to the next module using putnext(9F). Note that if the module does not have a service procedure it cannot queue the message, and must process and send the message to the next module.

Figure 7-11 shows typical processing flow for a service procedure that works as follows:

  • When the system goes from kernel mode to user mode, the STREAMS scheduler calls the service procedure.

  • The service procedure gets the first message (q_first) from the message queue using the getq(9F) utility.

  • The put procedure determines if the message can be sent to the next module using canput(9F) or canputnext(9F).

  • If the next module is flow controlled, the put procedure requeues the message with putbq(9F), and then returns.

  • If the next module is not flow controlled, the service procedure processes the message and passes it to the put procedure of the next queue with putnext(9F).

  • The service procedure gets the next message and processes it. This processing continues until the queue is empty or flow control blocks further processing. The service procedure returns to the caller.


Caution - A service or put procedure must never block since it has no user context. It must always return to its caller.


 
 
 
  Previous   Contents   Next