Page: 1 2 3 4 5 6 7

Chapter 4


STREAMS Processing Routines

4.1 INTRODUCTION

The put and service procedures in the queue are routines that process messages as they transit the queue. The processing is generally performed according to the message type and can result in a modified message, new message(s), or no message. A resultant message, if any, is generally sent in the same direction in which it was received by the queue, but may be sent in either direction. Typically, each put procedure places messages on its queue as they arrive, for later processing by the service procedure.

A queue will always contain a put procedure and may also contain an associated service procedure. Having both a put and service procedure in a queue enables STREAMS to provide the rapid response and the queuing required in multiuser systems.

The service and put routines pointed at by a queue, and the queues themselves, are not associated with any process. These routines may not sleep if they cannot continue processing, but must instead return. Any information about the current status of the queue must be saved by the routine before returning.

Home



4.1.1 put Procedure

A put procedure is the queue routine that receives messages from the preceding queue in the Stream. Messages are passed between queues by a procedure in one queue calling the put procedure contained in the following queue. A call to the put procedure in the appropriate direction is the only way to pass messages between STREAMS components. There is usually a separate put procedure for the read and write queues because of the full-duplex operation of most Streams. However, there can be a single put procedure shared between both the read and write queues.

The put procedure allows rapid response to certain data and events, such as echoing of input characters. It has higher priority than any scheduled service procedure and is associated with immediate, as opposed to deferred, processing of a message.

The put procedure executes before the service procedure for any given message.

Each STREAMS component accesses the adjacent put procedure indirectly using the DDI functions (for example, putnext).

NOTE
Under no circumstances may a driver or module directly call other driver or module routines, including put and service routines. All calls are indirect.

For example, consider that modA, modB, and modC are three consecutive components in a Stream, with modC connected to the Stream head. If modA receives a message to be sent upstream, modA processes that message and calls modB's read put procedure, which processes it and calls modC's read put procedure, which in turn processes it and calls the Stream head's read put procedure. Thus, the message is passed along the Stream in one continuous processing sequence. This sequence completes the entire processing in a short time with low overhead (subroutine calls). On the other hand, if this sequence is lengthy and the processing is implemented on a multiuser system, then this way of processing may be good for this Stream but may be harmful for others. Streams may have to wait too long to get their turn, because each put procedure is called from the preceding one, and the kernel stack (or interrupt stack) grows with each function call. The possibility of running off the stack exists, causing a system panic or producing indeterminate results.

NOTE
Because STREAMS modules in general do not know which modules they are connected to, put routines cannot depend on a message being handled solely by put routines at the stream head or in the driver. Any modules along the Stream may choose to queue the message and process it with a service routine.

Home



4.1.2 service Procedure

In addition to the put procedure, a service procedure may be contained in each queue to allow deferred processing of messages. If a queue has both a put and a service procedure, message processing is generally divided between both procedures. The put procedure is always called first, from a preceding queue. After completing its part of the message processing, it arranges for the service procedure to be called by passing the message to the putq routine. putq does two things: it places the message on the message queue of the queue and schedules the queue service procedure for deferred execution. When putq returns to the put procedure, the procedure can return or continue to process messages. Some time later, the service procedure is automatically called by the STREAMS scheduler.

The STREAMS scheduler is separate and distinct from the UNIX system process scheduler. The scheduler calls each service procedure of the scheduled queues one at a time in a FIFO manner.

The scheduling of queue service routines is machine-dependent.

STREAMS utilities deliver the messages to the processing service routine in the FIFO sequence within each priority class (high priority, priority band, ordinary), because the service procedure is unaware of the message priority and simply receives the next message. The service routine receives control in the order it was scheduled. When the service routine receives control, it may encounter multiple messages on its message queue. This buildup can occur if there is a long interval between the time a message is queued by a put procedure and the time that the STREAMS scheduler calls the associated service routine. In this interval, multiple calls to the put procedure can cause multiple messages to build up. The service procedure always processes all messages on its message queue unless prevented by flow control.

Terminal output and input erase and kill processing, for example, it is typically performed in a service procedure because this type of processing does not have to be as timely as echoing. A service procedure also allows processing time to be more evenly spread among multiple STREAMS. As with the put procedure, there can be a separate service procedure for each queue in a STREAMS component or a single procedure used by both the read and write queues.

Home



4.2 ASYNCHRONOUS PROTOCOL

In the following example, the system supports different kinds of asynchronous terminals, each logging in on its own port. The port hardware is limited in function; for example, it detects and reports line and modem status, but does not check parity.

Communications software support for these terminals is provided using a STREAMS-based asynchronous protocol. The protocol includes a variety of options that are set when a user dials in to log on. The options are determined by a STREAMS user process, getstrm, which analyzes data sent to it through a series of dialogs (prompts and responses) between the process and the terminal user.

The process sets the terminal options for the duration of the connection by pushing modules onto the Stream or by sending control messages to cause changes in modules (or in the device driver) already on the Stream. The options supported include

These options are set with the following modules:
CHARPROC Provides input character processing functions, including dynamically settable (using control messages passed to the module) character echo and parity checking. The module's default settings are to echo characters and not check character parity.
CANONPROC Performs canonical processing on ASCII characters upstream and downstream (note that this performs some processing in a different way from the standard UNIX system character I/O tty subsystem).
ASCEBC Translates EBCDIC code to ASCII upstream and ASCII to EBCDIC downstream.
At system initialization, a user process, getstrm, is created for each tty port. getstrm opens a Stream to its port and pushes the CHARPROC module onto the Stream by an ioctl I_PUSH command. Then, the process issues a getmsg system call to the Stream and sleeps until a message reaches the Stream head. The Stream is now in its idle state.

The initial idle Stream, shown in Figure 4-1, contains only one pushable module, CHARPROC. The device driver is a limited function raw tty driver connected to a limited-function communication port. The driverand port transparently transmit and receive one unbuffered character at a time.

Figure 4-1 Idle Stream Configuration

After receiving initial input from a tty port, getstrm establishes a connection with the terminal, analyzes the option requests, verifies them, and issues STREAMS system calls to set the options. After setting up the options, getstrm creates a user application process. Later, when the user terminates that application, getstrm restores the Stream to its idle state by similar system calls.

Figure 4-2 Operational Stream

Home




As mentioned previously, the upstream queue is also referred to as the read queue reflecting the message flow direction. Correspondingly, downstream is referred to as the write queue.

4.2.1 Read-Side Processing

In our example, read-side processing consists of driver processing, CHARPROC processing, and CANONPROC processing.
4.2.1.1 DRIVER PROCESSING
The user process has been blocked on the getmsg(2) system call while waiting for a message to reach the Stream head, and the device driver independently waits for input of a character from the port hardware or for a message from upstream. After receiving an input character interrupt from the port, the driver places the associated character in an M_DATA message, allocated previously. Then, the driver sends the message to the CHARPROC module by calling CHARPROC's upstream put procedure. On return from CHARPROC, the driver calls the allocb utility routine to get another message for the next character.
4.2.1.2 CHARPROC
CHARPROC has both put and service procedures on its read-side. In the example, the other queues in the modules also have both procedures, as shown in Figure 4-3.

Home



Figure 4-3 Module put and service Procedures

When the driver calls CHARPROC's read queue put procedure, the procedure checks private data flags in the queue. In this example, the flags indicate that echoing is to be performed.

NOTE

Echoing is optional for this example and the port hardware cannot automatically echo.

CHARPROC causes the echo to be transmitted back to the terminal by first copying the message with a STREAMS utility routine. Then, CHARPROC uses another utility routine to obtain the address of its own write queue. Finally, the CHARPROC read put procedure uses another utility routine to call its write put procedure and pass it the message copy. The write procedure sends the message to the driver to effect the echo and then returns to the read procedure.

This part of read-side processing is implemented with put procedures so that the entire processing sequence occurs as an extension of the driver input character interrupt.

After returning from echo processing, the CHARPROC read put procedure checks another of its private data flags and determines that parity checking should be performed on the input character. Parity should most reasonably be checked as part of echo processing. However, for this example, parity is checked only when the characters are sent upstream. This relaxes the timing in which the checking must occur, that is, it can be deferred along with the canonical processing. CHARPROC uses putq to schedule the (original) message for parity check processing by its read service procedure. When the CHARPROC read service procedure is complete, it forwards the message to the read put procedure of CHARPROC . Note that if parity checking was not required, the CHARPROC put procedure would call the CHARPROC put procedure through the putnext routine.

Home



4.2.1.3 CANONPROC
CANONPROC performs canonical processing. As implemented, all read queue processing is performed in its service procedure so that CANONPROC's put procedure simply calls putq to schedule the message for its read service procedure and then exits. The service procedure extracts the character from the message buffer and places it in the line buffer contained in another M_DATA message it is constructing. Then, the message that contained the single character is returned to the buffer pool. If the character received was not an end-of-line, the service procedure returns. Otherwise, a complete line has been assembled and CANONPROC sends the message upstream to the Stream head that unblocks the user process from the getmsg(2) call and passes it the contents of the message.

4.2.2 Write-Side Processing

The write-side of this Stream carries two kinds of messages from the user process: ioctl messages for CHARPROC and M_DATA messages to be output to the terminal.

ioctl messages are sent downstream as a result of an ioctl(2) system call. When CHARPROC receives an ioctl message type, it processes the message contents to change internal flags and then uses a utility routine to send an acknowledgment message upstream to the Stream head. The Stream head acts on the acknowledgment message by unblocking the user from the ioctl.

For terminal output, it is presumed that M_DATA messages, sent by write(2) system calls, contain multiple characters. In general, STREAMS returns to the user process immediately after processing the write call so that the process may send additional messages. Flow control eventually blocks the sending process. The messages can queue on the write-side of the driver because of character transmission timing. When a message is received by the driver's write put procedure, the procedure uses putq to place the message on its write-side service message queue if the driver is currently transmitting a previous message buffer. However, there is generally no write queue service procedure in a device driver. Driver output interrupt processing takes the place of scheduling and performs the service procedure functions, removing messages from the queue.

4.2.3 Analysis

For reasons of efficiency, a module implementation would generally avoid placing one character per message and using separate routines to echo and parity check each character, as was done in this example. Nevertheless, even this design yields potential benefits. Consider a case where alternate, more intelligent, port hardware was substituted. If the hardware processed multiple input characters and performed the echo and parity checking functions of CHARPROC, then the new driver could be implemented to present the same interface as CHARPROC. Other modules such as CANONPROC could continue to be used without change.

Home

Contents Previous Chapter Next Chapter Index Glossary