Sun Microsystems Logo
Products and Services
 
Support and Training
 
 

Previous Previous     Contents     Index     Next Next

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.

Queue service Procedure

A queue's service procedure is invoked to process messages on the queue. It removes successive messages from the queue, processes them, and calls the put procedure of the next module in the stream to give the processed message to the next queue.

The service procedure is optional. A module or driver can use a service procedure for the following reasons:

  • Streams flow control is implemented by service procedures. If the next component on the stream has been flow controlled, the put procedure can queue the message. (See Flow Control in Service Procedures in Chapter 7, STREAMS Framework - Kernel Level for more on flow control.)

  • Resource allocation recovery. If a put or service procedure cannot allocate a resource, such as memory, the message is usually queued to process later.

  • A device driver can queue a message and get out of interrupt context.

  • To combine multiple messages into larger messages.

The service procedure is invoked by the STREAMS scheduler. A STREAMS service procedure is scheduled to run if:

  • The queue is not disabled (noenable(9F)) and the message being queued is either the first message on the queue, or a priority band message.

  • The message being queued (putq(9F) or putbq(9F)) is a high-priority message,

  • The queue has been back-enabled because flow control has been relieved,

  • The queue has been explicitly enabled (qenable(9F)).

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! 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

Flow diagram shows how the service procedure processes a message.

The following example 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! 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.


The following figure shows a queue with two extra bands of flow.

Figure 7-12 Data Structure Linkage

Diagram shows the data structure linkage of a queue with two extra bands of flow.

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)

Previous Previous     Contents     Index     Next Next