PANIC! UNIX System Crash Dump Analysis Handbook (Bk/CD-ROM)

An individual Stream is composed of various pieces:

  • Stream head, which is the piece responsible for dealing with user requests via system calls. The Stream head supplies users with data from message blocks to satisfy their read requests and turns user writes into messages that are passed on down the Stream.

  • Device driver, which talks to the actual hardware and places/grabs data from queues. Some Streams talk to "pseudo-device" drivers, which just emulate the action of hardware (the pseudo-terminal driver, for instance).

  • Individual STREAMS modules, which filter and manipulate the data as it passes through the Stream.

The advantage of this approach is that the modules are essentially completely independent. You can arrange a Stream to do whatever kind of data processing you want by putting the appropriate modules into the Stream in the right order. There is a default set (for tty Streams), but user-level ioctl() calls can push any desired modules onto any Streams they own.

Here is a simple diagram of a Stream.

Figure 25-1. Stream diagram

User-level code will create the Stream initially by opening a STREAMS device. The user program can control and change the modules that are placed on the Stream as well as their order. The user program uses normal system calls to do this: ioctl() , write() , open () , close() , read() .

Note that all the pieces of a Stream live in kernel space: the driver, the Stream head, the queues, and the modules are all kernel text or data.

The "head" of the Stream is the connection to user space. Data coming from a user process and going to the driver (and probably eventually to a real device) is noted as coming downstream. The opposite direction is called, strangely enough, upstream.

Modules, drivers, and Stream heads have a queue for data going from one to the other in each direction. In other words, a queue connects modules (and the driver at one end, and the Stream head at the other). In between any two of these elements is a structure to handle the data being passed from one to the next one in the sequence. Each queue is essentially treated as a read "list" for the appropriate piece, and moving data from one Stream element to another involves putting data (messages) onto the read queue of the appropriate element. Thus, every module will have two queues associated with it: one for data going downstream, which is to be read and processed by this module; and another for data going upstream, which also must be handled. A module will also be able to pass data on to the next module's read queue once any filtering operation is done.

Категории