Part I Application Programming Interface
2. STREAMS Application-Level Components
3. STREAMS Application-Level Mechanisms
4. Application Access to the STREAMS Driver and Module Interfaces
7. STREAMS Framework - Kernel Level
Overview of Streams in Kernel Space
Sending and Receiving Messages
Message Queues and Message Priority
Flow Control in Service Procedures
8. STREAMS Kernel-Level Mechanisms
11. Configuring STREAMS Drivers and Modules
14. Debugging STREAMS-based Applications
B. Kernel Utility Interface Summary
The queue is the fundamental component of a stream. It is the interface between a STREAMS module and the rest of the stream, and is the repository for deferred message processing. For each instance of an open driver or pushed module or stream head, a pair of queues is allocated, one for the read side of the stream and one for the write side.
The RD(9F), WR(9F), and otherq(9F) routines allow reference of one queue from the other. Given a queue, RD(9F) returns a pointer to the read queue, WR(9F) returns a pointer to the write queue and otherq(9F) returns a pointer to the opposite queue of the pair (see queue(9S)).
By convention, queue pairs are depicted graphically as side- by-side blocks, with the write queue on the left and the read queue on the right (see following figure).
Figure 7-7 Queue Pair Allocation
As previously discussed, messages are ordered in message queues. Message queues, message priority, service procedures, and basic flow control all combine in STREAMS. A service procedure processes the messages in its queue. If there is no service procedure for a queue, putq(9F) does not schedule the queue to be run. The module developer must ensure that the messages in the queue are processed. Message priority and flow control are associated with message queues.
The queue structure is defined in stream.h as a typedef queue_t, and has the following public elements:
struct qinit *q_qinfo; /* procs and limits for queue */ struct msgb *q_first; /* first data block */ struct msgb *q_last; /* last data block */ struct queue *q_next; /* Q of next stream */ struct queue *q_link; /* to next Q for scheduling */ void *q_ptr; /* to private data structure */ size_t q_count; /* number of bytes on Q */ uint q_flag; /* queue state */ ssize_t q_minpsz; /* min packet size accepted by this module */ ssize_t q_maxpsz; /* max packet size accepted by this module */ size_t q_hiwat; /* queue high–water mark */ size_t q_lowat; /* queue low–water mark */
q_first points to the first message on the queue, and q_last points to the last message on the queue. q_count is used in flow control and contains the total number of bytes contained in normal and high-priority messages in band 0 of this queue. Each band is flow controlled individually and has its own count. For more details, see qband Structure. qsize(9F) can be used to determine the total number of messages on the queue. q_flag indicates the state of the queue. See Table 7-3 for the definitions of these flags.
q_minpsz contains the minimum packet size accepted by the queue, and q_maxpsz contains the maximum packet size accepted by the queue. These are suggested limits, and some implementations of STREAMS may not enforce them. The SunOS stream head enforces these values but they are voluntary at the module level. You should design modules to handle messages of any size.
q_hiwat indicates the limiting maximum number of bytes that can be put on a queue before flow control occurs. q_lowat indicates the lower limit where STREAMS flow control is released.
q_ptr is the element of the queue structure where modules can put values or pointers to data structures that are private to the module. This data can include any information required by the module for processing messages passed through the module, such as state information, module IDs, routing tables, and so on. Effectively, this element can be used any way the module or driver writer chooses. q_ptr can be accessed or changed directly by the driver, and is typically initialized in the open(9E) routine.
When a queue pair is allocated, streamtab initializes q_qinfo, and module_info initializes q_minpsz, q_maxpsz, q_hiwat, and q_lowat. Copying values from the module_info structure enables them to be changed in the queue without modifying the streamtab and module_info values.
The following table lists the queue(9S) flags.
Table 7-3 Queue Flags
|
The q_first, q_last, q_count, and q_flags components must not be modified by the module, and should be accessed using strqget(9F). The values of q_minpsz, q_maxpsz, q_hiwat, and q_lowat are accessed through strqget(9F), and are modified by strqset(9F). q_ptr can be accessed and modified by the module and contains data private to the module.
All other accesses to fields in the queue(9S) structure should be made through STREAMS utility routines (see Appendix B, “STREAMS Utilities”). Modules and drivers should not change any fields not explicitly listed previously.
strqget(9F) enables modules and drivers to get information about a queue or particular band of the queue. This insulates the STREAMS data structures from the modules and drivers. The prototype for the strqget(9F) routine is:
int strqget(queue_t *q, qfields_t what, unsigned char pri, void *valp)
q specifies from which queue the information is to be retrieved; what defines the queue_t field value to obtain (see the following structure fields). pri identifies a specific priority band. The value of the field is returned in valp. The fields that can be obtained are defined in <sys/stream.h> and shown here as:
QHIWAT /* high–water mark */ QLOWAT /* low–water mark */ QMAXPSZ /* largest packet accepted */ QMINPSZ /* smallest packet accepted */ QCOUNT /* approx. size (in bytes) of data */ QFIRST /* first message */ QLAST /* last message */ QFLAG /* status */
strqset(9F) enables modules and drivers to change information about a queue or a band of the queue. This also insulates the STREAMS data structures from the modules and drivers. Its prototype is:
int strqset(queue_t *q. qfields_t what, unsigned char pri, intptr_t val)
The q, what, and pri fields are the same as in strqget(9F), but the information to be updated is provided in val instead of through a pointer. If the field is read-only, EPERM is returned and the field is left unchanged. The following fields are read-only: QCOUNT, QFIRST, QLAST, and QFLAG.