• Keine Ergebnisse gefunden

QUEUEs and the kernel interface

Im Dokument sea UNIX Writing Drivers (Seite 195-200)

Line disciplines and serial device drivers

6.4 QUEUEs and the kernel interface

Each Stream module (including the Stream head and the Stream driver) consists of two QUEUEs. which are responsible for processing the downstream and upstream messages ~hat pass through a module.

A QUEUE has four principal components:

• One or more routines to procesS-the messages. A QUEUE must have at least an XXput routin~ that can be called to accept messages from other modules. It may also have an XXservice routine to carry out some or all of the message processing.

Additional, private routines can also "be provided for local use by the XXput and XXservice routines. For example, an XXioctl routine.

• A set of QUEUE attributes, including high and low water marks for the message queue.

• A message queue, containing the messages that are waiting to be processed by the QUEUE.

• Private data, used to manage the state of the module and the QUEUE. For example, a state transition look-up table.

6.4.1 The QUEUE structure

A QUEUE is defined by a struct queue (see (sys/stream.h)):

/* * The QUEUE structure

typedef struct queue queue_t;

I

QUEUEs and the kernel interface 179

Each module (including the Stream head and the Stream driver) has two QUEUES allocated automatically when the module is first opened.4

6.4.2 The kernel 'interface

The kernel interface to a Stream module (and therefore a Stream driver) is via the routines described by the struct qini t *q_info member of each QUEUE. A struct qinit defines the XXput, XXservice, XXopen, XXclose and XXadmin routines for the QUEUE, and also holds pointers to a struct module_info and an optional struct

struct module_info *qi-ffiinfo; /* module information structure */

struct module_stat *qi-ffistat; /* module statistics structure */

* module information structure

*/

I' f

QUEUE QUEUE QUEUE QUEUE

information information

CLqinfo p CLqinfo ~ p

qi_minfo - qi_minfo

-Module information

" " -JI'

Figure 6.9 A Stream module has two QUEUEs.

Figure 6.9 shows a typical Stream module with two QUEUEs. Note that the two QUEUEs share the same module information structure, and also the absence of a module statistics structure.

Figure 6.10 shows the same Stream module with some messages attached to each of the QUEUEs.

The XXput routine

A QUEUE's XXput routine is always required, and is called via the

putnext macro by another module's QUEUE (or the Stream head or Stream driver) to receive a message for processing:

xxput(q, mp)

queue_t *qi

mblk_t *mpi

The q parameter identifies the appropriate read or write QUEUE, and mp points to the message. Any immediate processing that is required should be performed by the XXput routine. In general, all priority

QUEUE

'Lfirst 'L1ast

QUEUE

information

QUEUEs and the kernel interface 181

QUEUE 'Lqinfo 'Lfirst 'L1ast

Messages

QUEUE

information

Messages

Figure 6.10 Message queues attached to module QUEUEs.

messages (see Section 6.3 above) should be processed immediately by XXput, and/or passed on to the next module. Ordinary messages can also be processed by XXput, although the module designer can provide an XXservice routine so that processing can be deferred.

After processing the message, both the xxput and XXservice routines should use putnext to pass the message to the adjacent module's xxput routine.

Therefore, depending on the design of each of the modules in a Stream, a message can flow all the way from the Stream head to the Stream driver (and vice versa) as an atomic operation. Figure 6.11 shows a message flowing downstream to a Stream driver via XXput routines.

There may be times when an XXput routine cannot immediately process the message. For example, a Stream driver's XXput routine may have to wait until a device's output buffer empties before it is able to transmit any more data. A Stream head may be receiving data from downstream, but there may not be any user processes making read(S) system calls. In both of these cases, it is clear that the

User process Stream head

Stream head calls Stream module's xxput Stream module

Stream driver

Device

User process Stream head

Stream module Stream module calls Stream driver's XXput

Stream driver

Device

Figure 6.11 A message flowing downstream.

User process Stream head

Stream module

Stream driver

Stream driver sends data to hardware Device

CJ)

;d ~

CJ)

QUEUEs and the kernel interface 183

messages must be queued in some way and the actual processing of the message must be deferred until later .

If the XXput routine is unable to process the message, it should call the putq routine to add the message to the QUEUE's own message queue. The putq routine also enables the corresponding QUEUE by adding it to the end of the STREAMS scheduling queue (see Section 6.5 below). After a short period, the STREAMS scheduler will call the QUEUE's XXservice routine to complete the processing.

The XXput routine should return as soon as putq returns.

The XXservice routine

The XXservice routine is responsible for the deferred processing of messages. An XXservice routine is not mandatory, and the module designer (or device driver writer) should determine whether to pro-vide an XXservice routine or not. Generally, if it is likely that XXput may not be able either to start or to complete the processing of a message, an XXservice routine must be provided.

When a QUEUE is enabled as described above, the STREAMS scheduler will call the QUEUE's XXservice routine at the next conven-ient opportunity:

XXservice(q) queue_t *q;

The q parameter identifies the appropriate read or write QUEUE. The XXservice routine should retrieve the first message from the message queue using the getq routine, process the message and then pass it on to the next module, using putnext. XXservice should repeat these steps until either the queue is empty, or flow control prevents any more messages being passed to the next module.

It is important to note that XXput and XXservice routines do not always run in a valid user context. This is a side-effect of the STREAMS scheduling mechanism, and means that the same care must be taken as when writing interrupt routines:

• Never access any context-related data, such as the U-area, or any part of the user's address space.

• Never go to sleep (K) inside an XXput or XXservice routine.

• Always return to the caller.

Flow control is discussed in Section 6.5 below.

The STREAMS loopback driver in Section 6.10 includes an XXservice routine.

Im Dokument sea UNIX Writing Drivers (Seite 195-200)