STREAMS Programming Guide

open Routine

The open routine of a device is called once for the initial open of the device, then is called again on subsequent reopens of the Stream. Module open routines are called once for the initial push onto the Stream and again on subsequent reopens of the Stream. See open(9E).

Figure 7-8 Order of a Module's open Procedure

Graphic

The Stream is analogous to a stack. Initially the driver is opened and, as modules are pushed onto the Stream, their open routines are invoked. Once the Stream is built, this order reverses if a reopen of the Stream occurs. For example, while building the Stream shown in Figure 7-8, device A's open routine is called, followed by B's and C's when they are pushed onto the Stream. If the Stream is reopened, Module C's open routine is called first, followed by B's, and finally by A's.

Usually the module or driver does not check this, but the issue is raised so that dependencies on the order of open routines are not introduced by the programmer. Note that although an open can happen more than once, close is only called once. See the next section on the close routine for more details. If a file is duplicated (dup(2)) the Stream is not reopened.

The syntax of the open entry point is:


int prefix open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *cred_p)

q -- Pointer to the read queue of this module.

devp -- Pointer to a device number that is always associated with the device at the end of the Stream. Modules cannot modify this value, but drivers can, as described in Chapter 9, STREAMS Drivers.

oflag -- For devices, oflag can contain the following bit mask values: FEXCL, FNDELAY, FREAD, and FWRITE. See Chapter 9, STREAMS Drivers for more information on drivers.

sflag -- When the open is associated with a driver, sflag is set to 0 or CLONEOPEN, see Chapter 9, STREAMS Drivers, "Cloning" for more details. If the open is associated with a module, sflag contains the value MODOPEN.

cred_p Pointer to the user credentials structure.

the open routines to devices are serialized (if more than one process attempts to open the device, only one proceeds and the others wait until the first finishes). Interrupts are not blocked during an open. So the driver's interrupt and open routines must allow for this. See Chapter 9, STREAMS Drivers for more information.

The open routines for both drivers and modules have user context. For example, they can do blocking operations, but the blocking routine should return in the event of a signal. In other words, q_wait_sig is allowed, but q_wait is not.

If the module or driver is to allocate a controlling terminal, it should send an M_SETOPTS message with SO_ISTTY set to the Stream head.

The open routine usually initializes the q_ptr member of the queue. q_ptr is generally initialized to some private data structure that contains various state information private to the module or driver. The module's close routine is responsible for freeing resources allocated by the module including q_ptr. Example 7-1 shows a simple open routine.


Example 7-1 A Simple open Routine

/* example of a module open */
int xx_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
{
	struct xxstr *xx_ptr;

	xx_ptr = kmemzalloc(sizeof(struct xxstr), KM_SLEEP);
	xx_ptr->xx_foo = 1;
	q->q_ptr = WR(q)->q_ptr = xx_ptr;
	qprocson(q);
	return (0);
}

In a multithreaded environment, data can flow up the Stream during the open. A module receiving this data before its open routine finishes initialization can panic. To eliminate this problem, modules and drivers are not linked into the Stream until qprocson(9F) is called. In other words, messages flow around the module until qprocson(9F) is called. Figure 7-9 illustrates this process.

Figure 7-9 Messages Flowing Around the Module Before qprocson

Graphic

The module or driver instance is guaranteed to be single-threaded before qprocson(9F) is called, except for interrupts or callbacks that must be handled separately. qprocson(9F) must be called before calling qbufcall(9F), qtimeout(9F), qwait(9F), or qwait_sig(9F) .