STREAMS/UX for the HP 9000 Reference Manual

90
STREAMS/UX Multiprocessor Support
Writing MP Scalable Modules and Drivers
spinlocks when calling some STREAMS/UX utilities. See Table 1 at the end of
this chapter for more information. See the SVR4.2 Driver manual for more
information about SVR4 MP hierarchies.
To reduce contention and improve performance, you should minimize the
amount of time that modules and drivers hold spinlocks.
To improve performance, modules and drivers should verify that they are actually
running on a multiprocessor system before calling the HP-UX native spinlock
primitives. The SVR4 MP LOCK and UNLOCK routines described in Chapter
3 do this for the caller. If a spinlock is being used only to protect against software
running on other processors, but not interrupts, modules or drivers can call the
MP_SPINLOCK and MP_SPINUNLOCK macros in /usr/include/sys/spinlock.h
(or /usr/conf/h/spinlock.h). These macros obtain only the requested spinlock if
they are executing on a multiprocessor system. If a spinlock is being used to
protect against both software running on other processors and interrupts, modules
and drivers should check the uniprocessor flag and raise the spl level if they are
running on a uniprocessor system. Example code is shown below.
if (uniprocessor)
x = splstr();
else
spinlock(mylock);
Be careful when choosing a multiplexor's synchronization level. When a driver
is linked under a mux, STREAMS/UX changes the driver's Stream head to be the
lower mux. STREAMS/UX uses the upper mux's synchronization level for the
lower mux. So if the upper mux uses global, elsewhere, or module
synchronization, the lower and upper muxes can share data. If the upper mux
uses queue or queue pair synchronization, the lower and upper muxes cannot
share data.
The synchronization level also influences how messages can be passed across
the mux. If the upper mux uses global, elsewhere, or module synchronization, it
can pass messages downward by passing the lower mux's write queue to putq,
put, or putnext. Likewise, the lower mux can pass messages upward by passing
the upper mux's read queue to putq, put, or putnext. If the upper mux uses queue
or queue pair synchronization, it can only use putq and put to pass messages to
the lower mux. To use putnext, the upper mux must ensure that the driver stays
linked under the mux until after the putnext completes. Also, the lower mux can
only use putq and put to pass messages to the upper mux. To use putnext, the
lower mux must guarantee that the driver stays linked under the mux, that the
mux stays open, and that modules are not pushed or popped until after the
putnext completes.