HPlogo STREAMS/UX for the HP 9000 Reference Manual > Chapter 3 Differences Between STREAMS/UX and System V Release 4 STREAMS

HP-UX Modifications to STREAMS/UX Utilities

» 

Technical documentation

Complete book in PDF

 » Table of Contents

 » Index

STREAMS/UX supports the following kernel utilities described in the SVR4.2 Driver manual, although some of the utilities have been modified for HP-UX.

adjmsg

allocb

backq

bcanput

bcanputnext

bcopy

bufcall

bzero

canput

canputnext

cmn_err

copyb

copymsg

datamsg

delay

drv_getparm

drv_priv

dupb

dupmsg

enableok

esballoc

esbbcall

flushband

flushq

freeb

freemsg

freezestr

getadmin

getmid

getmajor

getminor

getq

insq

itimeout

kmem_alloc

kmem_free

linkb

LOCK

LOCK_ALLOC

LOCK_DEALLOC

major

makedev

makedevice

max

min

minor

msgdsize

msgppullup

noenable

OTHERQ

pcmsg

pullupmsg

put

putbq

putctl

putctl1

putnext

putnextctl

putnextctl1

putq

qenable

qprocsoff

qprocon

qreply

qsize

RD

rmvb

rmvq

SAMESTR

sleep

spln

splstr

strlog

strqget

strqset

SV_ALLOC

SV_BROADCAST

SV_DEALLOC

SV_WAIT

SV_WAIT_SIG

testb

timeout

TRYLOCK

unbufcall

unfreezestr

unlinkb

UNLOCK

untimeout

vtop

wakeup

WR

In addition, HP-UX provides the following new utilities.

get_sleep_lock 
putctl2
putnextctl2
streams_put
unweldq
weldq

The strenv.h file redefines some native HP-UX kernel utilities to conform to System V Release 4.2. The strenv.h file redefines delay, get_sleep_lock, kmem_alloc, kmem_free, lbolt, max, min, sleep, time, timeout, and untimeout. These defines might collide with declarations in STREAMS/UX modules and drivers. You can customize the strenv.h file to avoid collisions or to use native HP-UX utilities. However, modules and drivers cannot call the native HP-UX sleep or get_sleep_lock directly. If your modules and drivers call sleep or get_sleep_lock, you must include strenv.h to redefine sleep and get_sleep_lock to streams_mpsleep and streams_get_sleep_lock. For more information about the native HP-UX primitives, see the HP-UX Driver Development Guide, part number 98577-90014.

Differences between the STREAMS/UX kernel utilities and the descriptions in the SVR4.2 Driver manual are discussed below, along with information about new utilities. This section assumes that modules and drivers include strenv.h.

esballoc

The STREAMS/UX esballoc is the same as the esballoc call described in the SVR4.2 Driver manual with a few differences. The HP-UX esballoc copies the contents of the fr_rtn structure into an area of the data block not visible to the STREAMS/UX programmer. Then esballoc stores a pointer to this area in the db_freep field. This allows modules and drivers to modify the fr_rtn parameter after calling esballoc without affecting subsequent freeb calls. Also, modules and drivers can change a data block's fr_rtn information by modifying the structure pointed to by db_freep. The free routine passed to esballoc can call STREAMS/UX utilities in the same way as the put or service routine that called freeb. Also, a free routine can safely access the same data structures as the put or service routine that called freeb. However, unlike SVR4.2, HP-UX does not block interrupts from all STREAMS/UX devices while the free routine runs. See "STREAMS/UX Uniprocessor Synchronization" in this chapter and "Writing MP Scalable Modules and Drivers" in Chapter 4 for more information about esballoc free routines.

cmn_err

The STREAMS/UX cmn_err is the same as the cmn_err described in the SVR4.2 Driver manual with a few differences. The HP-UX cmn_err always sends messages to both the system console and the circular kernel buffer. Inserting an exclamation point ("!") or a circumflex ("^") as the first character in the format string has no effect. HP-UX simply removes these control characters from the message, and sends the message to both the console and the kernel buffer. There are a couple of other very minor differences. HP-UX precedes CE_PANIC level messages with the string panic: instead of PANIC:. Also, the HP-UX circular kernel buffer is called msgbuf instead of putbuf. The HP-UX msgbuf is a fixed size, and can be viewed using the dmesg command or the adb debugger tool.

freezestr and unfreezestr

The SVR4.2 Driver manual says that freezestr and unfreezestr must be called on multiprocessors to protect searching a STREAMS/UX queue and calling insq, rmvq, strqset, and strqget. SVR4 MP provides freezestr and unfreezestr to prevent software on multiple processors from manipulating a queue's list of messages at the same time. STREAMS/UX uses synchronization levels for this. See "Writing MP Scalable Modules and Drivers" in Chapter 4 for more information about synchronization levels and HP-UX limitations on insq, rmvq, strqset, and strqget. Because STREAMS/UX uses a different mechanism to protect STREAMS/UX queues, the HP-UX freezestr just returns the current interrupt priority level, and unfreezestr is a no-op. HP-UX provides the freezestr and unfreezestr stubs to make porting code from SVR4 MP easier.

get_sleep_lock

STREAMS/UX provides some extra support for modules and drivers which use the native HP-UX get_sleep_lock primitive. Alternatively, modules and drivers can call the SVR4 MP SV_WAIT and SV_WAIT_SIG. Open and close routines call get_sleep_lock before sleeping to prevent missing wakeups. After calling get_sleep_lock, the open or close can release spinlocks before sleeping. Other processes cannot wakeup the open or close between the time it calls get_sleep_lock and sleep. Modules and drivers must include strenv.h to use get_sleep_lock. strenv.h redefines get_sleep_lock to streams_get_sleep_lock. Modules and drivers cannot call the native HP-UX get_sleep_lock directly, because STREAMS/UX needs to do some additional synchronization before invoking get_sleep_lock.

lock_t *
get_sleep_lock(event);

caddr_t event;

The open or close routine passes the event it will pass to the sleep primitive to get_sleep_lock. get_sleep_lock obtains a sleep spinlock, and returns a pointer to this lock.

itimeout

If the HP-UX itmeout cannot allocate memory, it panics instead of returning 0 like the SVR4 MP itimeout. The STREAMS/UX itimeout only returns 0 if it is passed an interrupt priority level that is lower than pltimeout. You can increase the amount of memory available to both the new itimeout and the existing timeout primitives using the NCALLOUT tunable. Set NCALLOUT to the maximum number of itimeout and timeout requests that can be outstanding at any one time.

kmem_alloc

The STREAMS/UX kmem_alloc tries to allocate 32 bytes if the size parameter is set to 0. The SVR4.2 kmem_alloc returns NULL instead.

LOCK

The STREAMS/UX LOCK calls the native HP-UX spinlock primitive. LOCK has an interrupt priority level parameter, which is used to raise the priority level and block interrupts which acquire the spinlock. The SVR4.2 Driver manual says that implementations which do not need to raise the interrupt level can ignore this parameter. Since the HP-UX spinlock primitive always raises the interrupt level to spl6 while a spinlock is held, STREAMS/UX ignores the interrupt level parameter on multiprocessor systems. For better performance on uniprocessor systems, the STREAMS/UX LOCK raises the priority level to the parameter value instead of acquiring a spinlock. Whether the caller will block or spin if the lock cannot be obtained is implementation defined. The HP-UX implementation spins.

LOCK_ALLOC

The STREAMS/UX LOCK_ALLOC calls the native HP-UX alloc_spinlock primitive. There are some small differences between the STREAMS/UX LOCK_ALLOC and the SVR4 MP utility. LOCK_ALLOC has a flag parameter which indicates if the caller is willing to block while waiting for memory to be allocated. HP-UX only allows this flag to be set to KM_SLEEP, and returns zero if it is set to KM_NOSLEEP. The STREAMS/UX LOCK_ALLOC accepts the following hierarchy parameter values which are reserved for STREAMS/UX modules and drivers in /usr/include/sys/semglobal.h and /usr/conf/h/semglobal.h: STREAMS_USR1_LOCK_ORDER, STREAMS_USR2_LOCK_ORDER, and STREAMS_USR3_LOCK_ORDER. The compiler options to turn on deadlock checking for HP-UX are different than those documented in the SVR4.2 Driver manual. The entire HP-UX kernel and the module or driver must be compiled with SEMAPHORE_DEBUG to enable deadlock checking. According to the SVR4.2 Driver manual, the min_pl parameter can be ignored by implementations which do not need to raise the priority level. The HP-UX STREAMS LOCK_ALLOC ignores it.

putctl2

STREAMS/UX also provides the additional utility called putctl2. This utility can be used to send a control message with a two-byte parameter to a queue. For example, putctl2 can send the new style of an M_ERROR message, which is two bytes long, to a queue.

int putctl2(q, type, p1, p2);

queue_t * q;
int type;
int p1;
int p2;

The q parameter is the queue to which the message is sent. The type parameter is the message type. The p1 and p2 parameters are the two bytes of data in the message. The putctl2 utility ensures that the type is not a data type. The utility also allocates a message block, fills in the data, and calls the put routine of the specified queue. putctl2 returns 0 if the type is M_DATA, M_PROTO or M_PCPROTO, or if a message block cannot be allocated. putctl2 returns 1 if it completes successfully.

putnextctl2

STREAMS/UX provides the additional utility putnextctl2. This utility can be used to send a control message with a two-byte parameter to the next queue in a stream. For example, putnextctl2 can send the new style of an M_ERROR message, which is two bytes long, to the next queue in a stream.

int putnextctl2(q, type, p1, p2); 

queue_t * q;
int type;
int p1;
int p2;

The q parameter is the queue from which the message is sent. The message is sent to q->q_next. The type parameter is the message type. The p1 and p2 parameters are the two bytes of data in the message. The putnextctl2 utility ensures that the type is not a data type. The utility also allocates a message block, fills in the data, and calls the put routine of q->q_next. putnextctl2 returns 0 if the type is M_DATA, M_PROTO, or M_PCPROTO, or if a message block cannot be allocated. putnextctl2 returns 1 if it completes successfully.

qprocson and qprocsoff

SVR4 MP STREAMS/UX provides qprocson and qprocsoff, which on a multiprocessor system allows a module's put and service routines to run concurrently with open and close. STREAMS/UX does not allow this much parallelism. A module's or driver's put and service routines cannot run at the same time as the open or close. Although STREAMS/UX does not run the put or service routine in parallel with the open or close, it does queue any requests to run the put or service routine. STREAMS/UX will process these when open finishes. Also, if open or close sleeps, STREAMS/UX can run the put and service routines while open or close are sleeping. However, a put or service routine cannot do the wakeup on a sleeping open or close. STREAMS/UX provides stubs which are no-ops for qprocson and qprocsoff to make porting easier.

streams_put utilities

STREAMS/UX provides a new utility streams_put, which allows non-STREAMS/UX software to safely call STREAMS/UX utilities. timeout and bufcall user functions and other non-STREAMS/UX code cannot call several of the STREAMS/UX utilities or share data with modules and drivers. For a more detailed discussion about these restrictions, see "STREAMS/UX Uniprocessor Synchronization" in this chapter and "Writing MP Scalable Modules and Drivers" in Chapter 4.

Non-STREAMS/UX code can call streams_put, passing it a function and a queue. STREAMS/UX runs the function as if it were the queue's put routine. The function can safely manipulate the queue and access the same data structures as the queue's put routine.

#ifdef _PROTOTYPES
typedef void (*streams_put_t)(void *, MBPKP);
#else
typedef void (*streams_put_t)();
#endif

void
streams_put(func, q, mp, private)
streams_put_t func;
queue_t *q;
mblk_t *mp;
void *private;

STREAMS/UX will run func as if it were q's put routine. STREAMS/UX passes private and mp to func. The non-STREAMS/UX code can pass any value in the private parameter. The code must pass a valid message block pointer in mp. streams_put uses fields in the message block not visible to the STREAMS/UX programmer.

SV_WAIT

STREAMS/UX implements a subset of the SVR4 MP synchronization variable utilities using sleep and wakeup. The HP-UX SV_WAIT differs from the SVR4 MP utility in the following ways. When the SVR4 MP SV_WAIT returns, the lkp spinlock is not held, and the priority level is set to plbase (SPLNOPREEMPT on HP-UX). On a multiprocessor system, the HP-UX SV_WAIT lowers the priority level to the value before the caller acquired the lkp spinlock, which may not be SPLNOPREEMPT. If the caller acquired the lock while holding other spinlocks, the priority level is lowered to the value before the first of these nested spinlock calls. Also, the SVR4 MP SV_WAIT has a priority argument that specifies the priority the caller would like to run at after waking. Since the HP-UX SV_WAIT is implemented by calling sleep, the HP-UX priorities are different than the SVR4 MP ones. On HP-UX, the priority passed into SV_WAIT is subtracted from PZERO-1. pridisk, prinet, pritty, pritape, prihi, primed, and prilo are defined to be 0, and do not affect the caller's priority. If you need to change the process's priority, study the priorities in /usr/include/sys/param.h or /usr/conf/h/param.h, and pass the needed offset to PZERO-1 in the priority parameter.

SV_WAIT_SIG

STREAMS/UX implements a subset of the SVR4 MP synchronization variable utilities using sleep and wakeup. The HP-UX SV_WAIT_SIG differs from the SVR4 MP utility in the following ways. When the SVR4 MP SV_WAIT_SIG returns, the lkp spinlock is not held, and the priority level is set to plbase (SPLNOPREEMPT on HP-UX). On a multiprocessor system, the HP-UX SV_WAIT_SIG lowers the priority level to the value before the caller acquired the lkp spinlock, which may not be SPLNOPREEMPT. If the caller acquired the lock while holding other spinlocks, the priority level is lowered to the value before the first of these nested spinlock calls. Also, the SVR4 MP SV_WAIT_SIG has a priority argument that specifies the priority the caller would like to run at after waking. Since the HP-UX SV_WAIT_SIG is implemented by calling sleep, the HP-UX priorities are different than the SVR4 MP ones. On HP-UX, the priority passed into SV_WAIT_SIG is added to PZERO+1|PCATCH. pridisk, prinet, pritty, pritape, prihi, primed, and prilo are defined to be 0, and do not affect the caller's priority. If you need to change the process's priority, study the priorities in /usr/include/sys/param.h or /usr/conf/h/param.h, and pass the needed offset to PZERO+1|PCATCH in the priority parameter. The last difference is that the SVR4 MP SV_WAIT_SIG returns if the process is first stopped by a job control signal and then continued. The HP-UX SV_WAIT_SIG continues to sleep until it receives a signal which does not stop the process, or an SV_BROADCAST wakes up the process.

TRYLOCK

The STREAMS/UX TRYLOCK calls the native HP-UX cspinlock primitive. TRYLOCK has an interrupt priority level parameter, which is used to raise the priority level and block interrupts which acquire the spinlock. The SVR4.2 Driver manual says that implementations which do not require the interrupt level to be raised can ignore this parameter. STREAMS/UX ignores the parameter on multiprocessor systems since the HP-UX cspinlock primitive always raises the interrupt level to spl6 while a spinlock is held. For better performance on uniprocessor systems, the STREAMS/UX TRYLOCK raises the priority level to the parameter value instead of acquiring a spinlock.

UNLOCK

The STREAMS/UX UNLOCK calls the native HP-UX spinunlock primitive. UNLOCK has an interrupt priority level parameter, which is used to lower the priority level. HP-UX will ignore this parameter on multiprocessor systems. If the caller is not holding any other spinlocks, the STREAMS/UX UNLOCK lowers the priority level to the value before the caller acquired the spinlock. On uniprocessor systems, the STREAMS/UX UNLOCK lowers the priority level to the parameter value instead of releasing a spinlock.

weldq and unweldq

STREAMS/UX provides the additional utilities weldq and unweldq to allow the user to build a pipe-like stream. These utilities are provided because the programmer is not allowed to modify q_next pointers directly. This restriction and others are described in more detail in the section called "HP-UX Changes to STREAMS/UX Data Structures."

unweldq

The utility unweldq disconnects two drivers' queues that were joined by weldq:

int unweldq (d1_wq, d2_rq, d2_wq, d1_rq, func, arg, protect_q);

queue_t * d1_wq;
queue_t * d2_rq;
queue_t * d2_wq;
queue_t * d1_rq;
weld_fcn_t func;
weld_arg_t arg;
queue_t * protect_q;

d1_wq and d1_rq are one of the driver's write and read queues. d2_wq and d2_rq are the second driver's queues. unweldq will set d1_wq->q_next and d2_wq->q_next to zero. Also, it updates queue fields used for flow control that are not visible to the STREAMS/UX programmer, and therefore cannot be changed by the STREAMS/UX programmer.

unweldq returns to the caller before disconnecting the drivers. unweldq requests that the STREAMS/UX weld daemon update the queues.

Note that if one end of a pipe-like stream created by weld is closed, STREAMS/UX will automatically unweld the two drivers. unweldq does not need to be called.

The weld daemon will call func with arg as an argument after it finishes the request. protect_q specifies which queue the callback function can access safely. See "STREAMS/UX Uniprocessor Synchronization" in this chapter and "Writing MP Scalable Modules and Drivers" in Chapter 4 for a more detailed discussion of protect_q.

If your driver does not need to be notified when the daemon finishes the weld request, pass weldq zero for the func, arg, and protect_q parameters.

On successful completion, unweldq returns 0. Otherwise, it returns an errno indicating the type of error that occurred. One of the following three values will be returned:

  • ENXIO indicates that the weld daemon is not running.

  • EINVAL indicates that invalid queue arguments are present.

  • EAGAIN means that no memory is available.

weldq

Weldq connects two drivers' queues to form a pipe by setting the q_next pointer:

int weldq (d1_wq, d2_rq, d2_wq, d1_rq, func, arg, protect_q);

queue_t * d1_wq;
queue_t * d2_rq;
queue_t * d2_wq;
queue_t * d1_rq;
weld_fcn_t func;
weld_arg_t arg;
queue_t * protect_q;

d1_wq and d1_rq are one of the drivers' write and read queues. d2_wq and d2_rq are the second driver's queues. weldq will set d1_wq->q_next to be d2_rq and d2_wq->q_next to d1_rq. Also, weldq updates queue fields used for flow control that are not visible to the STREAMS/UX programmer, and therefore cannot be updated by the STREAMS/UX programmer.

weldq returns to the caller before connecting the drivers. weldq requests the STREAMS/UX weld daemon to update the queues.

The weld daemon will call func with arg as an argument after it finishes the request. protect_q specifies which queue the callback function can access safely. See "STREAMS/UX Uniprocessor Synchronization" in this chapter and "Writing MP Scalable Modules and Drivers" in Chapter 4 for a more detailed discussion of protect_q.

If your driver does not need to be notified when the daemon finishes the weld request, pass weldq zero for the func, arg, and protect_q parameters.

On successful completion, weldq returns 0. However, if weldq fails, an errno indicating the type of error that has occurred is returned. The errno will contain one of the following three values:

  • ENXIO means that the weld daemon is not running.

  • EINVAL means that invalid queue arguments exist.

  • EAGAIN means that no memory is available.

Note that if one end of a pipe-like stream created by weldq is closed, STREAMS/UX will automatically unweld the two drivers. unweldq does not need to be called.

vtop

The STREAMS/UX vtop only accepts a NULL process structure pointer. In other words, it only converts kernel space addresses.

© 1995 Hewlett-Packard Development Company, L.P.