Annotation of coherent/f/etc/conf/streams/src/strmlib.c, revision 1.1.1.1

1.1       root        1: #define        _DDI_DKI        1
                      2: #define        _SYSV4          1
                      3: 
                      4: /*
                      5:  * This file contains the fundamental STREAMS routines defined in Appendix
                      6:  * C of the STREAMS Programmer's Guide for System V Release 4. Note that
                      7:  * additional information about the definition of these routines has been
                      8:  * taken from the System V Release 4 Multi-Processor DDI/DKI For Intel CPU's.
                      9:  *
                     10:  * Later documents significantly redefine the semantics of many STREAMS
                     11:  * routines. If there is a conflict, the normal System V Release 4 version
                     12:  * is preferred, and the conflict is noted. However, where possible the later
                     13:  * semantics have been incorporated or anticipated.
                     14:  */
                     15: 
                     16: /*
                     17:  *-IMPORTS:
                     18:  *     <common/ccompat.h>
                     19:  *             __USE_PROTO__
                     20:  *             __ARGS ()
                     21:  *     <kernel/defer.h>
                     22:  *             defer_int_any ()
                     23:  *     <sys/debug.h>
                     24:  *             ASSERT ()
                     25:  *     <sys/types.h>
                     26:  *             uchar_t
                     27:  *             uint_t
                     28:  *             ushort_t
                     29:  *             toid_t
                     30:  *     <sys/kmem.h>
                     31:  *             KM_NOSLEEP
                     32:  *             kmem_alloc ()
                     33:  *             kmem_free ()
                     34:  *     <sys/cmn_err.h>
                     35:  *             CE_WARN
                     36:  *             cmn_err ()
                     37:  *     <sys/strlog.h>
                     38:  *             SL_ERROR
                     39:  *             SL_TRACE
                     40:  *             SL_CONSOLE
                     41:  *             SL_NOTIFY
                     42:  *             SL_FATAL
                     43:  *             SL_WARN
                     44:  *             SL_NOTE
                     45:  *             SL_LEVEL_MASK
                     46:  *             NLOGARGS
                     47:  *             struct log_ctl
                     48:  *     <sys/errno.h>
                     49:  *             EINVAL
                     50:  *             ENOMEM
                     51:  *             EPERM
                     52:  *     <stdarg.h>
                     53:  *             va_start ()
                     54:  *             va_arg ()
                     55:  *             va_end ()
                     56:  *     <string.h>
                     57:  *             memcpy ()
                     58:  */
                     59: 
                     60: #include <common/ccompat.h>
                     61: #include <kernel/defer.h>
                     62: #include <sys/debug.h>
                     63: #include <sys/types.h>
                     64: #include <sys/kmem.h>
                     65: #include <sys/cmn_err.h>
                     66: #include <sys/strlog.h>
                     67: #include <sys/errno.h>
                     68: #include <stdarg.h>
                     69: #include <string.h>
                     70: 
                     71: #include <sys/stream.h>
                     72: #include <kernel/strmlib.h>
                     73: 
                     74: 
                     75: /*
                     76:  * The pre-SVR4 STREAMS system used a marker bit to determine when putq () and
                     77:  * putbq () should enable a queue. This flag, documented as QWANTR in the SVR4
                     78:  * STREAMS documentation, is no longer sufficient to deal with scheduling with
                     79:  * priority bands. The DDI/DKI and STREAMS documentation in SVR4 do not
                     80:  * contain detailed new rules for dealing with exactly when a queue should be
                     81:  * enabled automatically.
                     82:  *
                     83:  * The rules that we have adopted to deal with band flow control use our own
                     84:  * member of the queue structure, "q_lastband". The idea is for getq () and
                     85:  * rmvq () to record the band of the last message that was dequeued (or to
                     86:  * set QWANTR), so that when a message in a higher band is queued the stream
                     87:  * will be enabled to process it. If the last message retrieved is returned
                     88:  * to the queue because of a flow-control blockage, putq () will see that the
                     89:  * message is not a member of a higher band that the last read, and thus will
                     90:  * know not to enable the queue.
                     91:  */
                     92: 
                     93: 
                     94: /*
                     95:  * Simple helper macro: is this message a priority message?
                     96:  */
                     97: 
                     98: #define        IS_PRI_MSG(mp)          pcmsg ((mp)->b_datap->db_type)
                     99: 
                    100: 
                    101: /*
                    102:  * Simple realloc () function for memory allocated with kmem_alloc ()
                    103:  * (assuming that it is our kmem_alloc (), that is).
                    104:  */
                    105: 
                    106: #if    __USE_PROTO__
                    107: __LOCAL__ _VOID * (kmem_realloc) (_VOID * mem, size_t newsize, size_t oldsize)
                    108: #else
                    109: __LOCAL__ _VOID *
                    110: kmem_realloc __ARGS ((mem, newsize, oldsize))
                    111: _VOID        * mem;
                    112: size_t         newsize;
                    113: size_t         oldsize;
                    114: #endif
                    115: {
                    116:        pl_t            prev_pl;
                    117: 
                    118:        ASSERT (mem != NULL && newsize > 0 && oldsize > 0);
                    119: 
                    120:        prev_pl = LOCK (str_mem->sm_other_lock, str_other_pl);
                    121: 
                    122:        mem = st_realloc (str_mem->sm_other_heap, mem, newsize, oldsize);
                    123: 
                    124:        OTHER_ALLOCED (newsize - oldsize);
                    125: 
                    126:        UNLOCK (str_mem->sm_other_lock, prev_pl);
                    127: 
                    128:        return mem;
                    129: }
                    130: 
                    131: 
                    132: /*
                    133:  * This internal function actually implements the queue freezing; in addition,
                    134:  * it asserts that the queue is non-NULL, traces who froze the queue, and
                    135:  * so forth. If a queue monitoring facility is introduced, this would be the
                    136:  * place to do it.
                    137:  */
                    138: 
                    139: #if    __USE_PROTO__
                    140: pl_t (QFREEZE_TRACE) (queue_t * q, __CONST__ char * name)
                    141: #else
                    142: pl_t
                    143: QFREEZE_TRACE __ARGS ((q, name))
                    144: queue_t              * q;
                    145: __CONST__ char * name;
                    146: #endif
                    147: {
                    148:        if (q == NULL)
                    149:                cmn_err (CE_PANIC, "NULL queue passed to STREAMS utility %s",
                    150:                         name);
                    151: 
                    152:        return SFREEZE_LOCK (q, name);
                    153: }
                    154: 
                    155: 
                    156: /*
                    157:  * This internal function is similar to QFREEZE_TRACE (), but performs the
                    158:  * assertions and tracing functions for routines that require that the queue
                    159:  * already be frozen on entry.
                    160:  */
                    161: 
                    162: #if    __USE_PROTO__
                    163: void (QFROZEN_TRACE) (queue_t * q, __CONST__ char * name)
                    164: #else
                    165: void
                    166: QFROZEN_TRACE __ARGS ((q, name))
                    167: queue_t              * q;
                    168: __CONST__ char * name;
                    169: #endif
                    170: {
                    171:        if (q == NULL)
                    172:                cmn_err (CE_PANIC, "NULL queue passed to STREAMS utility %s",
                    173:                         name);
                    174: 
                    175:        SFREEZE_ASSERT_FROZEN (q);
                    176: }
                    177: 
                    178: 
                    179: /*
                    180:  * This internal function is for utility routines that walk over various
                    181:  * queues (and hence perform multiple freeze/unfreeze operations in local
                    182:  * procedures such as QUEUE_NEXT).
                    183:  */
                    184: 
                    185: #if    __USE_PROTO__
                    186: void (QUEUE_TRACE) (queue_t * q, __CONST__ char * name)
                    187: #else
                    188: void
                    189: QUEUE_TRACE __ARGS ((q, name))
                    190: queue_t              * q;
                    191: __CONST__ char * name;
                    192: #endif
                    193: {
                    194:        if (q == NULL)
                    195:                cmn_err (CE_PANIC, "NULL queue passed to STREAMS utility %s",
                    196:                         name);
                    197: }
                    198: 
                    199: 
                    200: /*
                    201:  * This internal function follows the singly-threaded lists of priority band
                    202:  * structures to find the "pri"th priority band attached to the queue. It
                    203:  * returns NULL if no such band has been allocated.
                    204:  *
                    205:  * The queue passed to this function must be frozen.
                    206:  */
                    207: 
                    208: #if    ! defined (VECTOR_BANDS) || defined (VECTOR_BANDS_TEST)
                    209: 
                    210: #if    __USE_PROTO__
                    211: qband_t * (QUEUE_BAND) (queue_t * q, uchar_t pri)
                    212: #else
                    213: qband_t *
                    214: QUEUE_BAND __ARGS ((q, pri))
                    215: queue_t              * q;
                    216: uchar_t                pri;
                    217: #endif
                    218: {
                    219:        qband_t       * qbandp;
                    220:        uchar_t         count = pri;
                    221: 
                    222: 
                    223:        ASSERT (pri > 0);
                    224:        QFROZEN_TRACE (q, "QUEUE_BAND");
                    225: 
                    226:        /*
                    227:         * Just iterate through the list of band structures.
                    228:         */
                    229: 
                    230:        if ((qbandp = q->q_bandp) != NULL)
                    231:                while (-- count > 0)
                    232:                        if ((qbandp = qbandp->qb_next) == NULL)
                    233:                                break;
                    234: 
                    235:        ASSERT (pri > q->q_nband ? qbandp == NULL : qbandp != NULL);
                    236: 
                    237: #ifdef VECTOR_BANDS_TEST
                    238:        /*
                    239:         * For extra fun, we define a mode where we work everything out both
                    240:         * ways to ensure correctness. The #undef makes all the later uses
                    241:         * of the QUEUE_BAND name map to this function version so that the
                    242:         * test gets included.
                    243:         */
                    244: 
                    245:        ASSERT (qbandp == QUEUE_BAND (q, pri));
                    246: # undef QUEUE_BAND
                    247: #endif
                    248: 
                    249:        return qbandp;
                    250: }
                    251: 
                    252: 
                    253: /*
                    254:  * This internal function gets the predecessor to a band structure from a
                    255:  * queue, or NULL if there is no such predecessor.
                    256:  *
                    257:  * The definition of the "qband" structure was public from its introduction in
                    258:  * SVR4, but was made private in the SVR4 MP release. We could reasonably
                    259:  * change the definition of this structure to include a back-link, but for
                    260:  * now we'll do it the hard way and stay with the structure as defined.
                    261:  *
                    262:  * The queue passed to this function must be frozen.
                    263:  */
                    264: 
                    265: #if    __USE_PROTO__
                    266: qband_t * (QBAND_PREV) (queue_t * q, qband_t * qbandp)
                    267: #else
                    268: qband_t *
                    269: QBAND_PREV __ARGS ((q, qbandp))
                    270: queue_t              * q;
                    271: qband_t              * qbandp;
                    272: #endif
                    273: {
                    274:        qband_t       * scan;
                    275: 
                    276:        ASSERT (qbandp != NULL);
                    277:        QFROZEN_TRACE (q, "QBAND_PREV");
                    278: 
                    279:        if ((scan = q->q_bandp) == qbandp)
                    280:                return NULL;
                    281: 
                    282:        while (scan->qb_next != qbandp) {
                    283:                scan = scan->qb_next;
                    284: 
                    285:                ASSERT (scan != NULL);
                    286:        }
                    287: 
                    288: #ifdef VECTOR_BANDS_TEST
                    289:        ASSERT (scan == QBAND_PREV (q, qbandp));
                    290: 
                    291: # undef        QBAND_PREV
                    292: #endif
                    293: 
                    294:        return scan;
                    295: }
                    296: 
                    297: #endif /* ! defined (VECTOR_BANDS) || defined (VECTOR_BANDS_TEST) */
                    298: 
                    299: 
                    300: /*
                    301:  * This local function attempts to allocate new storage for a priority-band
                    302:  * structure associated with a queue. Since for a given band "n", band
                    303:  * structures 1 through "n-1" must also be present, this function may attempt
                    304:  * to acquire several structures simultaneously.
                    305:  *
                    306:  * The caller must have the queue frozen.
                    307:  */
                    308: 
                    309: #if    __USE_PROTO__
                    310: __LOCAL__ qband_t * (QBAND_ALLOC) (queue_t * q, uchar_t pri)
                    311: #else
                    312: __LOCAL__ qband_t *
                    313: QBAND_ALLOC __ARGS ((q, pri))
                    314: queue_t              * q;
                    315: uchar_t                pri;
                    316: #endif
                    317: {
                    318:        qband_t       * newband;
                    319:        int             nbands;
                    320: 
                    321:        QFROZEN_TRACE (q, "QBAND_ALLOC");
                    322:        ASSERT (pri > 0);
                    323:        ASSERT (pri > q->q_nband);
                    324: 
                    325:        /*
                    326:         * We want to allocate band structures "q->q_nband + 1" ... "pri".
                    327:         *
                    328:         * Since the caller has the stream frozen, we want to do this fairly
                    329:         * quickly, so we allocate the new structures as a vector. In order
                    330:         * to speed up other operations, we may also try to reallocate any
                    331:         * existing information so that the entire set of band structures is
                    332:         * kept in a single block of memory.
                    333:         */
                    334: 
                    335: #ifdef VECTOR_BANDS
                    336:        if (q->q_bandp != NULL) {
                    337:                /*
                    338:                 * There are some existing band structures to be moved around
                    339:                 * (note that this will require that all the "qb_next"
                    340:                 * pointers be rethreaded).
                    341:                 */
                    342: 
                    343:                if ((newband = (qband_t *)
                    344:                        kmem_realloc (q->q_bandp, pri * sizeof (qband_t),
                    345:                                      q->q_nband * sizeof (qband_t))) == NULL)
                    346:                        return NULL;
                    347: 
                    348:                q->q_bandp = newband;
                    349: 
                    350:                for (nbands = 0 ; nbands < q->q_nband ; newband ++, nbands ++)
                    351:                        newband->qb_next = newband + 1;
                    352: 
                    353:                /*
                    354:                 * Now we have rethreaded the relocated version of the old
                    355:                 * band structures, "newband" is set correctly to initialize
                    356:                 * the new band structures.
                    357:                 *
                    358:                 * We zero the remaining memory to ease initialization.
                    359:                 */
                    360: 
                    361:                memset (newband, 0, (pri - q->q_nband) * sizeof (qband_t));
                    362:        } else
                    363: #endif
                    364: 
                    365:        if ((newband = (qband_t *)
                    366:                kmem_zalloc ((pri - q->q_nband) * sizeof (qband_t),
                    367:                             KM_NOSLEEP)) == NULL)
                    368:                return NULL;
                    369: 
                    370: #ifndef VECTOR_BANDS
                    371:        newband->qb_flag = QB_FIRST;
                    372: 
                    373:        /*
                    374:         * Special-case update the "qb_next" pointer of the previously highest
                    375:         * band.
                    376:         */
                    377: 
                    378:        if (q->q_nbands > 0)
                    379:                QUEUE_BAND (q, q->q_nbands)->qb_next = newband;
                    380: #endif
                    381: 
                    382:        /*
                    383:         * Thread the "qb_next" pointers of the new structures together.
                    384:         */
                    385: 
                    386:        for (nbands = q->q_nband ; nbands < pri - 1 ; newband ++, nbands ++)
                    387:                newband->qb_next = newband + 1;
                    388: 
                    389:        return newband;
                    390: }
                    391: 
                    392: 
                    393: /*
                    394:  * This internal function performs an atomic read of the "q_next" member of
                    395:  * the queue passed to it, skipping over queues that are hidden from the
                    396:  * STREAMS system.
                    397:  *
                    398:  * The queue passed to this function must be frozen. After this function, the
                    399:  * passed queue is unfrozen and the returned queue is frozen (unless it is
                    400:  * NULL).
                    401:  *
                    402:  * Note that this function illustrates a problem with using a fixed-hierarchy
                    403:  * basic lock scheme; this code can't deadlock with itself because of the
                    404:  * relationship expressed by the "q_next" member. Locks are only acquired in
                    405:  * one direction along a stream axis, so each queue lock has an implicit
                    406:  * hierarchy value lower that its successor.
                    407:  */
                    408: 
                    409: #if    __USE_PROTO__
                    410: queue_t * (QUEUE_NEXT) (queue_t * q)
                    411: #else
                    412: queue_t *
                    413: QUEUE_NEXT __ARGS ((q))
                    414: queue_t              * q;
                    415: #endif
                    416: {
                    417:        QFROZEN_TRACE (q, "QUEUE_NEXT");
                    418: 
                    419:        do {
                    420:                queue_t       * next;
                    421: 
                    422:                if ((next = q->q_next) != NULL)
                    423:                        (void) QFREEZE_TRACE (next, "QUEUE_NEXT");
                    424: 
                    425:                QUNFREEZE_TRACE (q, plstr);
                    426: 
                    427:                q = next;
                    428:        } while (q != NULL && (q->q_flag & QPROCSOFF) != 0);
                    429: 
                    430:        return q;
                    431: }
                    432: 
                    433: 
                    434: /*
                    435:  * This internal function attempts to schedule a queue. It will fail if the
                    436:  * queue has no service procedure or if the service procedure has been
                    437:  * disabled. It will do nothing, but return success, if the queue is currently
                    438:  * scheduled for service.
                    439:  */
                    440: 
                    441: #if    __USE_PROTO__
                    442: __LOCAL__ int (QUEUE_TRYSCHED) (queue_t * q)
                    443: #else
                    444: __LOCAL__ int
                    445: QUEUE_TRYSCHED __ARGS ((q))
                    446: queue_t              * q;
                    447: #endif
                    448: {
                    449:        QFROZEN_TRACE (q, "QUEUE_TRYSCHED");
                    450: 
                    451:        if (q->q_qinfo->qi_srvp == NULL || (q->q_flag & QPROCSOFF) != 0)
                    452:                return 0;
                    453: 
                    454:        if ((q->q_flag & QENAB) != 0 ||
                    455:            QSCHED_SCHEDULE (q, str_mem->sm_sched) != 0)
                    456:                return 1;
                    457: 
                    458:        /*
                    459:         * Mark the queue as having been scheduled, and if the STREAMS service
                    460:         * procedure scheduler has not been deferred, do so.
                    461:         */
                    462: 
                    463:        q->q_flag |= QENAB;
                    464: 
                    465:        if (ATOMIC_FETCH_AND_STORE_UCHAR (ddi_global_data ()->dg_run_strsched,
                    466:                                          1) == 0)
                    467:                defer_int_any (RUN_STREAMS);
                    468: 
                    469:        return 1;
                    470: }
                    471: 
                    472: 
                    473: /*
                    474:  * QUEUE_BACKENAB () is an internal function used to unblock a queue which
                    475:  * has been blocked by flow control. When a queue with a service procedure
                    476:  * becomes full, and a queue "behind" it finds that it cannot put into it
                    477:  * with bcanput (), bcanputnext (), canput (), or canputnext (), the target
                    478:  * queue is marked so that this procedure will be called when it is ready to
                    479:  * receive more data.
                    480:  *
                    481:  * Since the "behind" queue should have a service procedure (otherwise, the
                    482:  * flow-control tests would have no point), we scan the queues behind the
                    483:  * passed queue "q" and enable the first one which has a service procedure.
                    484:  *
                    485:  * The queue passed to this function must *not* be frozen. To avoid deadlock,
                    486:  * a single function cannot hold both sides of a queue frozen; this is the
                    487:  * only function in the STREAMS library that might plausibly want to do so.
                    488:  *
                    489:  * This function is normally called as a result of action in QBAND_REDUCE ()
                    490:  * or QUEUE_REDUCE (), and under normal circumstances this would not cause an
                    491:  * inconvenience. However, the action of rvmq () means that we use a condition
                    492:  * in the "q_flags" member of the queue to indirectly schedule this function
                    493:  * at a safe time. We only need to test the flag in a path that includes one
                    494:  * of the above named functions or in user calls to unfreezestr ().
                    495:  */
                    496: 
                    497: #if    __USE_PROTO__
                    498: void (QUEUE_BACKENAB) (queue_t * q)
                    499: #else
                    500: void
                    501: QUEUE_BACKENAB __ARGS ((q))
                    502: queue_t              * q;
                    503: #endif
                    504: {
                    505:        int             done;
                    506:        queue_t       * other;
                    507:        pl_t            prev_pl;
                    508: 
                    509:        ASSERT (q != NULL);
                    510: 
                    511:        /*
                    512:         * To walk backwards along the queue list, we must first move to the
                    513:         * other kind of queue and walk along that, which effectively moves us
                    514:         * in the reverse direction with respect to the original queue type.
                    515:         */
                    516: 
                    517:        other = OTHERQ (q);
                    518: 
                    519:        prev_pl = QFREEZE_TRACE (other, "QUEUE_BACKENAB");
                    520: 
                    521:        do {
                    522:                /*
                    523:                 * Atomically read the "q_next" member of the queue.
                    524:                 */
                    525: 
                    526:                if ((other = QUEUE_NEXT (other)) == NULL) {
                    527:                        /*
                    528:                         * Cannot search further.
                    529:                         */
                    530: 
                    531:                        (void) splx (prev_pl);
                    532:                        break;
                    533:                }
                    534: 
                    535: 
                    536:                /*
                    537:                 * To avoid deadlock, we have to unfreeze "other" before we
                    538:                 * look at freezing its partner. We ensure that it won't go
                    539:                 * away on us after we unfreeze it by incrementing the
                    540:                 * "active" count.
                    541:                 */
                    542: 
                    543:                other->q_active ++;
                    544: 
                    545:                QUNFREEZE_TRACE (other, prev_pl);
                    546: 
                    547: 
                    548:                /*
                    549:                 * We might be attempting to schedule an empty queue, which
                    550:                 * we should allow.
                    551:                 */
                    552: 
                    553:                q = OTHERQ (other);
                    554: 
                    555:                prev_pl = QFREEZE_TRACE (q, "QUEUE_BACKENAB");
                    556: 
                    557:                done = QUEUE_TRYSCHED (q);
                    558: 
                    559:                QUNFREEZE_TRACE (q, prev_pl);
                    560: 
                    561: 
                    562:                /*
                    563:                 * Now we go back and remove our reference to the partner
                    564:                 * queue after relocking it.
                    565:                 */
                    566: 
                    567:                prev_pl = QFREEZE_TRACE (other, "QUEUE_BACKENAB");
                    568: 
                    569:                ASSERT (other->q_active > 0);
                    570: 
                    571:                other->q_active --;
                    572: 
                    573:                if ((q->q_flag & QPROCSOFF) != 0 && q->q_active == 0) {
                    574:                        /*
                    575:                         * Time to wake up the sleepers waiting for the put
                    576:                         * and service routines on a queue to exit. See
                    577:                         * qprocsoff () for a discussion of the locking
                    578:                         * protocol.
                    579:                         */
                    580: 
                    581:                        (void) LOCK (str_mem->sm_proc_lock, plstr);
                    582:                        SV_BROADCAST (str_mem->sm_proc_sv, 0);
                    583:                        UNLOCK (str_mem->sm_proc_lock, plstr);
                    584:                }
                    585:        } while (! done);
                    586: 
                    587:        QUNFREEZE_TRACE (other, prev_pl);
                    588: }
                    589: 
                    590: 
                    591: /*
                    592:  * This local function is called whenever a queue's last message has been
                    593:  * dequeued, and will wake up any function waiting for the queue to drain.
                    594:  *
                    595:  * The caller must have the stream frozen.
                    596:  */
                    597: 
                    598: #if    __USE_PROTO__
                    599: __LOCAL__ void (QUEUE_DRAINED) (queue_t * q)
                    600: #else
                    601: __LOCAL__ void
                    602: QUEUE_DRAINED __ARGS ((q))
                    603: queue_t              * q;
                    604: #endif
                    605: {
                    606:        pl_t            prev_pl;
                    607: 
                    608:        QFROZEN_TRACE (q, "QUEUE_DRAINED");
                    609: 
                    610:        if ((q->q_flag & QDRAIN) != 0) {
                    611:                shead_t       * sheadp;
                    612: 
                    613:                /*
                    614:                 * Under normal circumstances, a call to SV_BROADCAST () would
                    615:                 * be all we needed to do. However, since we allow ourself to
                    616:                 * use a more primitive kind of lock that a basic lock to
                    617:                 * implement freezing a queue, the process that waits for us
                    618:                 * to drain cannot use the frozen queue as the lock to pass to
                    619:                 * SV_WAIT (). By making us wait for the lock, we make
                    620:                 * the wakeup multiprocessor-safe; otherwise, we might be able
                    621:                 * to try and wake the process before it has actually slept,
                    622:                 * causing infinite sleep.
                    623:                 *
                    624:                 * Since the synchronization variable we are going to
                    625:                 * broadcast to is part of the stream head, we ensure that
                    626:                 * this code is only executed for the module or driver which
                    627:                 * is immediately below the stream head, or the stream head
                    628:                 * write queue itself.
                    629:                 */
                    630: 
                    631:                ASSERT (RD (q)->q_next == NULL ||
                    632:                        RD (q)->q_next->q_next == NULL);
                    633: 
                    634:                sheadp = (shead_t *)
                    635:                        (RD (q)->q_next == NULL ? q->q_ptr :
                    636:                                RD (q)->q_next->q_ptr);
                    637: 
                    638:                prev_pl = SHEAD_LOCK (sheadp);
                    639: 
                    640:                SV_BROADCAST (sheadp->sh_wait_sv, 0);
                    641: 
                    642:                q->q_flag &= ~ QDRAIN;
                    643: 
                    644:                SHEAD_UNLOCK (sheadp, prev_pl);
                    645:        }
                    646: }
                    647: 
                    648: 
                    649: /*
                    650:  * This local function updates the flow-control information for a priority
                    651:  * band when the band current level is increasing.
                    652:  *
                    653:  * The queue passed to this function must be frozen.
                    654:  */
                    655: 
                    656: #if    __USE_PROTO__
                    657: __LOCAL__ void (QBAND_INCREASE) (queue_t * q, qband_t * qbandp, ulong_t adjust)
                    658: #else
                    659: __LOCAL__ void
                    660: QBAND_INCREASE __ARGS ((q, qbandp, adjust))
                    661: queue_t              * q;
                    662: qband_t              * qbandp;
                    663: ulong_t                adjust;
                    664: #endif
                    665: {
                    666:        ASSERT (qbandp != NULL);
                    667:        QFROZEN_TRACE (q, "QBAND_INCREASE");
                    668: 
                    669:        /*
                    670:         * If the band we are dealing with is already flow-controlled, just
                    671:         * get out of here.
                    672:         */
                    673: 
                    674:        qbandp->qb_count += adjust;
                    675: 
                    676:        if ((qbandp->qb_flag & QB_FULL) != 0)
                    677:                return;
                    678: 
                    679:        /*
                    680:         * If we are over the high-water mark, then we must mark ourself and
                    681:         * all the bands below us (including the normal messages) as full as
                    682:         * well.
                    683:         */
                    684: 
                    685:        if (qbandp->qb_count >= qbandp->qb_hiwat) {
                    686: 
                    687:                do
                    688:                        qbandp->qb_flag |= QB_FULL;
                    689:                while ((qbandp = QBAND_PREV (q, qbandp)) != NULL);
                    690: 
                    691: 
                    692:                /*
                    693:                 * According to the way I read the STREAMS
                    694:                 * programmer's guide, band flow control
                    695:                 * should affect normal messages as well (ie,
                    696:                 * as if they are band 0).
                    697:                 *
                    698:                 * We deal with this as a special case.
                    699:                 */
                    700: 
                    701:                if (q->q_count >= q->q_hiwat)
                    702:                        q->q_flag |= QFULL;
                    703:        }
                    704: }
                    705: 
                    706: 
                    707: /*
                    708:  * This local function updates the flow-control information for a priority
                    709:  * band when the band current level is decreasing.
                    710:  *
                    711:  * The queue passed to this function must be frozen.
                    712:  */
                    713: 
                    714: #if    __USE_PROTO__
                    715: __LOCAL__ void (QBAND_REDUCE) (queue_t * q, qband_t * qbandp, ulong_t adjust)
                    716: #else
                    717: __LOCAL__ void
                    718: QBAND_REDUCE __ARGS ((q, qbandp, adjust))
                    719: queue_t              * q;
                    720: qband_t              * qbandp;
                    721: ulong_t                adjust;
                    722: #endif
                    723: {
                    724: 
                    725:        ASSERT (qbandp != NULL);
                    726:        ASSERT (qbandp->qb_count >= adjust);
                    727:        QFROZEN_TRACE (q, "QBAND_REDUCE");
                    728: 
                    729:        /*
                    730:         * If this band wasn't flow-controlled anyway, then we don't need to
                    731:         * do anything other than adjust the count.
                    732:         */
                    733: 
                    734:        qbandp->qb_count -= adjust;
                    735: 
                    736:        if ((qbandp->qb_flag & QB_FULL) == 0)
                    737:                return;
                    738: 
                    739: 
                    740:        /*
                    741:         * If we are under the low-water mark, then we can release any pending
                    742:         * writes to this band and our hold on lower bands if and only if the
                    743:         * bands above us are not controlled.
                    744:         *
                    745:         * We can test the bands above us in one step since we require that a
                    746:         * band which has become full also mark all lower bands as full. If
                    747:         * our immediate upper neighbour is full then we cannot proceed.
                    748:         */
                    749: 
                    750:        if (qbandp->qb_count <= qbandp->qb_lowat &&
                    751:            (qbandp->qb_next == NULL ||
                    752:                        (qbandp->qb_next->qb_flag & QB_FULL) == 0)) {
                    753: 
                    754:                /*
                    755:                 * We release lower bands as long as they are under their low-
                    756:                 * water marks. It seems pointless to resume bands that are
                    757:                 * too close to entering a controlled state anyway.
                    758:                 */
                    759: 
                    760:                do {
                    761:                        qbandp->qb_flag &= ~ QB_FULL;
                    762: 
                    763:                        if ((qbandp->qb_flag & QB_WANTW) != 0) {
                    764:                                /*
                    765:                                 * Propagate a back-enable request to the
                    766:                                 * queue.
                    767:                                 */
                    768: 
                    769:                                qbandp->qb_flag &= ~ QB_WANTW;
                    770:                                q->q_flag |= QBACK;
                    771:                        }
                    772: 
                    773:                        if ((qbandp = QBAND_PREV (q, qbandp)) == NULL) {
                    774:                                /*
                    775:                                 * According to the way I read the STREAMS
                    776:                                 * programmer's guide, band flow control
                    777:                                 * should affect normal messages as well (ie,
                    778:                                 * as if they are band 0).
                    779:                                 *
                    780:                                 * We deal with this as a special case.
                    781:                                 */
                    782: 
                    783:                                if (q->q_count <= q->q_lowat) {
                    784:                                        q->q_flag &= ~ QFULL;
                    785: 
                    786:                                        if ((q->q_flag & QWANTW) != 0) {
                    787: 
                    788:                                                q->q_flag &= ~ QWANTW;
                    789:                                                q->q_flag |= QBACK;
                    790:                                        }
                    791:                                }
                    792: 
                    793:                                break;
                    794:                        }
                    795:                } while (qbandp->qb_count <= qbandp->qb_lowat);
                    796:        }
                    797: }
                    798: 
                    799: 
                    800: /*
                    801:  * This local function factors out the computation of the total number of
                    802:  * data bytes in a message from the routines that manipulate flow-control
                    803:  * parameters. Since this is often the only loop in such routines, factoring
                    804:  * this out might help inlining in some cases.
                    805:  */
                    806: 
                    807: #if    __USE_PROTO__
                    808: __LOCAL__ ulong_t (MSG_SIZE) (mblk_t * mp)
                    809: #else
                    810: __LOCAL__ ulong_t
                    811: MSG_SIZE __ARGS ((mp))
                    812: mblk_t       * mp;
                    813: #endif
                    814: {
                    815:        ulong_t         total = 0;
                    816: 
                    817:        ASSERT (mp != NULL);
                    818: 
                    819:        do
                    820:                total += mp->b_wptr - mp->b_rptr;
                    821:        while ((mp = mp->b_cont) != NULL);
                    822: 
                    823:        return total;
                    824: }
                    825: 
                    826: 
                    827: /*
                    828:  * This internal function wraps up the check for whether a newly queued
                    829:  * message is of sufficient priority to cause the queue to be enabled.
                    830:  *
                    831:  * The queue passed to this function must be frozen.
                    832:  */
                    833: 
                    834: #if    __USE_PROTO__
                    835: __LOCAL__ int (QUEUE_CHECK_SCHED) (queue_t * q, mblk_t * mp,
                    836:                                    qband_t * qbandp)
                    837: #else
                    838: __LOCAL__ int
                    839: QUEUE_CHECK_SCHED __ARGS ((q, mp, qbandp))
                    840: queue_t              * q;
                    841: mblk_t       * mp;
                    842: qband_t              * qbandp;
                    843: #endif
                    844: {
                    845:        ulong_t         msgsize;
                    846: 
                    847:        QFROZEN_TRACE (q, "QUEUE_CHECK_SCHED");
                    848: 
                    849:        if ((q->q_flag & QNOENB) == 0 &&
                    850:            ((q->q_flag & QWANTR) != 0 || q->q_lastband < mp->b_band)) {
                    851:                /*
                    852:                 * The new message is part of a higher-priority band than the
                    853:                 * last message that was retrieved, so we need to enable the
                    854:                 * queue.
                    855:                 */
                    856: 
                    857:                q->q_lastband = mp->b_band;
                    858:                (void) QUEUE_TRYSCHED (q);
                    859:        }
                    860: 
                    861: 
                    862:        /*
                    863:         * As a convenience to the callers, all of whom are queueing the new
                    864:         * message, update the flow control parameters.
                    865:         */
                    866: 
                    867:        msgsize = MSG_SIZE (mp);
                    868: 
                    869:        if (mp->b_band > 0) {
                    870: 
                    871:                ASSERT (qbandp != NULL);
                    872: 
                    873:                QBAND_INCREASE (q, qbandp, msgsize);
                    874: 
                    875:                return 1;
                    876:        } else {
                    877:                /*
                    878:                 * Just deal with the base flow-control stuff.
                    879:                 */
                    880: 
                    881:                if ((q->q_count += msgsize) > q->q_hiwat)
                    882:                        q->q_flag |= QFULL;
                    883: 
                    884:                return 0;
                    885:        }
                    886: }
                    887: 
                    888: 
                    889: /*
                    890:  * This internal function collects the details of dequeuing a message from
                    891:  * a priority-band structure.
                    892:  *
                    893:  * The queue on which "mp" was queued must be frozen.
                    894:  */
                    895: 
                    896: #if    __USE_PROTO__
                    897: __LOCAL__ void (QBAND_DEQUEUE) (qband_t * qbandp, mblk_t * mp)
                    898: #else
                    899: __LOCAL__ void
                    900: QBAND_DEQUEUE __ARGS ((qbandp, mp))
                    901: qband_t              * qbandp;
                    902: mblk_t       * mp;
                    903: #endif
                    904: {
                    905:        ASSERT (qbandp != NULL);
                    906:        ASSERT (mp != NULL);
                    907:        ASSERT (mp->b_band > 0);
                    908: 
                    909:        if (qbandp->qb_first == mp) {
                    910: 
                    911:                if (qbandp->qb_last == mp) {
                    912:                        /*
                    913:                         * The band has become empty.
                    914:                         */
                    915: 
                    916:                        ASSERT (mp->b_next == NULL ||
                    917:                                mp->b_next->b_band < mp->b_band);
                    918: 
                    919:                        qbandp->qb_last = qbandp->qb_first = NULL;
                    920:                } else {
                    921:                        /*
                    922:                         * There is more data in the band.
                    923:                         */
                    924: 
                    925:                        ASSERT (mp->b_next != NULL);
                    926:                        ASSERT (mp->b_next->b_band == mp->b_band);
                    927: 
                    928:                        qbandp->qb_first = mp->b_next;
                    929:                }
                    930:        } else if (qbandp->qb_last == mp) {
                    931:                /*
                    932:                 * The band is non-empty, but we have to move the end up.
                    933:                 */
                    934: 
                    935:                ASSERT (mp->b_prev != NULL);
                    936:                ASSERT (mp->b_prev->b_band == mp->b_band);
                    937: 
                    938:                qbandp->qb_last = mp->b_prev;
                    939:        }
                    940: }
                    941: 
                    942: 
                    943: /*
                    944:  * This internal function tests to see whether a stream wanting to write to
                    945:  * this queue should block to honour the flow-control scheme. The return
                    946:  * value is 1 if the caller can write to this queue, 0 otherwise.
                    947:  *
                    948:  * The queue passed to this function must be frozen.
                    949:  */
                    950: 
                    951: #if    __USE_PROTO__
                    952: __LOCAL__ int (QBAND_CANPUT) (queue_t * q, uchar_t pri)
                    953: #else
                    954: __LOCAL__ int
                    955: QBAND_CANPUT __ARGS ((q, pri))
                    956: queue_t              * q;
                    957: uchar_t                pri;
                    958: #endif
                    959: {
                    960:        qband_t       * qbandp;
                    961: 
                    962:        QFROZEN_TRACE (q, "QBAND_CANPUT");
                    963: 
                    964:        if (pri > 0) {
                    965: 
                    966:                qbandp = QUEUE_BAND (q, pri);
                    967: 
                    968:                if (qbandp != NULL && (qbandp->qb_flag & QB_FULL) != 0) {
                    969:                        /*
                    970:                         * We must set the following flag to indicate that
                    971:                         * back-enabling is desired for this priority band.
                    972:                         *
                    973:                         * We'll set the global QWANTW flag as well, to make
                    974:                         * testing simpler for qprocson ().
                    975:                         */
                    976: 
                    977:                        qbandp->qb_flag |= QB_WANTW;
                    978:                        q->q_flag |= QWANTW;
                    979:                        return 0;
                    980:                }
                    981:        } else
                    982:                if ((q->q_flag & QFULL) != 0) {
                    983:                        /*
                    984:                         * We must set the following flag to indicate that the
                    985:                         * queue has a writer who has made a failed write
                    986:                         * attempt.
                    987:                         */
                    988: 
                    989:                        q->q_flag |= QWANTW;
                    990:                        return 0;
                    991:                }
                    992: 
                    993:        return 1;
                    994: }
                    995: 
                    996: 
                    997: /*
                    998:  * This internal function collects the non-priority-band flow-control actions
                    999:  * from flushq () and getq ().
                   1000:  *
                   1001:  * The queue passed to this function must be frozen.
                   1002:  */
                   1003: 
                   1004: #if    __USE_PROTO__
                   1005: __LOCAL__ void (QUEUE_REDUCE) (queue_t * q, ulong_t adjust)
                   1006: #else
                   1007: __LOCAL__ void
                   1008: QUEUE_REDUCE __ARGS ((q, adjust))
                   1009: queue_t              * q;
                   1010: ulong_t                adjust;
                   1011: #endif
                   1012: {
                   1013:        QFROZEN_TRACE (q, "QUEUE_REDUCE");
                   1014: 
                   1015:        ASSERT (q->q_count >= adjust);
                   1016: 
                   1017:        /*
                   1018:         * If the queue was not previously full, then we don't need to do
                   1019:         * anything other than tweak the count.
                   1020:         */
                   1021: 
                   1022:        q->q_count -= adjust;
                   1023: 
                   1024:        if ((q->q_flag & QFULL) != 0 && q->q_count <= q->q_lowat) {
                   1025: 
                   1026:                q->q_flag &= ~ QFULL;
                   1027: 
                   1028:                if ((q->q_flag & QWANTW) != 0) {
                   1029: 
                   1030:                        q->q_flag &= ~ QWANTW;
                   1031:                        q->q_flag |= QBACK;
                   1032:                }
                   1033:        }
                   1034: }
                   1035: 
                   1036: 
                   1037: /*
                   1038:  * This function contains part of the M_SETOPTS processing; specifically, here
                   1039:  * we deal with changing the watermarks of a band. The caller should test the
                   1040:  * QBACK flag when unfreezing the stream.
                   1041:  */
                   1042: 
                   1043: #if    __USE_PROTO__
                   1044: void (QBAND_SETOPT) (queue_t * q, struct stroptions * so)
                   1045: #else
                   1046: void
                   1047: QBAND_SETOPT __ARGS ((q, so))
                   1048: queue_t              * q;
                   1049: struct stroptions
                   1050:              * so;
                   1051: #endif
                   1052: {
                   1053:        qband_t       * qbandp;
                   1054:        pl_t            prev_pl;
                   1055: 
                   1056:        prev_pl = QFREEZE_TRACE (q, "QBAND_SETOPTS");
                   1057: 
                   1058:        if ((so->so_flags & (SO_LOWAT | SO_HIWAT)) == 0)
                   1059:                return;
                   1060: 
                   1061:        if ((so->so_flags & SO_BAND) != 0 && so->so_band > 0) {
                   1062: 
                   1063:                if ((qbandp = QUEUE_BAND (q, so->so_band)) == NULL &&
                   1064:                    (qbandp = QBAND_ALLOC (q, so->so_band)) == NULL) {
                   1065:                        /*
                   1066:                         * We cannot allocate space for the band accounting
                   1067:                         * structures. Give up.
                   1068:                         */
                   1069: 
                   1070:                        QUNFREEZE_TRACE (q, prev_pl);
                   1071:                        return;
                   1072:                }
                   1073: 
                   1074:                if ((so->so_flags & SO_LOWAT) != 0) {
                   1075: 
                   1076:                        qbandp->qb_lowat = so->so_lowat;
                   1077:                        QBAND_REDUCE (q, qbandp, 0L);
                   1078:                }
                   1079: 
                   1080:                if ((so->so_flags & SO_HIWAT) != 0) {
                   1081: 
                   1082:                        qbandp->qb_hiwat = so->so_hiwat;
                   1083:                        QBAND_INCREASE (q, qbandp, 0L);
                   1084:                }
                   1085:        } else {
                   1086: 
                   1087:                if ((so->so_flags & SO_LOWAT) != 0) {
                   1088: 
                   1089:                        q->q_lowat = so->so_lowat;
                   1090:                        QUEUE_REDUCE (q, 0L);
                   1091:                }
                   1092: 
                   1093:                if ((so->so_flags & SO_HIWAT) != 0) {
                   1094: 
                   1095:                        q->q_hiwat = so->so_hiwat;
                   1096:                        if (q->q_count > q->q_hiwat)
                   1097:                                q->q_flag |= QFULL;
                   1098:                }
                   1099:        }
                   1100: 
                   1101: 
                   1102:        /*
                   1103:         * Since we are in a path with QBAND_REDUCE (), check for QBACK before
                   1104:         * unfreezing the stream.
                   1105:         */
                   1106: 
                   1107:        {
                   1108:                unsigned long   back;
                   1109: 
                   1110:                if ((back = q->q_flag & QBACK) != 0)
                   1111:                        q->q_flag &= ~ QBACK;
                   1112: 
                   1113:                QUNFREEZE_TRACE (q, prev_pl);
                   1114: 
                   1115:                if (back)
                   1116:                        QUEUE_BACKENAB (q);
                   1117:        }
                   1118: }
                   1119: 
                   1120: 
                   1121: /*
                   1122:  * This internal function is used by bufcall () and esbbcall () to queue a
                   1123:  * STREAMS event cell on the queue for eventual processing once memory
                   1124:  * becomes available.
                   1125:  */
                   1126: 
                   1127: #if    __USE_PROTO__
                   1128: __LOCAL__ toid_t (STORE_EVENT) (sevent_t * seventp, int pri)
                   1129: #else
                   1130: __LOCAL__ toid_t
                   1131: STORE_EVENT __ARGS ((seventp, pri))
                   1132: sevent_t      *        seventp;
                   1133: int            pri;
                   1134: #endif
                   1135: {
                   1136:        pl_t            prev_pl;
                   1137:        selist_t      * selistp;
                   1138:        sevent_t      * sprev;
                   1139: 
                   1140:        /*
                   1141:         * Let's lock the list that we are going to thread the new event on.
                   1142:         */
                   1143: 
                   1144:        selistp = & str_mem->sm_bcevents [MAP_PRI_LEVEL (pri)];
                   1145: 
                   1146:        prev_pl = SELIST_LOCK (selistp);
                   1147: 
                   1148: 
                   1149: #if _TOID_MEMBER
                   1150:        /*
                   1151:         * Before we perform the insertion of the event cell, we use the above
                   1152:         * lock to make our ID code generation multiprocessor-safe.
                   1153:         */
                   1154: 
                   1155:        selistp->sl_id = (((seventp->se_id = selistp->sl_id) +
                   1156:                                TOID_INCREMENT) % TOID_MODULUS);
                   1157: 
                   1158:        ASSERT (seventp->se_id != 0);
                   1159:        ASSERT (TOID_TO_PRI (seventp->se_id) == pri);
                   1160: #endif
                   1161: 
                   1162:        /*
                   1163:         * RESEARCH NOTE: There doesn't seem to be any compelling reason to
                   1164:         * choose a particular policy for managing event cells. Try getting
                   1165:         * some data of performance effects for low->high, high->low and FIFO
                   1166:         * queueing.
                   1167:         */
                   1168: #if _FIFO_BUFCALL
                   1169:        /*
                   1170:         * FIFO queueing is nice and simple.
                   1171:         */
                   1172: 
                   1173:        if ((sprev = selistp->sl_tail) == NULL) {
                   1174: 
                   1175:                ASSERT (selistp->sl_head == NULL);
                   1176: 
                   1177:                selistp->sl_head = selistp->sl_tail = seventp;
                   1178:                seventp->se_prev = seventp->se_next = NULL;
                   1179:        } else {
                   1180: 
                   1181:                sprev->se_next = seventp;
                   1182:                seventp->se_prev = sprev;
                   1183:                seventp->se_next = NULL;
                   1184:                selistp->sl_tail = seventp;
                   1185:        }
                   1186: #else
                   1187:        /*
                   1188:         * Now insert the event cell in the event list, keeping it sorted from
                   1189:         * low size to high size.
                   1190:         */
                   1191: 
                   1192:        {
                   1193:                sevent_t      * sscan;
                   1194: 
                   1195:                for (sscan = selistp->sl_head, sprev = NULL ; sscan != NULL ;
                   1196:                     sscan = (sprev = sscan)->se_next) {
                   1197: 
                   1198:                        if (sscan->se_size > seventp->se_size)
                   1199:                                break;
                   1200:                }
                   1201: 
                   1202:                if (sprev == NULL)
                   1203:                        selistp->sl_head = seventp;
                   1204:                else
                   1205:                        sprev->se_next = seventp;
                   1206: 
                   1207:                if (sscan != NULL)
                   1208:                        sscan->se_prev = seventp;
                   1209: 
                   1210:                seventp->se_prev = sprev;
                   1211:                seventp->se_next = sscan;
                   1212:        }
                   1213: #endif
                   1214: 
                   1215:        SELIST_UNLOCK (selistp, prev_pl);
                   1216: 
                   1217: #if _TOID_MEMBER
                   1218:        return seventp->se_id;
                   1219: #endif
                   1220: }
                   1221: 
                   1222: 
                   1223: /*
                   1224:  * This local function factors out the common code in put () and
                   1225:  * QUEUE_PUTNEXT () [used to implement the putnext (), putnextctl () and
                   1226:  * similar functions].
                   1227:  *
                   1228:  * The queue must be frozen on entry to this function.
                   1229:  */
                   1230: 
                   1231: #if    __USE_PROTO__
                   1232: __LOCAL__ void (QUEUE_PUT) (queue_t * q, mblk_t * mp, pl_t prev_pl)
                   1233: #else
                   1234: __LOCAL__ void
                   1235: QUEUE_PUT __ARGS ((q, mp, prev_pl))
                   1236: queue_t              * q;
                   1237: mblk_t       * mp;
                   1238: pl_t           prev_pl;
                   1239: #endif
                   1240: {
                   1241:        QFROZEN_TRACE (q, "QUEUE_PUT");
                   1242: 
                   1243:        q->q_active ++;
                   1244: 
                   1245:        if (q->q_qinfo->qi_mstat != NULL)
                   1246:                q->q_qinfo->qi_mstat->ms_pcnt ++;
                   1247: 
                   1248:        QUNFREEZE_TRACE (q, prev_pl);
                   1249: 
                   1250: 
                   1251:        (* q->q_qinfo->qi_putp) (q, mp);
                   1252: 
                   1253: 
                   1254:        (void) QFREEZE_TRACE (q, "QUEUE_PUT");
                   1255: 
                   1256:        q->q_active --;
                   1257: 
                   1258:        if ((q->q_flag & QPROCSOFF) != 0 && q->q_active == 0) {
                   1259:                /*
                   1260:                 * Time to wake up the sleepers waiting for the put and
                   1261:                 * service routines on a queue to exit. See qprocsoff () for
                   1262:                 * a discussion of the locking protocol.
                   1263:                 */
                   1264: 
                   1265:                (void) LOCK (str_mem->sm_proc_lock, plstr);
                   1266:                SV_BROADCAST (str_mem->sm_proc_sv, 0);
                   1267:                UNLOCK (str_mem->sm_proc_lock, plstr);
                   1268:        }
                   1269: }
                   1270: 
                   1271: 
                   1272: /*
                   1273:  * This local function factors out most of the interesting part of putnext ()
                   1274:  * into a common block that can be called from any of the related group of
                   1275:  * functions putnext (), putnextctl (), putnextctl1 (), and qreply ().
                   1276:  */
                   1277: 
                   1278: #if    __USE_PROTO__
                   1279: __LOCAL__ void (QUEUE_PUTNEXT) (queue_t * q, mblk_t * mp)
                   1280: #else
                   1281: __LOCAL__ void
                   1282: QUEUE_PUTNEXT __ARGS ((q, mp))
                   1283: queue_t              * q;
                   1284: mblk_t       * mp;
                   1285: #endif
                   1286: {
                   1287:        pl_t            prev_pl;
                   1288: 
                   1289:        /*
                   1290:         * We call QUEUE_NEXT () to find the next queue on the stream that has
                   1291:         * not been disabled via qprocsoff (). It may be that there is no
                   1292:         * such queue. This can happen on a uniprocessor or multiprocessor if
                   1293:         * a device's interrupt routine begins generating data before the
                   1294:         * queue open () entry point has issued qprocson (). Since this is
                   1295:         * really an error, we complain about it.
                   1296:         */
                   1297: 
                   1298:        prev_pl = QFREEZE_TRACE (q, "QUEUE_PUTNEXT");
                   1299: 
                   1300:        q = QUEUE_NEXT (q);
                   1301: 
                   1302:        if (q != NULL) {
                   1303:                /*
                   1304:                 * We have found a queue we are allowed to put to.
                   1305:                 */
                   1306: 
                   1307:                QUEUE_PUT (q, mp, prev_pl);
                   1308:        } else {
                   1309:                /*
                   1310:                 * We have run off the end of the stream... we can
                   1311:                 * either wait, put the message anyway, or discard
                   1312:                 * the message. Either way, a warning is appropriate.
                   1313:                 */
                   1314: 
                   1315:                cmn_err (CE_WARN, "putnext () ran off end of stream");
                   1316:                freemsg (mp);
                   1317:        }
                   1318: 
                   1319:        QUNFREEZE_TRACE (q, prev_pl);
                   1320: }
                   1321: 
                   1322: 
                   1323: /*
                   1324:  * This internal function is similar in spirit to QUEUE_PUTNEXT (), above, but
                   1325:  * instead factors out the process of looking for a queue with a service
                   1326:  * procedure that can be enabled from the bcanputnext () and canputnext ()
                   1327:  * routines.
                   1328:  *
                   1329:  * Determines whether the caller can legitimately put downstream in the
                   1330:  * indicated priority band.
                   1331:  *
                   1332:  * The queue passed to this function cannot be frozen.
                   1333:  */
                   1334: 
                   1335: #if    __USE_PROTO__
                   1336: __LOCAL__ int (QBAND_SRVNEXT) (queue_t * q, uchar_t pri)
                   1337: #else
                   1338: __LOCAL__ int
                   1339: QBAND_SRVNEXT __ARGS ((q, pri))
                   1340: queue_t              * q;
                   1341: uchar_t                pri;
                   1342: #endif
                   1343: {
                   1344:        int             retval;
                   1345:        pl_t            prev_pl;
                   1346: 
                   1347:        /*
                   1348:         * Scan through the stream for a queue with a service procedure that
                   1349:         * we can enable.
                   1350:         */
                   1351: 
                   1352:        prev_pl = QFREEZE_TRACE (q, "QBAND_SRVNEXT");
                   1353: 
                   1354:        for (;;) {
                   1355: 
                   1356:                q = QUEUE_NEXT (q);
                   1357: 
                   1358:                if (q == NULL) {
                   1359:                        /*
                   1360:                         * We have run off the end of the stream, so return
                   1361:                         * true to the caller.
                   1362:                         */
                   1363: 
                   1364:                        retval = 1;
                   1365:                        break;
                   1366: 
                   1367:                } else if (q->q_qinfo->qi_srvp != NULL) {
                   1368: 
                   1369:                        retval = QBAND_CANPUT (q, pri);
                   1370:                        break;
                   1371:                }
                   1372: 
                   1373:                /*
                   1374:                 * No service procedure, try next queue in line.
                   1375:                 */
                   1376:        }
                   1377: 
                   1378:        QUNFREEZE_TRACE (q, prev_pl);
                   1379: 
                   1380: 
                   1381:        /*
                   1382:         * If there are no queues with service procedures, the caller is
                   1383:         * allowed to put by default; the special case above is an exception.
                   1384:         */
                   1385: 
                   1386:        return retval;
                   1387: }
                   1388: 
                   1389: 
                   1390: /*
                   1391:  * This function deals with allocating and initializing a message block from
                   1392:  * the message memory; unlike allocb (), an extra parameter can be used to
                   1393:  * cause this function to block if there is insufficient memory available to
                   1394:  * satisfy the request immediately.
                   1395:  */
                   1396: 
                   1397: #if    __USE_PROTO__
                   1398: mblk_t * (MSGB_ALLOC) (size_t size, int pri, int flag)
                   1399: #else
                   1400: mblk_t *
                   1401: MSGB_ALLOC __ARGS ((size, pri, flag))
                   1402: size_t         size;
                   1403: int            pri;
                   1404: int            flag;
                   1405: #endif
                   1406: {
                   1407:        mblk_t        * mblkp;
                   1408: 
                   1409:        ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP);
                   1410:        ASSERT (pri == BPRI_LO || pri == BPRI_MED || pri == BPRI_HI);
                   1411: 
                   1412:        if ((mblkp = STRMEM_ALLOC (MSGB_SIZE (size), pri, flag)) != NULL) {
                   1413:                /*
                   1414:                 * Note that we don't bother setting up the b_prev and
                   1415:                 * b_next members of the message block.
                   1416:                 */
                   1417: 
                   1418:                mblkp->b_cont = NULL;
                   1419:                mblkp->b_datap = MB_TO_DB (mblkp);
                   1420:                mblkp->b_rptr = DB_TO_DATA (mblkp->b_datap);
                   1421:                mblkp->b_wptr = mblkp->b_rptr;
                   1422: 
                   1423:                /*
                   1424:                 * We specially flag this message block as part of
                   1425:                 * a triple. While there are other ways we could test
                   1426:                 * this, for now we permit the possibility that a
                   1427:                 * client might change the attachments of data blocks
                   1428:                 * and message blocks perversely.
                   1429:                 */
                   1430: 
                   1431:                mblkp->b_flag = MSGTRIPLE;
                   1432:                mblkp->b_band = 0;
                   1433: 
                   1434:                mblkp->b_datap->db_base = mblkp->b_rptr;
                   1435:                mblkp->b_datap->db_lim = mblkp->b_rptr + size;
                   1436:                mblkp->b_datap->db_type = M_DATA;
                   1437:                mblkp->b_datap->db_ref = 1;
                   1438: 
                   1439:                mblkp->b_datap->db_frtnp = NULL;
                   1440:        }
                   1441: 
                   1442:        return mblkp;
                   1443: }
                   1444: 
                   1445: 
                   1446: /*
                   1447:  * This local helper function factors out some code in strlog () common to
                   1448:  * building the "struct log_ctl" headers for the log messages.
                   1449:  */
                   1450: 
                   1451: #if    __USE_PROTO__
                   1452: __LOCAL__ mblk_t * (STRLOG_MAKE) (short mid, short sid, char level,
                   1453:                                  ushort_t flags, ulong_t seq, ushort_t whoami,
                   1454:                                  int * copies, int * failures, mblk_t * data)
                   1455: #else
                   1456: __LOCAL__ mblk_t *
                   1457: STRLOG_MAKE __ARGS ((mid, sid, level, flags, seq, whoami, copies, failures, data))
                   1458: short          mid;
                   1459: short          sid;
                   1460: char           level;
                   1461: ushort_t       flags;
                   1462: ulong_t                seq;
                   1463: ushort_t       whoami;
                   1464: int          * copies;
                   1465: int          * failures;
                   1466: mblk_t       * data;
                   1467: #endif
                   1468: {
                   1469:        mblk_t        * ctl;
                   1470:        struct log_ctl * lcp;
                   1471:        int             alloc_pri;
                   1472:        int             log_pri;
                   1473: 
                   1474:        if ((flags & whoami) == 0)
                   1475:                return NULL;
                   1476: 
                   1477:        /*
                   1478:         * Work out an allocation priority for the M_PROTO message block that
                   1479:         * will contain the "log_ctl" description structure, and also
                   1480:         * work out a priority for the "mwc_pri" member of the "log_ctl"
                   1481:         * structure.
                   1482:         *
                   1483:         * This code is pretty funky; the real rules might be much simpler,
                   1484:         * but this is what I get from the docs. The "log_pri" rules go from
                   1485:         * low to high priority, so this code should match the order defined
                   1486:          * for the 
                   1487:         */
                   1488: 
                   1489:        if (whoami == SL_ERROR || (flags & SL_FATAL) != 0)
                   1490:                alloc_pri = BPRI_HI;
                   1491:        else if ((flags & SL_WARN) != 0)
                   1492:                alloc_pri = BPRI_MED;
                   1493:        else
                   1494:                alloc_pri = BPRI_LO;
                   1495: 
                   1496: 
                   1497:        /*
                   1498:         * if (whoami == SL_CONSOLE)
                   1499:         */
                   1500:        log_pri = LOG_INFO;
                   1501: 
                   1502:        if ((flags & SL_NOTE) != 0)
                   1503:                log_pri = LOG_NOTICE;
                   1504: 
                   1505:        if (whoami == SL_TRACE)
                   1506:                log_pri = LOG_DEBUG;
                   1507: 
                   1508:        if ((flags & SL_WARN) != 0)
                   1509:                log_pri = LOG_WARNING;
                   1510: 
                   1511:        if (whoami == SL_ERROR)
                   1512:                log_pri = LOG_ERR;
                   1513: 
                   1514:        if ((flags & SL_FATAL) != 0)
                   1515:                log_pri = LOG_CRIT;
                   1516: 
                   1517: 
                   1518:        /*
                   1519:         * Allocate the necessary structures and fill them in.
                   1520:         */
                   1521: 
                   1522:        if ((ctl = MSGB_ALLOC (sizeof (struct log_ctl), alloc_pri,
                   1523:                               KM_NOSLEEP)) == NULL) {
                   1524: 
                   1525:                (* failures) ++;
                   1526:                return NULL;    /* return failure */
                   1527:        }
                   1528: 
                   1529:        if (* copies == 0)
                   1530:                ctl->b_cont = data;
                   1531:        else if ((ctl->b_cont = dupb (data)) == NULL) {
                   1532: 
                   1533:                freeb (ctl);
                   1534: 
                   1535:                (* failures) ++;
                   1536:                return NULL;
                   1537:        }
                   1538: 
                   1539:        (* copies) ++;
                   1540: 
                   1541:        ctl->b_datap->db_type = M_PROTO;
                   1542:        lcp = (struct log_ctl *) ctl->b_rptr;
                   1543:        ctl->b_wptr = (uchar_t *) (lcp + 1);
                   1544: 
                   1545:        lcp->mwc_mid = mid;
                   1546:        lcp->mwc_sid = sid;
                   1547:        lcp->level = level;
                   1548:        lcp->flags = flags;
                   1549:        lcp->mwc_seqno = seq;
                   1550:        lcp->mwc_pri = log_pri | LOG_KERN;
                   1551: 
                   1552:        return ctl;
                   1553: }
                   1554: 
                   1555: 
                   1556: /*
                   1557:  * This function factors out common code from putbq () and putq () for finding
                   1558:  * the insertion point for a message. The original routines differed only in
                   1559:  * whether the search was for the end of a band or the front of a band. By
                   1560:  * passing in an appropriately adjusted band parameter, the same code can be
                   1561:  * made to do double duty.
                   1562:  *
                   1563:  * The queue passed to this function must be frozen.
                   1564:  */
                   1565: 
                   1566: #if    __USE_PROTO__
                   1567: __LOCAL__ void (QUEUE_PLACE_MSG) (queue_t * q, mblk_t * mp, uchar_t band)
                   1568: #else
                   1569: __LOCAL__ void
                   1570: QUEUE_PLACE_MSG __ARGS ((q, mp, band))
                   1571: queue_t              * q;
                   1572: mblk_t       * mp;
                   1573: uchar_t                band;
                   1574: #endif
                   1575: {
                   1576:        mblk_t        * scan;
                   1577: 
                   1578:        /*
                   1579:         * The first stage is to skip over all the high-priority messages, and \
                   1580:         * then to find the right band location.
                   1581:         */
                   1582: 
                   1583:        for (scan = q->q_first ; scan != NULL ; scan = scan->b_next)
                   1584:                if (! IS_PRI_MSG (scan))
                   1585:                        break;
                   1586: 
                   1587:        while (scan != NULL && scan->b_band > band)
                   1588:                scan = scan->b_next;
                   1589: 
                   1590:        /*
                   1591:         * Now we know where the message goes, do it.
                   1592:         */
                   1593: 
                   1594:        if ((mp->b_next = scan) == NULL) {
                   1595: 
                   1596:                if ((mp->b_prev = q->q_last) == NULL)
                   1597:                        q->q_first = mp;
                   1598:                else
                   1599:                        mp->b_prev->b_next = mp;
                   1600: 
                   1601:                q->q_last = mp;
                   1602:        } else {
                   1603: 
                   1604:                if ((mp->b_prev = scan->b_prev) == NULL)
                   1605:                        q->q_first = mp;
                   1606:                else
                   1607:                        mp->b_prev->b_next = mp;
                   1608: 
                   1609:                scan->b_prev = mp;
                   1610:        }
                   1611: }
                   1612: 
                   1613: 
                   1614: /*
                   1615:  *-STATUS:
                   1616:  *     DDI/DKI
                   1617:  *
                   1618:  *-NAME:
                   1619:  *     adjmsg          Trim bytes from a message
                   1620:  *
                   1621:  *-SYNOPSIS:
                   1622:  *     #include <sys/streams.h>
                   1623:  *
                   1624:  *     int adjmsg (mblk_t * mp, int len);
                   1625:  *
                   1626:  *-ARGUMENTS:
                   1627:  *     mp              Pointer to the message to be trimmed.
                   1628:  *
                   1629:  *     len             The number of bytes to be removed.
                   1630:  *
                   1631:  *-DESCRIPTION:
                   1632:  *     adjmsg () removes bytes from a message. |"len"| (the absolute value of
                   1633:  *     "len") specifies the how many bytes are to be removed. If "len" is
                   1634:  *     greater than 0, bytes are removed from the head of the message. If
                   1635:  *     "len" is less than 0, bytes are removed from the tail. adjmsg () fails
                   1636:  *     if |"len"| is greater than the number of bytes in "mp". If "len" spans
                   1637:  *     more than one message block in the message, the message blocks must be
                   1638:  *     the same type, or else adjmsg () will fail.
                   1639:  *
                   1640:  *-RETURN VALUE:
                   1641:  *     If the message can be trimmed successfully, 1 is returned. Otherwise,
                   1642:  *     0 is returned.
                   1643:  *
                   1644:  *-LEVEL:
                   1645:  *     Base or interrupt.
                   1646:  *
                   1647:  *-NOTES:
                   1648:  *     Does not sleep.
                   1649:  *
                   1650:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   1651:  *     held across calls to this function.
                   1652:  *
                   1653:  *     If "len" is greater than the amount of data in a single message block,
                   1654:  *             that message block is not freed. Rather, it is left linked in the
                   1655:  *     message, and its read and write pointers are set equal to each other,
                   1656:  *     indicating no data present in the block.
                   1657:  *
                   1658:  *-SEE ALSO:
                   1659:  *     msgb
                   1660:  */
                   1661: 
                   1662: #if    __USE_PROTO__
                   1663: int (adjmsg) (mblk_t * mp, int len)
                   1664: #else
                   1665: int
                   1666: adjmsg __ARGS ((mp, len))
                   1667: mblk_t       * mp;
                   1668: int            len;
                   1669: #endif
                   1670: {
                   1671:        uchar_t         msgtype = mp->b_datap->db_type;
                   1672:        int             result = 1;
                   1673: 
                   1674:        ASSERT (mp != NULL);
                   1675: 
                   1676:        /*
                   1677:         * The DDI/DKI does not specify whether the message blocks are to be
                   1678:         * left unmodified in the case of failure. For now, we interpret the
                   1679:         * semantics of the routine such that a failure leaves all the
                   1680:         * requested data removed, with the return value supplying an
                   1681:         * indication that overflow occurred.
                   1682:         */
                   1683: 
                   1684:        if (len >= 0) {
                   1685:                /*
                   1686:                 * Remove bytes forward from the head of the message.
                   1687:                 */
                   1688: 
                   1689:                while (len != 0) {
                   1690:                        mblk_t        * next;
                   1691: 
                   1692:                        if (mp->b_wptr - mp->b_rptr >= len) {
                   1693:                                /*
                   1694:                                 * We are only comsuming part of the message.
                   1695:                                 */
                   1696: 
                   1697:                                mp->b_rptr += len;
                   1698: 
                   1699:                                return 1;
                   1700:                        } else if ((next = mp->b_cont) == NULL) {
                   1701:                                /*
                   1702:                                 * All the message blocks in the message have
                   1703:                                 * been totally consumed, so return failure.
                   1704:                                 */
                   1705: 
                   1706:                                mp->b_rptr = mp->b_wptr;
                   1707: 
                   1708:                                return 0;
                   1709:                        }
                   1710: 
                   1711:                        /*
                   1712:                         * This message block has been consumed, so leave it
                   1713:                         * empty.
                   1714:                         */
                   1715: 
                   1716:                        len -= mp->b_wptr - mp->b_rptr;
                   1717: 
                   1718:                        mp->b_wptr = mp->b_rptr = mp->b_datap->db_base;
                   1719: 
                   1720:                        mp = next;
                   1721: 
                   1722:                        if (mp->b_datap->db_type != msgtype)
                   1723:                                return 0;       /* wrong types */
                   1724:                }
                   1725: 
                   1726:        } else {
                   1727:                mblk_t        * span = mp;
                   1728:                int             size = 0;
                   1729: 
                   1730:                /*
                   1731:                 * Since message blocks only have forward links, we have to
                   1732:                 * employ some subterfuge to implement this efficiently. We
                   1733:                 * first scan forward to discover the size and start of the
                   1734:                 * last span of message blocks with the same type.
                   1735:                 */
                   1736: 
                   1737:                for (;;) {
                   1738:                        size += mp->b_wptr - mp->b_rptr;
                   1739: 
                   1740:                        if ((mp = mp->b_cont) == NULL)
                   1741:                                break;
                   1742: 
                   1743:                        if (mp->b_datap->db_type != msgtype) {
                   1744:                                /*
                   1745:                                 * The type has changed, so we reset our count
                   1746:                                 * and start pointers to begin a new span.
                   1747:                                 */
                   1748: 
                   1749:                                size = 0;
                   1750:                                msgtype = mp->b_datap->db_type;
                   1751:                                span = mp;
                   1752:                        }
                   1753:                }
                   1754: 
                   1755: 
                   1756:                if (size < len) {
                   1757:                        /*
                   1758:                         * The user has requested too many bytes be removed,
                   1759:                         * so we return a failure indication and remove as
                   1760:                         * many as we are able.
                   1761:                         */
                   1762: 
                   1763:                        result = 0;
                   1764:                        len = size;
                   1765:                }
                   1766: 
                   1767: 
                   1768:                /*
                   1769:                 * Now we have the last span, we can scan forward for the
                   1770:                 * point where we must begin emptying messages.
                   1771:                 */
                   1772: 
                   1773:                while (size > 0) {
                   1774: 
                   1775:                        size -= span->b_wptr - span->b_rptr;
                   1776: 
                   1777:                        if (size < len) {
                   1778:                                /*
                   1779:                                 * The count of bytes remaining in the span
                   1780:                                 * is less than the threshold, so we start to
                   1781:                                 * remove data.
                   1782:                                 */
                   1783: 
                   1784:                                span->b_wptr -= (len - size);
                   1785: 
                   1786:                                len = size;
                   1787:                        }
                   1788: 
                   1789:                        span = span->b_next;
                   1790:                }
                   1791:        }
                   1792: 
                   1793:        return result;
                   1794: }
                   1795: 
                   1796: 
                   1797: /*
                   1798:  *-STATUS:
                   1799:  *     DDI/DKI
                   1800:  *
                   1801:  *-NAME:
                   1802:  *     allocb          Allocate a message block
                   1803:  *
                   1804:  *-SYNOPSIS:
                   1805:  *     #include <sys/types.h>
                   1806:  *     #include <sys/stream.h>
                   1807:  *
                   1808:  *     mblk_t * allocb (int size, uint_t pri);
                   1809:  *
                   1810:  *-ARGUMENTS:
                   1811:  *     size            The number of bytes in the message block.
                   1812:  *
                   1813:  *     pri             Priority of the request. This can take on one of three
                   1814:  *                     values: BPRI_LO, BPRI_MED, or BPRI_HI.
                   1815:  *
                   1816:  *-DESCRIPTION:
                   1817:  *     allocb () tries to allocate a STREAMS message block. Buffer allocation
                   1818:  *     fails only when the system is out of memory. If no buffer is
                   1819:  *     available, the bufcall () function can help a module recover from an
                   1820:  *     allocation failure.
                   1821:  *
                   1822:  *     The "pri" argument is a hint to the allocator indicating how badly the
                   1823:  *     message is needed. BPRI_LO should be used for normal data allocations,
                   1824:  *     BPRI_MED should be used for other non-critical allocations. BPRI_HI
                   1825:  *     should be used for allocations that absolutely must succeed, even
                   1826:  *     though success is not guaranteed. Some implementations may choose to
                   1827:  *     ignore this parameter.
                   1828:  *
                   1829:  *-RETURN VALUE:
                   1830:  *     If successful, allocb () returns a pointer to the allocated message
                   1831:  *     block of type M_DATA (defined in <sys/stream.h>). If a block cannot be
                   1832:  *     allocated, a NULL pointer is returned.
                   1833:  *
                   1834:  *-LEVEL:
                   1835:  *     Base or Interrupt.
                   1836:  *
                   1837:  *-NOTES:
                   1838:  *     Does not sleep.
                   1839:  *
                   1840:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   1841:  *     held across calls to this function.
                   1842:  *
                   1843:  *-SEE ALSO:
                   1844:  *     bufcall (), esballoc (), esbbcall (), freeb (), msgb
                   1845:  */
                   1846: 
                   1847: #if    __USE_PROTO__
                   1848: mblk_t * (allocb) (int size, uint_t pri)
                   1849: #else
                   1850: mblk_t *
                   1851: allocb __ARGS ((size, pri))
                   1852: uint_t         size;
                   1853: uint_t         pri;
                   1854: #endif
                   1855: {
                   1856:        ASSERT (size >= 0);
                   1857:        ASSERT (ATOMIC_FETCH_UCHAR (str_mem->sm_init) &&
                   1858:                str_mem->sm_msg_lock != NULL);
                   1859: 
                   1860:        /*
                   1861:         * Since we allocate things in triples, "allocb (0)" could be legal if
                   1862:         * we wanted. There aren't any compelling reasons either way, but for
                   1863:         * simplicity I'll permit it.
                   1864:         */
                   1865: 
                   1866: #if 0
                   1867:        if (size == 0)
                   1868:                return NULL;
                   1869: #endif
                   1870: 
                   1871:        return MSGB_ALLOC (size, pri, KM_NOSLEEP);
                   1872: }
                   1873: 
                   1874: 
                   1875: /*
                   1876:  *-STATUS:
                   1877:  *     DDI/DKI
                   1878:  *
                   1879:  *-NAME:
                   1880:  *     bcanput         Test for flow control in specified priority band.
                   1881:  *
                   1882:  *-SYNOPSIS:
                   1883:  *     #include <sys/types.h>
                   1884:  *     #include <sys/stream.h>
                   1885:  *
                   1886:  *     int bcanput (queue_t * q, uchar_t pri);
                   1887:  *
                   1888:  *-ARGUMENTS:
                   1889:  *     q               Pointer to the message queue.
                   1890:  *
                   1891:  *     pri             Message priority.
                   1892:  *
                   1893:  *-DESCRIPTION:
                   1894:  *     bcanput () tests if there is room for a message in priority band "pri"
                   1895:  *     of the queue pointed to by "q". The queue _must_ have a service
                   1896:  *     procedure.
                   1897:  *
                   1898:  *     If "pri" is 0, the bcanput () call is equivalent to a call to
                   1899:  *     canput ().
                   1900:  *
                   1901:  *     It is possible because of race conditions to test for room using
                   1902:  *     bcanput () and get an indication that there is room for a message, and
                   1903:  *     then have the queue fill up before subsequently enqueuing the message,
                   1904:  *     causing a violation of flow control. This is not a problem, since the
                   1905:  *     violation of flow control in this case is bounded.
                   1906:  *
                   1907:  *-RETURN VALUE:
                   1908:  *     bcanput () returns 1 if a message of priority "pri" can be placed on
                   1909:  *     the queue. 0 is returned if a message of priority "pri" cannot be
                   1910:  *     enqueued because of flow control within the priority band.
                   1911:  *
                   1912:  *-LEVEL:
                   1913:  *     Base or interrupt.
                   1914:  *
                   1915:  *-NOTES:
                   1916:  *     Does not sleep.
                   1917:  *
                   1918:  *     The driver writer is responsible for both testing a queue with
                   1919:  *     bcanput () and refraining from placing a message if bcanput () fails.
                   1920:  *
                   1921:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   1922:  *     calling this function.
                   1923:  *
                   1924:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   1925:  *     held across calls to this function.
                   1926:  *
                   1927:  *     The "q" argument may not reference "q_next" (for example, an argument
                   1928:  *     of "q->q_next" is erroneous on a multiprocessor and is disallowed by
                   1929:  *     the DDI/DKI). "bcanputnext (q)" is provided as a multiprocessor-safe
                   1930:  *     equivalent to the common call "bcanput (q->q_next)", which is no
                   1931:  *     longer allowed [see bcanputnext ()].
                   1932:  *
                   1933:  *-SEE ALSO:
                   1934:  *     bcanputnext (), canput (), canputnext (), putbq (), putnext ()
                   1935:  */
                   1936: 
                   1937: #if    __USE_PROTO__
                   1938: int (bcanput) (queue_t * q, uchar_t pri)
                   1939: #else
                   1940: int
                   1941: bcanput __ARGS ((q, pri))
                   1942: queue_t              * q;
                   1943: uchar_t                pri;
                   1944: #endif
                   1945: {
                   1946:        pl_t            prev_pl;
                   1947:        int             result = 1;
                   1948: 
                   1949:        prev_pl = QFREEZE_TRACE (q, "bcanput");
                   1950: 
                   1951:        result = QBAND_CANPUT (q, pri);
                   1952: 
                   1953:        QUNFREEZE_TRACE (q, prev_pl);
                   1954: 
                   1955:        return result;
                   1956: }
                   1957: 
                   1958: 
                   1959: /*
                   1960:  *-STATUS:
                   1961:  *     DDI/DKI
                   1962:  *
                   1963:  *-NAME:
                   1964:  *     bcanputnext     Test for flow control in specified priority band.
                   1965:  *
                   1966:  *-SYNOPSIS:
                   1967:  *     #include <sys/types.h>
                   1968:  *     #include <sys/stream.h>
                   1969:  *
                   1970:  *     int bcanputnext (queue_t * q, uchar_t pri);
                   1971:  *
                   1972:  *-ARGUMENTS:
                   1973:  *     q               Pointer to the message queue.
                   1974:  *
                   1975:  *     pri             Message priority.
                   1976:  *
                   1977:  *-DESCRIPTION:
                   1978:  *     bcanputnext () searches through the stream (starting at "q->q_next")
                   1979:  *     until it finds a queue containing a service routine, or until it
                   1980:  *     reaches the end of the stream. If found, the queue containing the
                   1981:  *     service routine is tested to see if a message in priority band "pri"
                   1982:  *     can be enqueued. If the band is full, bcanputnext () marks the queue
                   1983:  *     to automatically back-enable the caller's service routine when the
                   1984:  *     amount of data in messages on the queue has reached its low water
                   1985:  *     mark.
                   1986:  *
                   1987:  *     If "pri" is 0, the bcanputnext () call is equivalent to a call to
                   1988:  *     canputnext ().
                   1989:  *
                   1990:  *     It is possible because of race conditions to test for room using
                   1991:  *     bcanputnext () and get an indication that there is room for a message,
                   1992:  *     and then have the queue fill up before subsequently enqueuing the
                   1993:  *     message, causing a violation of flow control. This is not a problem,
                   1994:  *     since the violation of flow control in this case is bounded.
                   1995:  *
                   1996:  *-RETURN VALUE:
                   1997:  *     bcanputnext () returns 1 if a message of priority "pri" can be sent in
                   1998:  *     the stream, or 0 if the stream is flow-controlled. If bcanputnext ()
                   1999:  *     reaches the end of the stream without finding a queue with a service
                   2000:  *     procedure, then it returns 1.
                   2001:  *
                   2002:  *-LEVEL:
                   2003:  *     Base or interrupt.
                   2004:  *
                   2005:  *-NOTES:
                   2006:  *     Does not sleep.
                   2007:  *
                   2008:  *     The driver writer is responsible for both testing a queue with
                   2009:  *     bcanputnext () and refraining from placing a message if bcanputnext ()
                   2010:  *     fails.
                   2011:  *
                   2012:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   2013:  *     calling this function.
                   2014:  *
                   2015:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2016:  *     held across calls to this function.
                   2017:  *
                   2018:  *     The "q" argument may not reference "q_next" (for example, an argument
                   2019:  *     of "q->q_next" is erroneous on a multiprocessor and is disallowed by
                   2020:  *     the DDI/DKI). "bcanputnext (q)" is provided as a multiprocessor-safe
                   2021:  *     equivalent to the common call "bcanput (q->q_next)", which is no
                   2022:  *     longer allowed [see bcanputnext ()].
                   2023:  *
                   2024:  *-SEE ALSO:
                   2025:  *     bcanput (), canput (), canputnext (), putbq (), putnext ()
                   2026:  */
                   2027: 
                   2028: #if    __USE_PROTO__
                   2029: int (bcanputnext) (queue_t * q, uchar_t pri)
                   2030: #else
                   2031: int
                   2032: bcanputnext __ARGS ((q, pri))
                   2033: queue_t              * q;
                   2034: uchar_t                pri;
                   2035: #endif
                   2036: {
                   2037:        QUEUE_TRACE (q, "bcanputnext");
                   2038: 
                   2039:        return QBAND_SRVNEXT (q, pri);
                   2040: }
                   2041: 
                   2042: 
                   2043: /*
                   2044:  * Note: backq () is not present in the System V DDI/DKI For Intel Processors
                   2045:  * with Multiprocessing reference, and is listed in one of the appendices of
                   2046:  * that volume as having been removed in the R3.2 to R4 transition. However,
                   2047:  * the function is present in the regular generic System V DDI/DKI.
                   2048:  */
                   2049: 
                   2050: #if 0
                   2051: /*
                   2052:  *-STATUS:
                   2053:  *     DDI/DKI
                   2054:  *
                   2055:  *-NAME:
                   2056:  *     backq           Get pointer to the queue behind the current queue.
                   2057:  *
                   2058:  *-SYNOPSIS:
                   2059:  *     #include <sys/stream.h>
                   2060:  *
                   2061:  *     queue_t * backq (queue_t * q);
                   2062:  *
                   2063:  *-ARGUMENTS:
                   2064:  *     q               Pointer to the current queue.
                   2065:  *
                   2066:  *-DESCRIPTION:
                   2067:  *     backq () returns a pointer to the queue preceding "q". If "q" is a
                   2068:  *     read queue, backq () returns a pointer to the queue downstream from
                   2069:  *     "q", unless it is the stream end. If "q" is a write queue, backq ()
                   2070:  *     returns a pointer to the next queue upstream from "q", unless it is
                   2071:  *     the stream head.
                   2072:  *
                   2073:  *-RETURN VALUE:
                   2074:  *     If successful, backq () returns a pointer to the queue preceding the
                   2075:  *     current queue. Otherwise, it returns NULL.
                   2076:  *
                   2077:  *-LEVEL:
                   2078:  *     Base or interrupt.
                   2079:  *
                   2080:  *-NOTES:
                   2081:  *     Does not sleep.
                   2082:  *
                   2083:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   2084:  *     calling this function.
                   2085:  *
                   2086:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2087:  *     held across calls to this function.
                   2088:  *
                   2089:  *     If the case of a STREAMS-based fifo, this function takes no special
                   2090:  *     action at the midpoint of the stream where the read and write sides
                   2091:  *     interchange.
                   2092:  */
                   2093: 
                   2094: #if    __USE_PROTO__
                   2095: queue_t * (backq) (queue_t * q)
                   2096: #else
                   2097: queue_t *
                   2098: backq __ARGS ((q))
                   2099: queue_t              * q;
                   2100: #endif
                   2101: {
                   2102:        q = OTHERQ (q);
                   2103: 
                   2104:        q = QUEUE_NEXT (q);
                   2105: 
                   2106:        if (q == NULL)
                   2107:                return NULL;
                   2108: 
                   2109:        return OTHERQ (q);
                   2110: }
                   2111: #endif
                   2112: 
                   2113: 
                   2114: /*
                   2115:  *-STATUS:
                   2116:  *     DDI/DKI
                   2117:  *
                   2118:  *-NAME:
                   2119:  *     bufcall         Call a function when a buffer becomes available.
                   2120:  *
                   2121:  *-SYNOPSIS:
                   2122:  *     #include <sys/types.h>
                   2123:  *     #include <sys/stream.h>
                   2124:  *
                   2125:  *     toid_t bufcall (uint_t size, int pri, void (* func) (), long arg);
                   2126:  *
                   2127:  *-ARGUMENTS:
                   2128:  *     size            Number of bytes in the buffer to be allocated (from
                   2129:  *                     the failed allocb () request).
                   2130:  *
                   2131:  *     pri             Priority of the allocb () allocation request (BPRI_LO,
                   2132:  *                     BPRI_MED, or BPRI_HI).
                   2133:  *
                   2134:  *     func            Fuction or driver routine to be called when a buffer
                   2135:  *                     becomes available.
                   2136:  *
                   2137:  *     arg             Argument to the function to be called when a buffer
                   2138:  *                     becomes available.
                   2139:  *
                   2140:  *-DESCRIPTION:
                   2141:  *     bufcall () serves as a timeout call of indeterminate length. When a
                   2142:  *     buffer allocation request fails, bufcall () can be used to schedule
                   2143:  *     the routine "func" to be called with the argument "arg" when a buffer
                   2144:  *     of at least "size" bytes becomes available.
                   2145:  *
                   2146:  *     When "func" runs, all interrupts from STREAMS devices will be blocked
                   2147:  *     on the processor on which it is running. "func" will have no user
                   2148:  *     context and may not call any function that sleeps.
                   2149:  *
                   2150:  *-RETURN VALUE:
                   2151:  *     If successful, bufcall () returns a non-zero value that identifies the
                   2152:  *     scheduling request. This non-zero identifier may be passed to
                   2153:  *     unbufcall () to cancel the request. If any failure occurs, bufcall ()
                   2154:  *     returns 0.
                   2155:  *
                   2156:  *-LEVEL:
                   2157:  *     Base or interrupt.
                   2158:  *
                   2159:  *-NOTES:
                   2160:  *     Does not sleep.
                   2161:  *
                   2162:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2163:  *     held across calls to this function.
                   2164:  *
                   2165:  *     Even when "func" is called, allocb () can still fail if another
                   2166:  *     module or driver had allocated the memory before "func" was able to
                   2167:  *     call allocb ().
                   2168:  *
                   2169:  *-SEE ALSO:
                   2170:  *     allocb (), esballoc (), esbbcall (), itimeout (), unbufcall ().
                   2171:  */
                   2172: 
                   2173: #if    __USE_PROTO__
                   2174: toid_t (bufcall) (uint_t size, int pri, ...)
                   2175: #else
                   2176: toid_t
                   2177: bufcall __ARGS ((size, pri))
                   2178: uint_t         size;
                   2179: int            pri;
                   2180: #endif
                   2181: {
                   2182:        se_funcptr_t    func;
                   2183:        long            arg;
                   2184:        va_list         arglist;
                   2185:        sevent_t      * seventp;
                   2186: 
                   2187: 
                   2188:        /*
                   2189:         * Before we do anything, we fetch the two other arguments. We use
                   2190:         * the variable-argument function convention to get around problems
                   2191:         * with implicit conversions introduced by having a prototype for
                   2192:         * this function visible.
                   2193:         *
                   2194:         * This is a generic problem with callbacks, since the shape of a
                   2195:         * function type includes the shapes of the function arguments, and
                   2196:         * because we want to pass some argument to the user-supplied function
                   2197:         * without knowing its type (and hence, we must not cause any implicit
                   2198:         * conversions on its value).
                   2199:         */
                   2200: 
                   2201:        va_start (arglist, pri);
                   2202: 
                   2203:        func = va_arg (arglist, se_funcptr_t);
                   2204:        arg = va_arg (arglist, long);
                   2205: 
                   2206:        va_end (arglist);
                   2207: 
                   2208: 
                   2209:        /*
                   2210:         * It may be that NULL is defined in such a way that it is not
                   2211:         * meaningful to compare it with a function pointer, so we just cast
                   2212:         * a zero to get the right kind of effect.
                   2213:         *
                   2214:         * We add some extra assertions below to check that "long" is of
                   2215:         * sufficient size to contain all likely parameter data items. For
                   2216:         * C, "likely" means the fundamental types, which has to include
                   2217:         * pointers to functions, pointers to void, and also pointers to
                   2218:         * structures since under C++ there is currently no guarantee to match
                   2219:         * the ISO C requirement that a pointer of type "void *" be able to
                   2220:         * hold the value of any pointer type without loss of information.
                   2221:         * [We don't consider member pointers here; they are pathological]
                   2222:         */
                   2223: 
                   2224:        ASSERT (sizeof (se_funcptr_t) <= sizeof (long) &&
                   2225:                sizeof (_VOID *) <= sizeof (long) &&
                   2226:                sizeof (selist_t *) <= sizeof (long));
                   2227: 
                   2228:        ASSERT (func != (se_funcptr_t) 0);
                   2229:        ASSERT (pri == BPRI_LO || pri == BPRI_HI || pri == BPRI_LO);
                   2230: 
                   2231: 
                   2232:        /*
                   2233:         * Here we *could* lock and test the available space in the STREAMS
                   2234:         * message heap to see whether sufficient space to satisfy the
                   2235:         * request has become available between the failed allocb () and
                   2236:         * the bufcall () request.
                   2237:         *
                   2238:         * The question is whether the extra time that the heap is locked is
                   2239:         * worth overcoming a delay for a freemsg () to trigger the bufcall ()
                   2240:         * later, especially given the fact that we'll have to unlock the
                   2241:         * heap to call the user's callback (introducing the opportunity for
                   2242:         * the newly-discovered space to vanish).
                   2243:         *
                   2244:         * All in all, once things get to the bufcall () stage there seems
                   2245:         * little reason to keep pushing the system, so we don't bother.
                   2246:         */
                   2247: 
                   2248:        /*
                   2249:         * First off, let's get ourselves an event cell. This is mutually
                   2250:         * dependent with the ID generation policy; if ID codes are stored in
                   2251:         * the event cells, we are free to allocate and discard from a general
                   2252:         * memory pool; if ID codes are not stored, then they must reflect
                   2253:         * some persistent attribute of the cell, which usually implies that
                   2254:         * cells come from some nonshrinking managed pool.
                   2255:         *
                   2256:         * Of course, a generative ID code scheme requires extra locking in
                   2257:         * the absence of atomic FETCH_AND_INCREMENT () operations. In this
                   2258:         * implementation, we get around this by using the list-head locks
                   2259:         * to guard the counter operations. [This has interesting implications
                   2260:         * for the design of a generic list-manipulation facility.] 
                   2261:         */
                   2262: 
                   2263: #if _TOID_MEMBER
                   2264:        if ((seventp = (sevent_t *) kmem_alloc (sizeof (sevent_t),
                   2265:                                                KM_NOSLEEP)) == NULL)
                   2266:                return 0;
                   2267: #else
                   2268: #error Need an allocator for event cells that matches the ID policy
                   2269: #endif
                   2270: 
                   2271:        /*
                   2272:         * Fill in the event cell. Note that the size member includes the
                   2273:         * memory space required for the message block and data block!
                   2274:         */
                   2275: 
                   2276:        seventp->se_arg = arg;
                   2277:        seventp->se_func = func;
                   2278:        seventp->se_size = MSGB_SIZE (size);
                   2279: 
                   2280: 
                   2281:        return STORE_EVENT (seventp, pri);
                   2282: }
                   2283: 
                   2284: 
                   2285: /*
                   2286:  *-STATUS:
                   2287:  *     DDI/DKI
                   2288:  *
                   2289:  *-NAME:
                   2290:  *     canput          Test for room in a message queue.
                   2291:  *
                   2292:  *-SYNOPSIS:
                   2293:  *     #include <sys/stream.h>
                   2294:  *
                   2295:  *     int canput (queue_t * q);
                   2296:  *
                   2297:  *-ARGUMENTS:
                   2298:  *     q               Pointer to the message queue.
                   2299:  *
                   2300:  *-DESCRIPTION:
                   2301:  *     canput () tests if there is room for a message in the queue pointed to
                   2302:  *     by "q". The queue _must_ have a service procedure.
                   2303:  *
                   2304:  *     It is possivle because of race conditions to test for room using
                   2305:  *     canput () and get an indication that there is room for a message, and
                   2306:  *     then have the queue fill up before subsequently enqueuing the message,
                   2307:  *     causing a violation of flow control. This is not a problem, since the
                   2308:  *     violation of flow control in this case is bounded.
                   2309:  *
                   2310:  *-RETURN VALUE:
                   2311:  *     canput () returns 1 if a message can be placed on the queue. 0 is
                   2312:  *     returned if a message cannot be enqueued because of flow control.
                   2313:  *
                   2314:  *-LEVEL:
                   2315:  *     Base or interrupt.
                   2316:  *
                   2317:  *-NOTES:
                   2318:  *     Does not sleep.
                   2319:  *
                   2320:  *     The driver writer is responsible for both testing a queue with
                   2321:  *     canput () and refraining from placing a message if canput () fails.
                   2322:  *
                   2323:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   2324:  *     calling this function.
                   2325:  *
                   2326:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2327:  *     held across calls to this function.
                   2328:  *
                   2329:  *     The "q" argument may not reference "q_next" (for example, an argument
                   2330:  *     of "q->q_next" is erroneous on a multiprocessor and is disallowed by
                   2331:  *     the DDI/DKI). "canputnext (q)" is provided as a multiprocessor-safe
                   2332:  *     equivalent to the common call "canput (q->q_next)", which is no
                   2333:  *     longer allowed [see canputnext ()].
                   2334:  *
                   2335:  *-SEE ALSO:
                   2336:  *     bcanputnext (), bcanput (), canputnext (), putbq (), putnext ()
                   2337:  */
                   2338: 
                   2339: #if    __USE_PROTO__
                   2340: int (canput) (queue_t * q)
                   2341: #else
                   2342: int
                   2343: canput __ARGS ((q))
                   2344: queue_t              * q;
                   2345: #endif
                   2346: {
                   2347:        pl_t            prev_pl;
                   2348:        int             result = 1;
                   2349: 
                   2350:        prev_pl = QFREEZE_TRACE (q, "canput");
                   2351: 
                   2352:        if ((q->q_flag & QFULL) != 0) {
                   2353:                /*
                   2354:                 * We must set the following flag to indicate that the
                   2355:                 * queue has a writer who has made a failed write
                   2356:                 * attempt.
                   2357:                 */
                   2358: 
                   2359:                q->q_flag |= QWANTW;
                   2360: 
                   2361:                result = 0;
                   2362:        }
                   2363: 
                   2364:        QUNFREEZE_TRACE (q, prev_pl);
                   2365: 
                   2366:        return result;
                   2367: }
                   2368: 
                   2369: 
                   2370: /*
                   2371:  *-STATUS:
                   2372:  *     DDI/DKI
                   2373:  *
                   2374:  *-NAME:
                   2375:  *     canputnext      Test for flow control in a stream.
                   2376:  *
                   2377:  *-SYNOPSIS:
                   2378:  *     #include <sys/stream.h>
                   2379:  *
                   2380:  *     int bcanputnext (queue_t * q);
                   2381:  *
                   2382:  *-ARGUMENTS:
                   2383:  *     q               Pointer to the message queue.
                   2384:  *
                   2385:  *-DESCRIPTION:
                   2386:  *     canputnext () searches through the stream (starting at "q->q_next")
                   2387:  *     until it finds a queue containing a service routine, or until it
                   2388:  *     reaches the end of the stream. If found, the queue containing the
                   2389:  *     service routine is tested to see if there is room for a message in the
                   2390:  *     queue. If the band is full, canputnext () marks the queue to
                   2391:  *     automatically back-enable the caller's service routine when the amount
                   2392:  *     of data in messages on the queue has reached its low water mark.
                   2393:  *
                   2394:  *     It is possible because of race conditions to test for room using
                   2395:  *     canputnext () and get an indication that there is room for a message,
                   2396:  *     and then have the queue fill up before subsequently enqueuing the
                   2397:  *     message, causing a violation of flow control. This is not a problem,
                   2398:  *     since the violation of flow control in this case is bounded.
                   2399:  *
                   2400:  *-RETURN VALUE:
                   2401:  *     canputnext () returns 1 if a message can be sent in the stream, or 0
                   2402:  *     if the stream is flow-controlled. If canputnext () reaches the end of
                   2403:  *     the stream without finding a queue with a service procedure, then it
                   2404:  *     returns 1.
                   2405:  *
                   2406:  *-LEVEL:
                   2407:  *     Base or interrupt.
                   2408:  *
                   2409:  *-NOTES:
                   2410:  *     Does not sleep.
                   2411:  *
                   2412:  *     The driver writer is responsible for both testing a queue with
                   2413:  *     bcanputnext () and refraining from placing a message if bcanputnext ()
                   2414:  *     fails.
                   2415:  *
                   2416:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   2417:  *     calling this function.
                   2418:  *
                   2419:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2420:  *     held across calls to this function.
                   2421:  *
                   2422:  *     The "q" argument may not reference "q_next" (for example, an argument
                   2423:  *     of "q->q_next" is erroneous on a multiprocessor and is disallowed by
                   2424:  *     the DDI/DKI). "bcanputnext (q)" is provided as a multiprocessor-safe
                   2425:  *     equivalent to the common call "bcanput (q->q_next)", which is no
                   2426:  *     longer allowed [see bcanputnext ()].
                   2427:  *
                   2428:  *-SEE ALSO:
                   2429:  *     bcanput (), bcanputnext (), canput (), putbq (), putnext ()
                   2430:  */
                   2431: 
                   2432: #if    __USE_PROTO__
                   2433: int (canputnext) (queue_t * q)
                   2434: #else
                   2435: int
                   2436: canputnext __ARGS ((q))
                   2437: queue_t              * q;
                   2438: #endif
                   2439: {
                   2440:        QUEUE_TRACE (q, "canputnext");
                   2441: 
                   2442:        /*
                   2443:         * Rather than depend on canput () above, we'll use the band-capable
                   2444:         * function QBAND_SRVNEXT () and depend on its ability to handle
                   2445:         * band 0. The mechanics of iterating through a stream are much more
                   2446:         * complex now than in the old SVR3.2 days due to both freezestr ()
                   2447:         * and qprocsoff ().
                   2448:         */
                   2449: 
                   2450:        return QBAND_SRVNEXT (q, 0);
                   2451: }
                   2452: 
                   2453: 
                   2454: /*
                   2455:  *-STATUS:
                   2456:  *     DDI/DKI
                   2457:  *
                   2458:  *-NAME:
                   2459:  *     copyb           Copy a message block.
                   2460:  *
                   2461:  *-SYNOPSIS:
                   2462:  *     #include <sys/stream.h>
                   2463:  *
                   2464:  *     mblk_t * copyb (mblk_t * bp);
                   2465:  *
                   2466:  *-ARGUMENTS:
                   2467:  *     bp              Pointer to the message block from which data are
                   2468:  *                     copied.
                   2469:  *
                   2470:  *-DESCRIPTION:
                   2471:  *     copyb () allocates a new message block, and copies into it the data
                   2472:  *     from the block pointed to by "bp". The new block will be at least as
                   2473:  *     large as the block being copied. The "b_rptr" and "b_wptr" members of
                   2474:  *     the message block pointed to by "bp" are used to determine how many
                   2475:  *     bytes to copy.
                   2476:  *
                   2477:  *-RETURN VALUE:
                   2478:  *     If successful, copyb () returns a pointer to the newly allocated
                   2479:  *     message block containing the copied data. Otherwise, it returns a NULL
                   2480:  *     pointer.
                   2481:  *
                   2482:  *-LEVEL:
                   2483:  *     Base or interrupt.
                   2484:  *
                   2485:  *-NOTES:
                   2486:  *     Does not sleep.
                   2487:  *
                   2488:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2489:  *     held across calls to this function.
                   2490:  *
                   2491:  *-SEE ALSO:
                   2492:  *     allocb (), copymsg (), msgb
                   2493:  */
                   2494: 
                   2495: #define        ALLOW_EMPTY_COPIES
                   2496: 
                   2497: #if    __USE_PROTO__
                   2498: mblk_t * (copyb) (mblk_t * bp)
                   2499: #else
                   2500: mblk_t *
                   2501: copyb __ARGS ((bp))
                   2502: mblk_t       * bp;
                   2503: #endif
                   2504: {
                   2505:        mblk_t        * newmsg;
                   2506:        size_t          size;
                   2507: 
                   2508:        ASSERT (bp != NULL && bp->b_datap != NULL);
                   2509: 
                   2510:        /*
                   2511:         * What to do if there is no real data in the original message?
                   2512:         *
                   2513:         * Copy it anyway, I guess.
                   2514:         */
                   2515: 
                   2516:        size = bp->b_wptr - bp->b_rptr;
                   2517: 
                   2518:        if (size == 0)
                   2519:                return MSGB_ALLOC (0, BPRI_LO, KM_NOSLEEP);
                   2520: 
                   2521: 
                   2522:        /*
                   2523:         * In this implementation we only allocate exactly as much space as
                   2524:         * we require (thus opening the zero-length issue). It is possible to
                   2525:         * interpret the wording of the manual-page as implying that the size
                   2526:         * of the new block is at least the size of the old block including
                   2527:         * unused space, but that doesn't seem reasonable. I read that
                   2528:         * requirement as merely pointing out that the allocator can give
                   2529:         * more memory to the new block that is strictly necessary.
                   2530:         */
                   2531: 
                   2532:        if ((newmsg = MSGB_ALLOC (size, BPRI_LO, KM_NOSLEEP)) != NULL) {
                   2533: 
                   2534:                newmsg->b_datap->db_type = bp->b_datap->db_type;
                   2535: 
                   2536:                memcpy (newmsg->b_rptr, bp->b_rptr, size);
                   2537: 
                   2538:                newmsg->b_wptr += size;
                   2539:        }
                   2540: 
                   2541:        return newmsg;
                   2542: }
                   2543: 
                   2544: 
                   2545: /*
                   2546:  *-STATUS:
                   2547:  *     DDI/DKI
                   2548:  *
                   2549:  *-NAME:
                   2550:  *     copymsg         Copy a message.
                   2551:  *
                   2552:  *-SYNOPSIS:
                   2553:  *     #include <sys/stream.h>
                   2554:  *
                   2555:  *     mblk_t * copymsg (mblk_t * mp);
                   2556:  *
                   2557:  *-ARGUMENTS:
                   2558:  *     mp              Pointer to the message to be copied.
                   2559:  *
                   2560:  *-DESCRIPTION:
                   2561:  *     copymsg () forms a new message by allocating message blocks, copies
                   2562:  *     the conents of the message referred to by "mp" (using the copyb ()
                   2563:  *     function) and returns a pointer to the new message.
                   2564:  *
                   2565:  *-RETURN VALUE:
                   2566:  *     If successful, copymsg () returns a pointer to the new message.
                   2567:  *     Otherwise, it returns a NULL pointer.
                   2568:  *
                   2569:  *-LEVEL:
                   2570:  *     Base or interrupt.
                   2571:  *
                   2572:  *-NOTES:
                   2573:  *     Does not sleep.
                   2574:  *
                   2575:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2576:  *     held across calls to this function.
                   2577:  *
                   2578:  *-SEE ALSO:
                   2579:  *     allocb (), copyb (), msgb
                   2580:  */
                   2581: 
                   2582: #if    __USE_PROTO__
                   2583: mblk_t * (copymsg) (mblk_t * mp)
                   2584: #else
                   2585: mblk_t *
                   2586: copymsg __ARGS ((mp))
                   2587: mblk_t       * mp;
                   2588: #endif
                   2589: {
                   2590:        mblk_t        * oldscan;
                   2591:        mblk_t        * msg;
                   2592:        mblk_t        * newblk;
                   2593: 
                   2594:        ASSERT (mp != NULL && mp->b_datap != NULL);
                   2595: 
                   2596:        /*
                   2597:         * Rather than simply layering on top of copyb (), we can make this
                   2598:         * function be more friendly in situations where memory is scarce by
                   2599:         * trying the allocations before the copies, so that we don't spend
                   2600:         * time copying data that is going to be discarded.
                   2601:         */
                   2602: 
                   2603:        if ((newblk = msg = MSGB_ALLOC (mp->b_wptr - mp->b_rptr, BPRI_LO,
                   2604:                                        KM_NOSLEEP)) == NULL)
                   2605:                return NULL;
                   2606: 
                   2607:        for (oldscan = mp->b_cont ; oldscan != NULL ;
                   2608:             newblk = newblk->b_cont, oldscan = oldscan->b_cont) {
                   2609: 
                   2610:                if ((newblk->b_cont =
                   2611:                                MSGB_ALLOC (oldscan->b_wptr - oldscan->b_rptr,
                   2612:                                            BPRI_LO, KM_NOSLEEP)) == NULL) {
                   2613:                        freemsg (msg);
                   2614:                        return NULL;
                   2615:                }
                   2616:        }
                   2617: 
                   2618:        /*
                   2619:         * Now we have the memory, do the copy. Like copyb (), we have have to
                   2620:         * remember to dance around zero-length blocks in the original, which
                   2621:         * we will be preserve as copied zero-length blocks.
                   2622:         */
                   2623: 
                   2624:        oldscan = mp;
                   2625:        newblk = msg;
                   2626: 
                   2627:        do {
                   2628:                size_t          size;
                   2629: 
                   2630:                ASSERT (oldscan != NULL);
                   2631: 
                   2632:                if ((size = oldscan->b_wptr - oldscan->b_rptr) > 0)
                   2633:                        memcpy (newblk->b_rptr, oldscan->b_rptr, size);
                   2634:                newblk->b_wptr += size;
                   2635: 
                   2636:                oldscan = oldscan->b_cont;
                   2637:        } while ((newblk = newblk->b_cont) != NULL);
                   2638: 
                   2639:        ASSERT (oldscan == NULL);
                   2640: 
                   2641: #if 0
                   2642:        if ((msg = newblk = copyb (mp)) != NULL)
                   2643:                while ((mp = mp->b_cont) != NULL)
                   2644:                        if ((newblk = (newblk->b_cont = copyb (mp))) == NULL) {
                   2645:                                /*
                   2646:                                 * If a given block in the message cannot be
                   2647:                                 * copied, undo all the work done so far.
                   2648:                                 */
                   2649: 
                   2650:                                freemsg (msg);
                   2651:                                return NULL;
                   2652:                        }
                   2653: #endif
                   2654: 
                   2655:        return msg;
                   2656: }
                   2657: 
                   2658: 
                   2659: /*
                   2660:  *-STATUS:
                   2661:  *     DDI/DKI
                   2662:  *
                   2663:  *-NAME:
                   2664:  *     datamsg         Test whether a message is a data message.
                   2665:  *
                   2666:  *-SYNOPSIS:
                   2667:  *     #include <sys/types.h>
                   2668:  *     #include <sys/stream.h>
                   2669:  *     #include <sys/ddi.h>
                   2670:  *
                   2671:  *     int datamsg (uchar_t type);
                   2672:  *
                   2673:  *-ARGUMENTS:
                   2674:  *     type            The type of message to be tested. The "db_type" field
                   2675:  *                     of the "datab" structure contains the message type.
                   2676:  *                     This field may be accessed through the message block
                   2677:  *                     using "mp->b_datap->db_type".
                   2678:  *
                   2679:  *-DESCRIPTION:
                   2680:  *     The datamsg () function tests the type of message to determine if it
                   2681:  *     is a data message type (M_DATA, M_DELAY, M_PROTO or M_PCPROTO).
                   2682:  *
                   2683:  *-RETURN VALUE:
                   2684:  *     datamsg () returns 1 if the message is a data message and 0 if the
                   2685:  *     message is any other type.
                   2686:  *
                   2687:  *-LEVEL:
                   2688:  *     Base or interrupt.
                   2689:  *
                   2690:  *-NOTES:
                   2691:  *     Does not sleep.
                   2692:  *
                   2693:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2694:  *     held across calls to this function.
                   2695:  *
                   2696:  *-SEE ALSO:
                   2697:  *     allocb (), datab, msgb, messages
                   2698:  */
                   2699: 
                   2700: #if    __USE_PROTO__
                   2701: int (datamsg) (uchar_t type)
                   2702: #else
                   2703: int
                   2704: datamsg __ARGS ((type))
                   2705: uchar_t                type;
                   2706: #endif
                   2707: {
                   2708:        return datamsg (type);          /* appeal to the macro version */
                   2709: }
                   2710: 
                   2711: 
                   2712: /*
                   2713:  *-STATUS:
                   2714:  *     DDI/DKI
                   2715:  *
                   2716:  *-NAME:
                   2717:  *     dupb            Duplicate a message block.
                   2718:  *
                   2719:  *-SYNOPSIS:
                   2720:  *     #include <sys/stream.h>
                   2721:  *
                   2722:  *     mblk_t * dupb (mblk_t * bp);
                   2723:  *
                   2724:  *-ARGUMENTS:
                   2725:  *     bp              Pointer to the message block to be duplicated.
                   2726:  *
                   2727:  *-DESCRIPTION:
                   2728:  *     dupb () creates a new message block structure to reference the message
                   2729:  *     block pointed to by "bp". Unlike copyb (), dupb () does not copy the
                   2730:  *     information in the data block, but creates a new structure to point to
                   2731:  *     it.
                   2732:  *
                   2733:  *-RETURN VALUE:
                   2734:  *     If successful, dupb () returns a pointer to the new message block.
                   2735:  *     Otherwise, it returns a NULL pointer.
                   2736:  *
                   2737:  *-LEVEL:
                   2738:  *     Base or interrupt.
                   2739:  *
                   2740:  *-NOTES:
                   2741:  *     Does not sleep.
                   2742:  *
                   2743:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2744:  *     held across calls to this function.
                   2745:  *
                   2746:  *-SEE ALSO:
                   2747:  *     copyb (), dupmsg (), datab, msgb
                   2748:  */
                   2749: 
                   2750: #if    __USE_PROTO__
                   2751: mblk_t * (dupb) (mblk_t * bp)
                   2752: #else
                   2753: mblk_t *
                   2754: dupb __ARGS ((bp))
                   2755: mblk_t       * bp;
                   2756: #endif
                   2757: {
                   2758:        mblk_t        * newblk;
                   2759: 
                   2760:        ASSERT (bp != NULL);
                   2761: 
                   2762:        if ((newblk = STRMEM_ALLOC (sizeof (mblk_t), BPRI_HI,
                   2763:                                    KM_NOSLEEP)) != NULL) {
                   2764:                /*
                   2765:                 * Note that we do not initialize the "b_prev" and "b_next"
                   2766:                 * members, and that the "b_cont" member is NULL rather than
                   2767:                 * a copy of the original.
                   2768:                 */
                   2769: 
                   2770:                newblk->b_cont = NULL;
                   2771:                newblk->b_datap = bp->b_datap;
                   2772:                newblk->b_rptr = bp->b_rptr;
                   2773:                newblk->b_wptr = bp->b_wptr;
                   2774:                ++ newblk->b_datap->db_ref;
                   2775:        }
                   2776: 
                   2777:        return newblk;
                   2778: }
                   2779: 
                   2780: 
                   2781: /*
                   2782:  *-STATUS:
                   2783:  *     DDI/DKI
                   2784:  *
                   2785:  *-NAME:
                   2786:  *     dupmsg          Duplicate a message.
                   2787:  *
                   2788:  *-SYNOPSIS:
                   2789:  *     #include <sys/stream.h>
                   2790:  *
                   2791:  *     mblk_t * dupmsg (mblk_t * mp);
                   2792:  *
                   2793:  *-ARGUMENTS:
                   2794:  *     mp              Pointer to the message to be duplicated.
                   2795:  *
                   2796:  *-DESCRIPTION:
                   2797:  *     dupmsg () forms a new message by duplicating the message blocks in the
                   2798:  *     message pointed to by "mp" and linking them via their "b_cont"
                   2799:  *     pointers.
                   2800:  *
                   2801:  *-RETURN VALUE:
                   2802:  *     If successful, dupmsg () returns a pointer to the new message.
                   2803:  *     Otherwise it returns a NULL pointer.
                   2804:  *
                   2805:  *-LEVEL:
                   2806:  *     Base or interrupt.
                   2807:  *
                   2808:  *-NOTES:
                   2809:  *     Does not sleep.
                   2810:  *
                   2811:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2812:  *     held across calls to this function.
                   2813:  *
                   2814:  *-SEE ALSO:
                   2815:  *     copyb (), copymsg (), dupb (), datab, msgb
                   2816:  */
                   2817: 
                   2818: #if    __USE_PROTO__
                   2819: mblk_t * (dupmsg) (mblk_t * mp)
                   2820: #else
                   2821: mblk_t *
                   2822: dupmsg __ARGS ((mp))
                   2823: mblk_t       * mp;
                   2824: #endif
                   2825: {
                   2826:        mblk_t        * msg;
                   2827:        mblk_t        * newblk;
                   2828: 
                   2829:        ASSERT (mp != NULL);
                   2830: 
                   2831:        if ((msg = newblk = dupb (mp)) != NULL)
                   2832:                while ((mp = mp->b_cont) != NULL)
                   2833:                        if ((newblk = (newblk->b_cont = dupb (mp))) == NULL) {
                   2834:                                /*
                   2835:                                 * Discard the work we have done so far.
                   2836:                                 */
                   2837: 
                   2838:                                freemsg (msg);
                   2839:                                return NULL;
                   2840:                        }
                   2841: 
                   2842:        return msg;
                   2843: }
                   2844: 
                   2845: 
                   2846: /*
                   2847:  *-STATUS:
                   2848:  *     DDI/DKI
                   2849:  *
                   2850:  *-NAME:
                   2851:  *     enableok        Enable a queue to be serviced.
                   2852:  *
                   2853:  *-SYNOPSIS:
                   2854:  *     #include <sys/stream.h>
                   2855:  *     #include <sys/ddi.h>
                   2856:  *
                   2857:  *     void enableok (queue_t * q);
                   2858:  *
                   2859:  *-ARGUMENTS:
                   2860:  *     q               Pointer to the queue.
                   2861:  *
                   2862:  *-DESCRIPTION:
                   2863:  *     The enableok () function allows the service routine of the queue
                   2864:  *     pointed to by "q" to be rescheduled for service. It cancels the effect
                   2865:  *     of a previous use of the noenable () function on "q".
                   2866:  *
                   2867:  *-RETURN VALUE:
                   2868:  *     None.
                   2869:  *
                   2870:  *-LEVEL:
                   2871:  *     Base or interrupt.
                   2872:  *
                   2873:  *-NOTES:
                   2874:  *     Does not sleep.
                   2875:  *
                   2876:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   2877:  *     calling this function.
                   2878:  *
                   2879:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2880:  *     held across calls to this function.
                   2881:  *
                   2882:  *-SEE ALSO:
                   2883:  *     noenable (), qenable (), queue
                   2884:  */
                   2885: 
                   2886: #if    __USE_PROTO__
                   2887: void (enableok) (queue_t * q)
                   2888: #else
                   2889: void
                   2890: enableok __ARGS ((q))
                   2891: queue_t              * q;
                   2892: #endif
                   2893: {
                   2894:        pl_t            prev_pl;
                   2895: 
                   2896:        prev_pl = QFREEZE_TRACE (q, "enableok");
                   2897: 
                   2898:        q->q_flag &= ~ QNOENB;
                   2899: 
                   2900:        QUNFREEZE_TRACE (q, prev_pl);
                   2901: }
                   2902: 
                   2903: 
                   2904: /*
                   2905:  *-STATUS:
                   2906:  *     DDI/DKI
                   2907:  *
                   2908:  *-NAME:
                   2909:  *     esballoc        Allocate a message block using an externally supplied
                   2910:  *                     buffer.
                   2911:  *
                   2912:  *-SYNOPSIS:
                   2913:  *     #include <sys/stream.h>
                   2914:  *
                   2915:  *     mblk_t * esballoc (uchar_t * base, int size, int pri,
                   2916:  *                        frtn_t * fr_rtnp);
                   2917:  *
                   2918:  *-ARGUMENTS:
                   2919:  *     base            Address of driver-supplied data buffer.
                   2920:  *
                   2921:  *     size            Number of bytes in data buffer.
                   2922:  *
                   2923:  *     pri             Priority of allocation request (used to allocate the
                   2924:  *                     message and data blocks). Valid values are BPRI_LO,
                   2925:  *                     BPRI_MED, and BPRI_HI.
                   2926:  *
                   2927:  *     fr_rtnp         Pointer to the free-routine data structure.
                   2928:  *
                   2929:  *-DESCRIPTION:
                   2930:  *     esballoc () creates a STREAMS message and attaches a driver-supplied
                   2931:  *     data buffer in place of a STREAMS data buffer. It allocates a message
                   2932:  *     and data block header only. The driver-supplied data buffer, pointed
                   2933:  *     to by "base", is used as the data buffer for the message.
                   2934:  *
                   2935:  *     When freeb () is called to free the message, on the last reference to
                   2936:  *     the message the driver's free-routine specified by the "free_func"
                   2937:  *     field in the "free_rtn" structure is called with one argument
                   2938:  *     (specified by the "free_arg" field) to free the data buffer.
                   2939:  *
                   2940:  *     Instead of requiring a specific number of arguments, the "free_arg"
                   2941:  *     field is defined as type "char *". This way, the driver can pass a
                   2942:  *     pointer to a structure if more than one argument is needed.
                   2943:  *
                   2944:  *     When the "free_func" function runs, interrupts from all STREAMS
                   2945:  *     devices will be blocked. It has no user context and may not call any
                   2946:  *     routine that sleeps. The function may not access any dynamically
                   2947:  *     allocated data structures that might no longer exist when it runs.
                   2948:  *
                   2949:  *-RETURN VALUE:
                   2950:  *     On success, a pointer to the newly allocated message block is
                   2951:  *     returned. On failure, a NULL pointer is returned.
                   2952:  *
                   2953:  *-LEVEL:
                   2954:  *     Base or interrupt.
                   2955:  *
                   2956:  *-NOTES:
                   2957:  *     Does not sleep.
                   2958:  *
                   2959:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2960:  *     held across calls to this function.
                   2961:  *
                   2962:  *-SEE ALSO:
                   2963:  *     allocb (), freeb (), free_rtn
                   2964:  */
                   2965: 
                   2966: #if    __USE_PROTO__
                   2967: mblk_t * (esballoc) (uchar_t * base, int size, int pri, frtn_t * fr_rtnp)
                   2968: #else
                   2969: mblk_t *
                   2970: esballoc __ARGS ((base, size, pri, fr_rtnp))
                   2971: uchar_t              * base;
                   2972: int            size;
                   2973: int            pri;
                   2974: frtn_t       * fr_rtnp;
                   2975: #endif
                   2976: {
                   2977:        mblk_t        * mblkp;
                   2978: 
                   2979:        ASSERT (base != NULL);
                   2980:        ASSERT (size >= 0);
                   2981:        ASSERT (pri == BPRI_LO || pri == BPRI_HI || pri == BPRI_LO);
                   2982:        ASSERT (ATOMIC_FETCH_UCHAR (str_mem->sm_init) &&
                   2983:                str_mem->sm_msg_lock != NULL);
                   2984: 
                   2985:        /*
                   2986:         * Is it permissible for a driver to specify a NULL fr_rtnp?
                   2987:         *
                   2988:         * I think that it seems entirely logical, but neither the DDI/DKI
                   2989:         * nor the STREAMS Programmer's Guide say anything about this.
                   2990:         */
                   2991: 
                   2992:        if ((mblkp = STRMEM_ALLOC (MSGB_SIZE (0), pri, KM_NOSLEEP)) != NULL) {
                   2993:                /*
                   2994:                 * Note that we don't bother setting up the "b_prev" and
                   2995:                 * "b_next" members of the message block.
                   2996:                 */
                   2997: 
                   2998:                mblkp->b_cont = NULL;
                   2999:                mblkp->b_datap = MB_TO_DB (mblkp);
                   3000:                mblkp->b_rptr = base;
                   3001:                mblkp->b_wptr = base;
                   3002: 
                   3003:                /*
                   3004:                 * We specially flag this message block as part of
                   3005:                 * a triple. While there are other ways we could test
                   3006:                 * this, for now we permit the possibility that a
                   3007:                 * client might change the attachments of data blocks
                   3008:                 * and message blocks perversely.
                   3009:                 */
                   3010: 
                   3011:                mblkp->b_flag = MSGTRIPLE;
                   3012:                mblkp->b_band = 0;
                   3013: 
                   3014:                mblkp->b_datap->db_base = base;
                   3015:                mblkp->b_datap->db_lim = base + size;
                   3016:                mblkp->b_datap->db_type = M_DATA;
                   3017:                mblkp->b_datap->db_ref = 1;
                   3018: 
                   3019:                mblkp->b_datap->db_frtnp = fr_rtnp;
                   3020:        }
                   3021: 
                   3022:        return mblkp;
                   3023: }
                   3024: 
                   3025: 
                   3026: /*
                   3027:  *-STATUS:
                   3028:  *     DDI/DKI
                   3029:  *
                   3030:  *-NAME:
                   3031:  *     esbbcall        Call a function when an externally-supplied buffer
                   3032:  *                     can be allocated.
                   3033:  *
                   3034:  *-SYNOPSIS:
                   3035:  *     #include <sys/types.h>
                   3036:  *     #include <sys/stream.h>
                   3037:  *
                   3038:  *     toid_t esbbcall (int pri, int (* func) (), long arg);
                   3039:  *
                   3040:  *-ARGUMENTS:
                   3041:  *     pri             Priority of the esballoc () allocation request
                   3042:  *                     (BPRI_LO, BPRI_MED or BPRI_HI).
                   3043:  *
                   3044:  *     func            Function to be called when a buffer becomes available.
                   3045:  *
                   3046:  *     arg             Argument to the function to be called when a buffer
                   3047:  *                     becomes available.
                   3048:  *
                   3049:  *-DESCRIPTION:
                   3050:  *     esbbcall (), like bufcall (), serves as a timeout call of
                   3051:  *     indeterminate duration. If esballoc () is unable to allocate a message
                   3052:  *     block header and a data block header to go with the externally
                   3053:  *     supplied data buffer, esbbcall () can be used to schedule the routine
                   3054:  *     "func", to be called with the argument "arg" when memory becomes
                   3055:  *     available.
                   3056:  *
                   3057:  *     When "func" runs, all interrupts from STREAMS devices will be blocked
                   3058:  *     on the processor on which it is running. "func" will have no user
                   3059:  *     context and may not call any function that sleeps.
                   3060:  *
                   3061:  *-RETURN VALUE:
                   3062:  *     If successful, esbbcall () returns a non-zero value that identifies
                   3063:  *     the scheduling request. This non-zero identifier may be passed to
                   3064:  *     unbufcall () to cancel the request. If any failure occurs, esbbcall ()
                   3065:  *     returns 0.
                   3066:  *
                   3067:  *-LEVEL:
                   3068:  *     Base or interrupt.
                   3069:  *
                   3070:  *-NOTES:
                   3071:  *     Does not sleep.
                   3072:  *
                   3073:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   3074:  *     held across calls to this function.
                   3075:  *
                   3076:  *     Even when "func" is called, esballoc () can still fail if another
                   3077:  *     module or driver had allocated the memory before "func" was able to
                   3078:  *     call esballoc ().
                   3079:  *
                   3080:  *-SEE ALSO:
                   3081:  *     allocb (), bufcall (), esballoc (), itimeout (), unbufcall ()
                   3082:  */
                   3083: 
                   3084: #if    __USE_PROTO__
                   3085: toid_t (esbbcall) (int pri, ...)
                   3086: #else
                   3087: toid_t
                   3088: esbbcall __ARGS ((pri))
                   3089: int            pri;
                   3090: #endif
                   3091: {
                   3092:        se_funcptr_t    func;
                   3093:        long            arg;
                   3094:        va_list         arglist;
                   3095:        sevent_t      * seventp;
                   3096: 
                   3097: 
                   3098:        /*
                   3099:         * Before we do anything, we fetch the two other arguments. We use
                   3100:         * the variable-argument function convention to get around problems
                   3101:         * with implicit conversions introduced by having a prototype for
                   3102:         * this function visible.
                   3103:         *
                   3104:         * This is a generic problem with callbacks, since the shape of a
                   3105:         * function type includes the shapes of the function arguments, and
                   3106:         * because we want to pass some argument to the user-supplied function
                   3107:         * without knowing its type (and hence, we must not cause any implicit
                   3108:         * conversions on its value).
                   3109:         */
                   3110: 
                   3111:        va_start (arglist, pri);
                   3112: 
                   3113:        func = va_arg (arglist, se_funcptr_t);
                   3114:        arg = va_arg (arglist, long);
                   3115: 
                   3116:        va_end (arglist);
                   3117: 
                   3118: 
                   3119:        /*
                   3120:         * It may be that NULL is defined in such a way that it is not
                   3121:         * meaningful to compare it with a function pointer, so we just cast
                   3122:         * a zero to get the right kind of effect.
                   3123:         *
                   3124:         * We add some extra assertions below to check that "long" is of
                   3125:         * sufficient size to contain all likely parameter data items. For
                   3126:         * C, "likely" means the fundamental types, which has to include
                   3127:         * pointers to functions, pointers to void, and also pointers to
                   3128:         * structures since under C++ there is currently no guarantee to match
                   3129:         * the ISO C requirement that a pointer of type "void *" be able to
                   3130:         * hold the value of any pointer type without loss of information.
                   3131:         * [We don't consider member pointers here; they are pathological]
                   3132:         */
                   3133: 
                   3134:        ASSERT (sizeof (se_funcptr_t) <= sizeof (long) &&
                   3135:                sizeof (_VOID *) <= sizeof (long) &&
                   3136:                sizeof (selist_t *) <= sizeof (long));
                   3137: 
                   3138:        ASSERT (func != (se_funcptr_t) 0);
                   3139:        ASSERT (pri == BPRI_LO || pri == BPRI_HI || pri == BPRI_LO);
                   3140: 
                   3141: 
                   3142:        /*
                   3143:         * Here we *could* lock and test the available space in the STREAMS
                   3144:         * message heap to see whether sufficient space to satisfy the
                   3145:         * request has become available between the failed allocb () and
                   3146:         * the bufcall () request.
                   3147:         *
                   3148:         * The question is whether the extra time that the heap is locked is
                   3149:         * worth overcoming a delay for a freemsg () to trigger the bufcall ()
                   3150:         * later, especially given the fact that we'll have to unlock the
                   3151:         * heap to call the user's callback (introducing the opportunity for
                   3152:         * the newly-discovered space to vanish).
                   3153:         *
                   3154:         * All in all, once things get to the bufcall () stage there seems
                   3155:         * little reason to keep pushing the system, so we don't bother.
                   3156:         */
                   3157: 
                   3158:        /*
                   3159:         * First off, let's get ourselves an event cell. This is mutually
                   3160:         * dependent with the ID generation policy; if ID codes are stored in
                   3161:         * the event cells, we are free to allocate and discard from a general
                   3162:         * memory pool; if ID codes are not stored, then they must reflect
                   3163:         * some persistent attribute of the cell, which usually implies that
                   3164:         * cells come from some nonshrinking managed pool.
                   3165:         *
                   3166:         * Of course, a generative ID code scheme requires extra locking in
                   3167:         * the absence of atomic FETCH_AND_INCREMENT () operations. In this
                   3168:         * implementation, we get around this by using the list-head locks
                   3169:         * to guard the counter operations. [This has interesting implications
                   3170:         * for the design of a generic list-manipulation facility.]
                   3171:         */
                   3172: 
                   3173: #if _TOID_MEMBER
                   3174:        if ((seventp = (sevent_t *) kmem_alloc (sizeof (sevent_t),
                   3175:                                                KM_NOSLEEP)) == NULL)
                   3176:                return 0;
                   3177: #else
                   3178: #error Need an allocator for event cells that matches the ID policy
                   3179: #endif
                   3180: 
                   3181:        seventp->se_arg = arg;
                   3182:        seventp->se_func = func;
                   3183:        seventp->se_size = MSGB_SIZE (0);
                   3184: 
                   3185:        return STORE_EVENT (seventp, pri);
                   3186: }
                   3187: 
                   3188: 
                   3189: /*
                   3190:  *-STATUS:
                   3191:  *     DDI/DKI
                   3192:  *
                   3193:  *-NAME:
                   3194:  *     flushband       Flush messages in a specified priority band.
                   3195:  *
                   3196:  *-SYNOPSIS:
                   3197:  *     #include <sys/types.h>
                   3198:  *     #include <sys/stream.h>
                   3199:  *
                   3200:  *     void flushband (queue_t * q, uchar_t pri, int flag);
                   3201:  *
                   3202:  *-ARGUMENTS:
                   3203:  *     q               Pointer to the queue.
                   3204:  *
                   3205:  *     pri             Priority band of messages to be flushed.
                   3206:  *
                   3207:  *     flag            Determines messages to flush. Valid "flag" values are:
                   3208:  *
                   3209:  *                       FLUSHDATA     Flush only data messages (types
                   3210:  *                                     M_DATA, M_DELAY, M_PROTO, and
                   3211:  *                                     M_PCPROTO).
                   3212:  *
                   3213:  *                       FLUSHALL      Flush all messages.
                   3214:  *
                   3215:  *-DESCRIPTION:
                   3216:  *     The flushband () function flushes messages associated with the
                   3217:  *     priority band specified by "pri". If "pri" is 0, only normal and high
                   3218:  *     priority messages are flushed. Otherwise, messages are flushed from
                   3219:  *     the band "pri" according to the value of "flag".
                   3220:  *
                   3221:  *-RETURN VALUE:
                   3222:  *     None.
                   3223:  *
                   3224:  *-LEVEL:
                   3225:  *     Base or interrupt.
                   3226:  *
                   3227:  *-NOTES:
                   3228:  *     Does not sleep.
                   3229:  *
                   3230:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   3231:  *     calling this function.
                   3232:  *
                   3233:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   3234:  *     held across calls to this function.
                   3235:  *
                   3236:  *-SEE ALSO:
                   3237:  *     put (), flushq (), queue
                   3238:  */
                   3239: 
                   3240: #if    __USE_PROTO__
                   3241: void (flushband) (queue_t * q, uchar_t pri, int flag)
                   3242: #else
                   3243: void
                   3244: flushband __ARGS ((q, pri, flag))
                   3245: queue_t              * q;
                   3246: uchar_t                pri;
                   3247: int            flag;
                   3248: #endif
                   3249: {
                   3250:        pl_t            prev_pl;
                   3251:        qband_t       * qbandp;
                   3252:        mblk_t        * mp;
                   3253:        mblk_t        * next;
                   3254:        ulong_t         flushsize;
                   3255: 
                   3256:        ASSERT (flag == FLUSHDATA || flag == FLUSHALL);
                   3257: 
                   3258:        if (pri == 0) {
                   3259:                /*
                   3260:                 * Since the priority-band flush algorithm is necessarily
                   3261:                 * different from the regular one (due to flow control
                   3262:                 * handling), we'll just forward this on to the regular
                   3263:                 * version.
                   3264:                 */
                   3265: 
                   3266:                flushq (q, flag);
                   3267:                return;
                   3268:        }
                   3269: 
                   3270:        prev_pl = QFREEZE_TRACE (q, "flushband");
                   3271: 
                   3272:        if ((qbandp = QUEUE_BAND (q, pri)) != NULL &&
                   3273:            (mp = qbandp->qb_first) != NULL) {
                   3274: 
                   3275:                flushsize = 0;
                   3276: 
                   3277:                do {
                   3278:                        /*
                   3279:                         * Read the "b_next" member now in case we unlink this message
                   3280:                         * from the queue.
                   3281:                         */
                   3282: 
                   3283:                        next = mp->b_next;
                   3284: 
                   3285:                        ASSERT (mp->b_band == pri);
                   3286: 
                   3287:                        if (flag == FLUSHALL || datamsg (mp->b_datap->db_type)) {
                   3288: 
                   3289:                                if (mp->b_prev == NULL)
                   3290:                                        q->q_first = next;
                   3291:                                else
                   3292:                                        mp->b_prev->b_next = next;
                   3293: 
                   3294:                                if (next == NULL)
                   3295:                                        q->q_last = mp->b_prev;
                   3296:                                else
                   3297:                                        next->b_prev = mp->b_prev;
                   3298: 
                   3299:                                QBAND_DEQUEUE (qbandp, mp);
                   3300: 
                   3301: 
                   3302:                                /*
                   3303:                                 * Free the message, accumulating the total
                   3304:                                 * size of the data referred to by the
                   3305:                                 * message.
                   3306:                                 */
                   3307: 
                   3308:                                flushsize += MSG_SIZE (mp);
                   3309:                                freemsg (mp);
                   3310:                        }
                   3311:                } while ((mp = next) != qbandp->qb_last);
                   3312: 
                   3313: 
                   3314:                /*
                   3315:                 * Here we update the flow control parameters for the band
                   3316:                 * now that we have accumulated all the necessary changes.
                   3317:                 */
                   3318: 
                   3319:                QBAND_REDUCE (q, qbandp, flushsize);
                   3320:        }
                   3321: 
                   3322: 
                   3323:        /*
                   3324:         * Since we are in a path with QBAND_REDUCE (), check for QBACK before
                   3325:         * unfreezing the stream.
                   3326:         */
                   3327: 
                   3328:        {
                   3329:                unsigned long   back;
                   3330: 
                   3331:                if ((back = q->q_flag & QBACK) != 0)
                   3332:                        q->q_flag &= ~ QBACK;
                   3333: 
                   3334:                QUNFREEZE_TRACE (q, prev_pl);
                   3335: 
                   3336:                if (back)
                   3337:                        QUEUE_BACKENAB (q);
                   3338:        }
                   3339: }
                   3340: 
                   3341: 
                   3342: /*
                   3343:  *-STATUS:
                   3344:  *     DDI/DKI
                   3345:  *
                   3346:  *-NAME:
                   3347:  *     flushq          Flush messages on a queue.
                   3348:  *
                   3349:  *-SYNOPSIS:
                   3350:  *     #include <sys/stream.h>
                   3351:  *
                   3352:  *     void flushq (queue_t * q, int flag);
                   3353:  *
                   3354:  *-ARGUMENTS:
                   3355:  *     q               Pointer to the queue.
                   3356:  *
                   3357:  *     flag            Determines messages to flush. Valid "flag" values are:
                   3358:  *
                   3359:  *                       FLUSHDATA     Flush only data messages (types
                   3360:  *                                     M_DATA, M_DELAY, M_PROTO, and
                   3361:  *                                     M_PCPROTO).
                   3362:  *
                   3363:  *                       FLUSHALL      Flush all messages.
                   3364:  *
                   3365:  *-DESCRIPTION:
                   3366:  *     flushq () frees messages on a queue by calling freemsg () for each
                   3367:  *     message. If the queue's count falls below the low water mark and
                   3368:  *     someone wants to write to the queue, the nearest upstream or
                   3369:  *     downstream (as approriate) service procedure is enabled.
                   3370:  *
                   3371:  *-RETURN VALUE:
                   3372:  *     None.
                   3373:  *
                   3374:  *-LEVEL:
                   3375:  *     Base or interrupt.
                   3376:  *
                   3377:  *-NOTES:
                   3378:  *     Does not sleep.
                   3379:  *
                   3380:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   3381:  *     calling this function.
                   3382:  *
                   3383:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   3384:  *     held across calls to this function.
                   3385:  *
                   3386:  *-SEE ALSO:
                   3387:  *     put (), flushband (), freemsg (), putq (), queue
                   3388:  */
                   3389: 
                   3390: #if    __USE_PROTO__
                   3391: void (flushq) (queue_t * q, int flag)
                   3392: #else
                   3393: void
                   3394: flushq __ARGS ((q, flag))
                   3395: queue_t              * q;
                   3396: int            flag;
                   3397: #endif
                   3398: {
                   3399:        pl_t            prev_pl;
                   3400:        mblk_t        * mp;
                   3401:        mblk_t        * next;
                   3402:        ulong_t         flushsize;
                   3403: 
                   3404:        ASSERT (flag == FLUSHDATA || flag == FLUSHALL);
                   3405: 
                   3406:        flushsize = 0;
                   3407: 
                   3408:        prev_pl = QFREEZE_TRACE (q, "flushq");
                   3409: 
                   3410:        /*
                   3411:         * High-priority messages are flushed as well as low-priority messages
                   3412:         * so we could presumably split this function into a two-part scan
                   3413:         * since the high-priority messages are at the front of the message
                   3414:         * list while the low-priority messages are at the end.
                   3415:         *
                   3416:         * However, this function is not called very often, and we expect
                   3417:         * band usage to be rare.
                   3418:         */
                   3419: 
                   3420:        for (mp = q->q_first ; mp != NULL ; mp = next) {
                   3421:                /*
                   3422:                 * Read the "b_next" member now in case we unlink this message
                   3423:                 * from the queue.
                   3424:                 */
                   3425: 
                   3426:                next = mp->b_next;
                   3427: 
                   3428:                if (mp->b_band == 0 &&
                   3429:                    (flag == FLUSHALL || datamsg (mp->b_datap->db_type))) {
                   3430: 
                   3431:                        if (mp->b_prev == NULL)
                   3432:                                q->q_first = next;
                   3433:                        else
                   3434:                                mp->b_prev->b_next = next;
                   3435: 
                   3436:                        if (next == NULL)
                   3437:                                q->q_last = mp->b_prev;
                   3438:                        else
                   3439:                                next->b_prev = mp->b_prev;
                   3440: 
                   3441:                        /*
                   3442:                         * If the message is high-priority, then we skip the
                   3443:                         * accumulation of the size.
                   3444:                         */
                   3445: 
                   3446:                        if (IS_PRI_MSG (mp)) {
                   3447:                                freemsg (mp);
                   3448:                                continue;
                   3449:                        }
                   3450: 
                   3451:                        /*
                   3452:                         * Free the message, accumulating the total size of
                   3453:                         * the data referred to by the message.
                   3454:                         */
                   3455: 
                   3456:                        flushsize += MSG_SIZE (mp);
                   3457:                        freemsg (mp);
                   3458:                }
                   3459:        }
                   3460: 
                   3461:        QUEUE_REDUCE (q, flushsize);
                   3462: 
                   3463: 
                   3464:        /*
                   3465:         * Since we are in a path with QUEUE_REDUCE (), check for QBACK before
                   3466:         * unfreezing the stream.
                   3467:         */
                   3468: 
                   3469:        {
                   3470:                unsigned long   back;
                   3471: 
                   3472:                if ((back = q->q_flag & QBACK) != 0)
                   3473:                        q->q_flag &= ~ QBACK;
                   3474: 
                   3475:                QUNFREEZE_TRACE (q, prev_pl);
                   3476: 
                   3477:                if (back)
                   3478:                        QUEUE_BACKENAB (q);
                   3479:        }
                   3480: }
                   3481: 
                   3482: 
                   3483: /*
                   3484:  *-STATUS:
                   3485:  *     DDI/DKI
                   3486:  *
                   3487:  *-NAME:
                   3488:  *     freeb           Free a message block.
                   3489:  *
                   3490:  *-SYNOPSIS:
                   3491:  *     #include <sys/stream.h>
                   3492:  *
                   3493:  *     void freeb (mblk_t * bp);
                   3494:  *
                   3495:  *-ARGUMENTS:
                   3496:  *     bp              Pointer to the message block to be deallocated.
                   3497:  *
                   3498:  *-DESCRIPTION:
                   3499:  *     freeb () deallocates a message block. If the reference count of the
                   3500:  *     "db_ref" member of the "datab" structure is greater than 1, freeb ()
                   3501:  *     decrements the count and returns. Otherwise, if "db_ref" equals 1, it
                   3502:  *     deallocates the message block and the corresponding data block and the
                   3503:  *     corresponding data block and buffer.
                   3504:  *
                   3505:  *     If the data buffer to be freed was allocated with esballoc (), the
                   3506:  *     driver is notified that the attached data buffer needs to be freed by
                   3507:  *     calling the free-routine [see free_rtn] associated with the data
                   3508:  *     buffer. Once this is accomplished, freeb () releases the STREAMS
                   3509:  *     resources associated with the buffer.
                   3510:  *
                   3511:  *-RETURN VALUE:
                   3512:  *     None.
                   3513:  *
                   3514:  *-LEVEL:
                   3515:  *     Base or interrupt.
                   3516:  *
                   3517:  *-NOTES:
                   3518:  *     Does not sleep.
                   3519:  *
                   3520:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   3521:  *     held across calls to this function.
                   3522:  *
                   3523:  *-SEE ALSO:
                   3524:  *     allocb (), dupb (), esballoc (), datab, free_rtn, msgb
                   3525:  */
                   3526: 
                   3527: #if    __USE_PROTO__
                   3528: void (freeb) (mblk_t * bp)
                   3529: #else
                   3530: void
                   3531: freeb __ARGS ((bp))
                   3532: mblk_t       * bp;
                   3533: #endif
                   3534: {
                   3535:        size_t          size;
                   3536:        pl_t            prev_pl;
                   3537:        dblk_t        * datap;
                   3538:        frtn_t        * frtnp = NULL;
                   3539: 
                   3540: 
                   3541:        ASSERT (bp != NULL && bp->b_datap != NULL);
                   3542:        ASSERT (bp->b_datap->db_ref > 0);
                   3543: 
                   3544:        datap = bp->b_datap;
                   3545: 
                   3546:        /*
                   3547:         * It is expected that almost all of the calls to freeb () will result
                   3548:         * in some memory being returned to the free pool, so to save space
                   3549:         * and ensure correctness we lock the heap now.
                   3550:         *
                   3551:         * This has the advantage of serializing some of the tests below for
                   3552:         * dealing with which parts of a message triple are free. Since the
                   3553:         * message and data parts of a triple could be being freed
                   3554:         * simultaneously by different contexts, this will guarantee that the
                   3555:         * data will be freed by exactly one of the contexts.
                   3556:         *
                   3557:         * Another note about memory management: if the message and other
                   3558:         * heaps are not kept separate, then some extra work needs to be done
                   3559:         * to wake up processes sleeping for memory and for calling the
                   3560:         * scheduled buffer events. Essentially, the systems need to map to
                   3561:         * some common code that correctly prioritizes access and runs at an
                   3562:         * appropriate time (possibly when some processor is about to return
                   3563:         * to user mode from the kernel, or is totally idle).
                   3564:         */
                   3565: 
                   3566:        prev_pl = LOCK (str_mem->sm_msg_lock, str_msg_pl);
                   3567: 
                   3568:        -- datap->db_ref;
                   3569: 
                   3570:        if (datap->db_ref > 0) {
                   3571:                /*
                   3572:                 * Ok, we don't need to free the data block and buffer, but
                   3573:                 * we may still need to free the message block. This gets a
                   3574:                 * little convoluted since we might be deallocating only part
                   3575:                 * of a structure that was actually allocated as a whole by
                   3576:                 * allocb () or esballoc ().
                   3577:                 */
                   3578: 
                   3579:                if ((bp->b_flag & MSGTRIPLE) == 0) {
                   3580: 
                   3581:                        STRMEM_FREE (bp, sizeof (mblk_t));
                   3582:                        goto free_done;
                   3583:                }
                   3584: 
                   3585:                if ((datap = MB_TO_DB (bp))->db_ref > 0) {
                   3586:                        /*
                   3587:                         * The data block part of the triple is not free,
                   3588:                         * so we set a flag (tested when the data block is
                   3589:                         * freed).
                   3590:                         */
                   3591: 
                   3592:                        bp->b_flag |= MSGFREE;
                   3593: 
                   3594:                        goto free_done;
                   3595:                }
                   3596: 
                   3597:                /*
                   3598:                 * If the test above was false, it arranged for the message
                   3599:                 * block to be associated with its triple partner so that
                   3600:                 * we can proceed with the freeing process.
                   3601:                 */
                   3602: 
                   3603:        } else if ((bp->b_flag & MSGTRIPLE) == 0) {
                   3604:                /*
                   3605:                 * The message block isn't from the same triple as the data
                   3606:                 * block. We free the message block and then see whether the
                   3607:                 * message block from the triple with the data block is free.
                   3608:                 */
                   3609: 
                   3610: 
                   3611:                STRMEM_FREE (bp, sizeof (mblk_t));
                   3612: 
                   3613:                bp = DB_TO_MB (datap);
                   3614: 
                   3615:                if ((bp->b_flag & MSGFREE) == 0) {
                   3616:                        /*
                   3617:                         * The data block part of the triple is free but the
                   3618:                         * message block isn't. The triple will be freed when
                   3619:                         * the message block is freed.
                   3620:                         */
                   3621: 
                   3622:                        goto free_done;
                   3623:                }
                   3624:        }
                   3625: 
                   3626: 
                   3627:        /*
                   3628:         * Now we deal with freeing the data portion of the message. First off
                   3629:         * we check whether or not the data block holds a user-supplied buffer
                   3630:         * or not.
                   3631:         */
                   3632: 
                   3633:        if (datap->db_base != DB_TO_DATA (datap)) {
                   3634:                /*
                   3635:                 * Calling the user-supplied free function now would be a
                   3636:                 * really bad idea, since while all the conditions that are
                   3637:                 * guaranteed to true while the function is called are true,
                   3638:                 * we are still holding the lock on the heap. We record the
                   3639:                 * information we need and do the job later.
                   3640:                 */
                   3641: 
                   3642:                ASSERT (datap->db_frtnp != NULL);
                   3643: 
                   3644:                frtnp = datap->db_frtnp;
                   3645:                size = 0;
                   3646: 
                   3647:        } else {
                   3648:                ASSERT (datap->db_frtnp == NULL);
                   3649: 
                   3650:                size = datap->db_lim - datap->db_base;
                   3651:        }
                   3652: 
                   3653: 
                   3654:        /*
                   3655:         * At this point we know we have a message block and a data block to
                   3656:         * free, plus "size" bytes of data buffer.
                   3657:         */
                   3658: 
                   3659:        STRMEM_FREE (bp, MSGB_SIZE (size));
                   3660: 
                   3661: free_done:
                   3662:        UNLOCK (str_mem->sm_msg_lock, plstr);
                   3663: 
                   3664:        /*
                   3665:         * Here we call any deferred user data buffer free function
                   3666:         */
                   3667: 
                   3668:        if (frtnp != NULL)
                   3669:                (* frtnp->free_func) (frtnp->free_arg);
                   3670: 
                   3671:        (void) splx (prev_pl);
                   3672: }
                   3673: 
                   3674: 
                   3675: /*
                   3676:  *-STATUS:
                   3677:  *     DDI/DKI
                   3678:  *
                   3679:  *-NAME:
                   3680:  *     freemsg         Free a message.
                   3681:  *
                   3682:  *-SYNOPSIS:
                   3683:  *     #include <sys/stream.h>
                   3684:  *
                   3685:  *     void freemsg (mblk_t * mp);
                   3686:  *
                   3687:  *-ARGUMENTS:
                   3688:  *     mp              Pointer to the message to be freed.
                   3689:  *
                   3690:  *-DESCRIPTION:
                   3691:  *     freemsg () frees all message blocks, data blocks, and data buffers
                   3692:  *     associated with the message pointed to by "mp". freemsg () walks down
                   3693:  *     the "b_cont" list [see msgb], calling freeb () for every message block
                   3694:  *     in the message.
                   3695:  *
                   3696:  *-RETURN VALUE:
                   3697:  *     None.
                   3698:  *
                   3699:  *-LEVEL:
                   3700:  *     Base or interrupt.
                   3701:  *
                   3702:  *-NOTES:
                   3703:  *     Does not sleep.
                   3704:  *
                   3705:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   3706:  *     held across calls to this function.
                   3707:  *
                   3708:  *-SEE ALSO:
                   3709:  *     freeb (), msgb
                   3710:  */
                   3711: 
                   3712: #if    __USE_PROTO__
                   3713: void (freemsg) (mblk_t * mp)
                   3714: #else
                   3715: void
                   3716: freemsg __ARGS ((mp))
                   3717: mblk_t       * mp;
                   3718: #endif
                   3719: {
                   3720:        mblk_t        * next;
                   3721: 
                   3722:        ASSERT (mp != NULL);
                   3723: 
                   3724:        do {
                   3725:                next = mp->b_cont;
                   3726:                freeb (mp);
                   3727:        } while ((mp = next) != NULL);
                   3728: }
                   3729: 
                   3730: 
                   3731: /*
                   3732:  *-STATUS:
                   3733:  *     DDI/DKI
                   3734:  *
                   3735:  *-NAME:
                   3736:  *     freezestr       Freeze the state of a stream.
                   3737:  *
                   3738:  *-SYNOPSIS:
                   3739:  *     #include <sys/types.h>
                   3740:  *     #include <sys/stream.h>
                   3741:  *
                   3742:  *     pl_t freezestr (queue_t * q);
                   3743:  *
                   3744:  *-ARGUMENTS:
                   3745:  *     q               Pointer to a message queue.
                   3746:  *
                   3747:  *-DESCRIPTION:
                   3748:  *     freezestr () sets the interrupt priority to "plstr" (if the current
                   3749:  *     level is lower than "plstr" and the implementation requires that
                   3750:  *     interrupts be blocked while the stream is frozen) and freezes the
                   3751:  *     state of the stream containing the queue specified by "q". Freezing
                   3752:  *     the stream prevents any further entries into open, close, put or
                   3753:  *     service procedures on the stream and prevents any messages from being
                   3754:  *     taken on or taken off any queues in the stream (except by the caller
                   3755:  *     of freezestr ()). Freezing the stream does not automatically stop all
                   3756:  *     functions that are running within the stream; functions will continue
                   3757:  *     to run until they attempt to perform some operation which changes the
                   3758:  *     state of the stream, at while point they will be forced to wait for
                   3759:  *     the stream to be unfrozen by a call to unfreezestr ().
                   3760:  *
                   3761:  *     Drivers and modules must freeze the stream while they manipulate its
                   3762:  *     queues directly. This includes searching the queues and for the
                   3763:  *     duration of any calls to insq (), rmvq (), strqset (), and strqget ().
                   3764:  *
                   3765:  *-RETURN VALUE:
                   3766:  *     freezestr () returns the previous interrupt priority level which is
                   3767:  *     typically used in a subsequent call to unfreezestr ().
                   3768:  *
                   3769:  *-LEVEL:
                   3770:  *     Base or interrupt.
                   3771:  *
                   3772:  *-NOTES:
                   3773:  *     Does not sleep.
                   3774:  *
                   3775:  *     Calling freezestr () to freeze a stream that is already frozen by the
                   3776:  *     caller will result in deadlock.
                   3777:  *
                   3778:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   3779:  *     held across calls to this function.
                   3780:  *
                   3781:  *     freezestr () should be used sparingly as it is rarely necessary to
                   3782:  *     freeze a stream (most modules do not need to manipulate their queues
                   3783:  *     directly) and freezing a stream can have a significant negative impact
                   3784:  *     on performance.
                   3785:  *
                   3786:  *-SEE ALSO:
                   3787:  *     unfreezestr ()
                   3788:  */
                   3789: 
                   3790: #if    __USE_PROTO__
                   3791: pl_t (freezestr) (queue_t * q)
                   3792: #else
                   3793: pl_t
                   3794: freezestr __ARGS ((q))
                   3795: queue_t              * q;
                   3796: #endif
                   3797: {
                   3798:        return QFREEZE_TRACE (q, "freezestr");
                   3799: }
                   3800: 
                   3801: 
                   3802: /*
                   3803:  *-STATUS:
                   3804:  *     DDI/DKI
                   3805:  *
                   3806:  *-NAME:
                   3807:  *     getq            Get the next message from a queue.
                   3808:  *
                   3809:  *-SYNOPSIS:
                   3810:  *     #include <sys/stream.h>
                   3811:  *
                   3812:  *     mblk_t * getq (queue_t * q);
                   3813:  *
                   3814:  *-ARGUMENTS:
                   3815:  *     q               Pointer to the queue from which the message is to be
                   3816:  *                     retrieved.
                   3817:  *
                   3818:  *-DESCRIPTION:
                   3819:  *     getq () is used by service routines to retrieve queue messages. It
                   3820:  *     gets the next available message from the top of the queue pointed to
                   3821:  *     by "q". getq () handles flow control, restarting I/O that was blocked
                   3822:  *     as needed.
                   3823:  *
                   3824:  *-RETURN VALUE:
                   3825:  *     If there is a message to retrieve, getq () returns a pointer to it. If
                   3826:  *     no message is queued, getq () returns a NULL pointer.
                   3827:  *
                   3828:  *-LEVEL:
                   3829:  *     Base or interrupt.
                   3830:  *
                   3831:  *-NOTES:
                   3832:  *     Does not sleep.
                   3833:  *
                   3834:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   3835:  *     calling this function.
                   3836:  *
                   3837:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   3838:  *     held across calls to this function.
                   3839:  *
                   3840:  *-SEE ALSO:
                   3841:  *     bcanput (), canput (), putbq (), putq (), qenable (), rmvq ()
                   3842:  */
                   3843: 
                   3844: #if    __USE_PROTO__
                   3845: mblk_t * (getq) (queue_t * q)
                   3846: #else
                   3847: mblk_t *
                   3848: getq __ARGS ((q))
                   3849: queue_t              * q;
                   3850: #endif
                   3851: {
                   3852:        pl_t            prev_pl;
                   3853:        mblk_t        * mp;
                   3854: 
                   3855:        prev_pl = QFREEZE_TRACE (q, "getq");
                   3856: 
                   3857:        if ((mp = q->q_first) != NULL) {
                   3858:                ulong_t         msgsize;
                   3859: 
                   3860:                /*
                   3861:                 * There is a message. Dequeue it and adjust the flow-control
                   3862:                 * parameters appropriately depending on whether the message
                   3863:                 * is a priority message and also on the band of the message.
                   3864:                 */
                   3865: 
                   3866:                if ((q->q_first = mp->b_next) == NULL) {
                   3867: 
                   3868:                        q->q_last = NULL;
                   3869:                        QUEUE_DRAINED (q);
                   3870:                } else
                   3871:                        mp->b_next->b_prev = NULL;
                   3872: 
                   3873:                /*
                   3874:                 * Record the message band for the putq () enabling mechanism.
                   3875:                 */
                   3876: 
                   3877:                q->q_lastband = mp->b_band;
                   3878: 
                   3879: 
                   3880:                /*
                   3881:                 * If the message is a priority-band message, we have to
                   3882:                 * finish up the dequeueing operation by adjusting the
                   3883:                 * "qb_first" and "qb_last" members of the "qband" structure.
                   3884:                 *
                   3885:                 * We do this below with the band flow-control management.
                   3886:                 */
                   3887: 
                   3888:                ASSERT (mp->b_datap != NULL);
                   3889: 
                   3890:                if (! IS_PRI_MSG (mp)) {
                   3891: 
                   3892:                        msgsize = MSG_SIZE (mp);
                   3893: 
                   3894:                        if (mp->b_band > 0) {
                   3895:                                qband_t       * qbandp = QUEUE_BAND (q, mp->b_band);
                   3896: 
                   3897:                                ASSERT (qbandp->qb_first == mp);
                   3898: 
                   3899:                                QBAND_DEQUEUE (qbandp, mp);
                   3900: 
                   3901:                                QBAND_REDUCE (q, qbandp, msgsize);
                   3902:                        } else
                   3903:                                QUEUE_REDUCE (q, msgsize);
                   3904:                }
                   3905:        } else {
                   3906:                /*
                   3907:                 * The queue is empty; we set a flag to indicate to putq ()
                   3908:                 * that it should enable the queue when a message is put.
                   3909:                 */
                   3910: 
                   3911:                q->q_flag |= QWANTR;
                   3912:        }
                   3913: 
                   3914: 
                   3915:        /*
                   3916:         * Since we are in a path with QUEUE_REDUCE (), check for QBACK before
                   3917:         * unfreezing the stream.
                   3918:         */
                   3919: 
                   3920:        {
                   3921:                unsigned long   back;
                   3922: 
                   3923:                if ((back = q->q_flag & QBACK) != 0)
                   3924:                        q->q_flag &= ~ QBACK;
                   3925: 
                   3926:                QUNFREEZE_TRACE (q, prev_pl);
                   3927: 
                   3928:                if (back)
                   3929:                        QUEUE_BACKENAB (q);
                   3930:        }
                   3931: 
                   3932:        return mp;
                   3933: }
                   3934: 
                   3935: 
                   3936: /*
                   3937:  *-STATUS:
                   3938:  *     DDI/DKI
                   3939:  *
                   3940:  *-NAME:
                   3941:  *     insq            Insert a message into a queue.
                   3942:  *
                   3943:  *-SYNOPSIS:
                   3944:  *     #include <sys/stream.h>
                   3945:  *
                   3946:  *     int insq (queue_t * q, mblk_t * emp, mblk_t * nmp);
                   3947:  *
                   3948:  *-ARGUMENTS:
                   3949:  *     q               Pointer to the queue containing message "emp".
                   3950:  *
                   3951:  *     emp             Pointer to the existing message before which the new
                   3952:  *                     message is to be inserted.
                   3953:  *
                   3954:  *     nmp             Pointer to the new message to be inserted.
                   3955:  *
                   3956:  *-DESCRIPTION:
                   3957:  *     insq () inserts a message into a queue. The message to be inserted,
                   3958:  *     "nmp", is placed in the queue pointer to by "q", immediately before
                   3959:  *     the message "emp". If "emp" is NULL, the new message is placed at the
                   3960:  *     end of the queue. All flow control parameters are updated. The service
                   3961:  *     procedure is scheduled to run unless disabled by a previous call to
                   3962:  *     noenable ().
                   3963:  *
                   3964:  *     Messages are ordered in the queue based on their priority. If an
                   3965:  *     attempt is made to insert a message out of order in the queue, then
                   3966:  *     "nmp" is not enqueued.
                   3967:  *
                   3968:  *-RETURN VALUE:
                   3969:  *     If "nmp" was successfully enqueued, insq () returns 1. Otherwise,
                   3970:  *     insq () returns 0.
                   3971:  *
                   3972:  *-LEVEL:
                   3973:  *     Base or interrupt.
                   3974:  *
                   3975:  *-NOTES:
                   3976:  *     Does not sleep.
                   3977:  *
                   3978:  *     The caller must have the stream frozen [see freezestr ()] when calling
                   3979:  *     this function.
                   3980:  *
                   3981:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   3982:  *     held across calls to this function.
                   3983:  *
                   3984:  *     The insertion can fail if there is not enough memory to allocate the
                   3985:  *     accounting data structures used with messages whose priority bands are
                   3986:  *     greater than zero.
                   3987:  *
                   3988:  *     If "emp" is non-NULL, it must point to a message in the queue pointed
                   3989:  *     to by "q", or a system panic could result.
                   3990:  *
                   3991:  *-SEE ALSO:
                   3992:  *     freezestr (), getq (), putbq (), putq (), rmvq (), unfreezestr ()
                   3993:  */
                   3994: 
                   3995: #if    __USE_PROTO__
                   3996: int (insq) (queue_t * q, mblk_t * emp, mblk_t * nmp)
                   3997: #else
                   3998: int
                   3999: insq __ARGS ((q, emp, nmp))
                   4000: queue_t              * q;
                   4001: mblk_t       * emp;
                   4002: mblk_t       * nmp;
                   4003: #endif
                   4004: {
                   4005:        qband_t       * qbandp;
                   4006: 
                   4007:        ASSERT (nmp != NULL);
                   4008:        QFROZEN_TRACE (q, "insq");
                   4009: 
                   4010: 
                   4011:        /*
                   4012:         * The code for high-priority messages has been factored out into a
                   4013:         * completely separate path since the legality tests are incompatible
                   4014:         * with the regular sequence, and in addition because such messages do
                   4015:         * not have their size accumulated in the flow control-parameters at
                   4016:         * all, at all. The execution path here is torturous enough without
                   4017:         * folding all the checks into a sequence with a common exit.
                   4018:         */
                   4019: 
                   4020:        if (IS_PRI_MSG (nmp)) {
                   4021:                /*
                   4022:                 * Since putq () is defined as forcing b_band to 0 for high-
                   4023:                 * priority messages, we do the same.
                   4024:                 */
                   4025: 
                   4026:                nmp->b_band = 0;
                   4027: 
                   4028:                if ((nmp->b_next = emp) == NULL) {
                   4029: 
                   4030:                        if ((nmp->b_prev = q->q_last) == NULL) {
                   4031: 
                   4032:                                q->q_first = nmp;
                   4033:                        } else {
                   4034: 
                   4035:                                if (! IS_PRI_MSG (nmp->b_prev))
                   4036:                                        return 0;
                   4037: 
                   4038:                                nmp->b_prev->b_next = nmp;
                   4039:                        }
                   4040: 
                   4041:                        q->q_last = nmp;
                   4042:                } else {
                   4043: 
                   4044:                        if ((nmp->b_prev = emp->b_prev) == NULL) {
                   4045: 
                   4046:                                q->q_first = nmp;
                   4047:                        } else {
                   4048: 
                   4049:                                if (! IS_PRI_MSG (nmp->b_prev))
                   4050:                                        return 0;
                   4051: 
                   4052:                                nmp->b_prev->b_next = nmp;
                   4053:                        }
                   4054: 
                   4055:                        emp->b_prev = nmp;
                   4056: 
                   4057:                }
                   4058: 
                   4059: 
                   4060:                /*
                   4061:                 * A high-priority message causes a queue to be scheduled,
                   4062:                 * even if a noenable () has been done. If we cannot schedule
                   4063:                 * the queue for some reason (it is disabled with qprocsoff ()
                   4064:                 * or has no service routine) that is not our concern.
                   4065:                 */
                   4066: 
                   4067:                (void) QUEUE_TRYSCHED (q);
                   4068:                return 1;
                   4069:        }
                   4070: 
                   4071: 
                   4072:        qbandp = NULL;          /* paranoia */
                   4073: 
                   4074:        if (nmp->b_band > 0 &&
                   4075:            (qbandp = QUEUE_BAND (q, nmp->b_band)) == NULL &&
                   4076:            (qbandp = QBAND_ALLOC (q, nmp->b_band)) == NULL) {
                   4077:                /*
                   4078:                 * Return failure if we were unable to allocate a necessary
                   4079:                 * extra band structure.
                   4080:                 */
                   4081: 
                   4082:                return 0;
                   4083:        }
                   4084: 
                   4085: 
                   4086:        if ((nmp->b_next = emp) == NULL) {
                   4087: 
                   4088:                if ((nmp->b_prev = q->q_last) == NULL) {
                   4089: 
                   4090:                        q->q_first = nmp;
                   4091:                } else {
                   4092: 
                   4093:                        if (nmp->b_prev->b_band < nmp->b_band)
                   4094:                                return 0;
                   4095: 
                   4096:                        nmp->b_prev->b_next = nmp;
                   4097: 
                   4098:                }
                   4099: 
                   4100:                q->q_last = nmp;
                   4101: 
                   4102:        } else {
                   4103:                /*
                   4104:                 * The check against "emp" isn't sufficient, since this
                   4105:                 * request could be attempting to insert a message in the
                   4106:                 * middle of a sequence of messages with a lower band.
                   4107:                 */
                   4108: 
                   4109:                if (emp->b_band > nmp->b_band || IS_PRI_MSG (emp))
                   4110:                        return 0;
                   4111: 
                   4112:                if ((nmp->b_prev = emp->b_prev) == NULL) {
                   4113: 
                   4114:                        q->q_first = nmp;
                   4115:                } else {
                   4116: 
                   4117:                        if (nmp->b_prev->b_band < nmp->b_band)
                   4118:                                return 0;
                   4119: 
                   4120:                        emp->b_prev->b_next = nmp;
                   4121:                }
                   4122: 
                   4123:                emp->b_prev = nmp;
                   4124:        }
                   4125: 
                   4126: 
                   4127:        /*
                   4128:         * Now update the flow control information and priority-band pointers
                   4129:         * after possibly scheduling the queue.
                   4130:         */
                   4131: 
                   4132:        if (QUEUE_CHECK_SCHED (q, nmp, qbandp)) {
                   4133:                /*
                   4134:                 * Keep the band pointers updated.
                   4135:                 */
                   4136: 
                   4137:                if (qbandp->qb_first == emp)
                   4138:                        qbandp->qb_first = nmp;
                   4139: 
                   4140:                if (qbandp->qb_last == NULL || (qbandp->qb_last->b_next == emp))
                   4141:                        qbandp->qb_last = nmp;
                   4142:        }
                   4143: 
                   4144:        return 1;                       /* success ! */
                   4145: }
                   4146: 
                   4147: 
                   4148: /*
                   4149:  *-STATUS:
                   4150:  *     DDI/DKI
                   4151:  *
                   4152:  *-NAME:
                   4153:  *     linkb           Concatenate two message blocks.
                   4154:  *
                   4155:  *-SYNOPSIS:
                   4156:  *     #include <sys/stream.h>
                   4157:  *
                   4158:  *     void linkb (mblk_t * mp1, mblk_t * mp2);
                   4159:  *
                   4160:  *-ARGUMENTS:
                   4161:  *     mp1             Pointer to the message block to which "mp2" is to be
                   4162:  *                     added.
                   4163:  *
                   4164:  *     mp2             Pointer to the message to be added.
                   4165:  *
                   4166:  *-DESCRIPTION:
                   4167:  *     linkb () appends the message "mp2" to the tail of message "mp1". The
                   4168:  *     continuation pointer "b_cont" of the last message block in the first
                   4169:  *     message is set to point to the second message.
                   4170:  *
                   4171:  *-RETURN VALUE:
                   4172:  *     None.
                   4173:  *
                   4174:  *-LEVEL:
                   4175:  *     Base or interrupt.
                   4176:  *
                   4177:  *-NOTES:
                   4178:  *     Does not sleep.
                   4179:  *
                   4180:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   4181:  *     held across calls to this function.
                   4182:  *
                   4183:  *-SEE ALSO:
                   4184:  *     unlinkb (), msgb
                   4185:  */
                   4186: 
                   4187: #if    __USE_PROTO__
                   4188: void (linkb) (mblk_t * mp1, mblk_t * mp2)
                   4189: #else
                   4190: void
                   4191: linkb __ARGS ((mp1, mp2))
                   4192: mblk_t       * mp1;
                   4193: mblk_t       * mp2;
                   4194: #endif
                   4195: {
                   4196:        ASSERT (mp1 != NULL && mp2 != NULL);
                   4197: 
                   4198:        while (mp1->b_cont != NULL)
                   4199:                mp1 = mp1->b_cont;
                   4200: 
                   4201:        mp1->b_cont = mp2;
                   4202: }
                   4203: 
                   4204: 
                   4205: /*
                   4206:  *-STATUS:
                   4207:  *     DDI/DKI
                   4208:  *
                   4209:  *-NAME:
                   4210:  *     msgdsize        Return number of bytes of data in a message.
                   4211:  *
                   4212:  *-SYNOPSIS:
                   4213:  *     #include <sys/stream.h>
                   4214:  *
                   4215:  *     int msgdsize (mblk_t * mp);
                   4216:  *
                   4217:  *-ARGUMENTS:
                   4218:  *     mp              Pointer to the message to be evaluated.
                   4219:  *
                   4220:  *-DESCRIPTION:
                   4221:  *     msgdsize () counts the number of bytes of data in the message pointed
                   4222:  *     to by "mp". Only bytes included in message blocks of type "M_DATA" are
                   4223:  *     included in the count.
                   4224:  *
                   4225:  *-RETURN VALUE:
                   4226:  *     The number of bytes of data in the message.
                   4227:  *
                   4228:  *-LEVEL:
                   4229:  *     Base or interrupt.
                   4230:  *
                   4231:  *-NOTES:
                   4232:  *     Does not sleep.
                   4233:  *
                   4234:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   4235:  *     held across calls to this function.
                   4236:  *
                   4237:  *-SEE ALSO:
                   4238:  *     msgb
                   4239:  */
                   4240: 
                   4241: #if    __USE_PROTO__
                   4242: int (msgdsize) (mblk_t * mp)
                   4243: #else
                   4244: int
                   4245: msgdsize __ARGS ((mp))
                   4246: mblk_t       * mp;
                   4247: #endif
                   4248: {
                   4249:        int     sum = 0;
                   4250: 
                   4251:        ASSERT (mp != NULL);
                   4252: 
                   4253:        do
                   4254:                if (mp->b_datap->db_type == M_DATA)
                   4255:                        sum += mp->b_wptr - mp->b_rptr;
                   4256:        while ((mp = mp->b_cont) != NULL);
                   4257: 
                   4258:        return sum;
                   4259: }
                   4260: 
                   4261: 
                   4262: /*
                   4263:  *-STATUS:
                   4264:  *     DDI/DKI
                   4265:  *
                   4266:  *-NAME:
                   4267:  *     msgpullup       Concatenate bytes in a message,
                   4268:  *
                   4269:  *-SYNOPSIS:
                   4270:  *     #include <sys/stream.h>
                   4271:  *
                   4272:  *     mblk_t * msgpullup (mblk_t * mp, int len);
                   4273:  *
                   4274:  *-ARGUMENTS:
                   4275:  *     mp              Pointer to the message whose blocks are to be
                   4276:  *                     concatenated.
                   4277:  *
                   4278:  *     len             Number of bytes to concatenate,
                   4279:  *
                   4280:  *-DESCRIPTION:
                   4281:  *     msgpullup () concatenates and aligns the first "len" data bytes of the
                   4282:  *     message pointed to by "mp", copying the data into a new message. The
                   4283:  *     original message is unaltered. If "len" equals -1, all data are
                   4284:  *     concatenated. If "len" bytes of the same message type cannot be found,
                   4285:  *     msgpullup () fails and returns NULL.
                   4286:  *
                   4287:  *-RETURN VALUE:
                   4288:  *     On success, a pointer to the new message is returned; on failure a
                   4289:  *     NULL pointer is returned.
                   4290:  *
                   4291:  *-LEVEL:
                   4292:  *     Base or interrupt.
                   4293:  *
                   4294:  *-NOTES:
                   4295:  *     Does not sleep.
                   4296:  *
                   4297:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   4298:  *     held across calls to this function.
                   4299:  *
                   4300:  *-SEE ALSO:
                   4301:  *     allocb (), msgb
                   4302:  */
                   4303: 
                   4304: #if    __USE_PROTO__
                   4305: mblk_t * (msgpullup) (mblk_t * mp, int len)
                   4306: #else
                   4307: mblk_t *
                   4308: msgpullup __ARGS ((mp, len))
                   4309: mblk_t       * mp;
                   4310: int            len;
                   4311: #endif
                   4312: {
                   4313:        size_t          size;
                   4314:        uchar_t         msgtype;
                   4315:        mblk_t        * scan;
                   4316: 
                   4317:        ASSERT (mp != NULL);
                   4318:        ASSERT (mp->b_datap != NULL);
                   4319: 
                   4320:        /*
                   4321:         * Something that is now particularly well-specified about this new
                   4322:         * routine (intended to replace pullupmsg () from SVR3.2 STREAMS and
                   4323:         * the SVR4 DDI/DKI) is what happens to the message data in the
                   4324:         * original message *after* the "len" bytes to be pulled up?
                   4325:         *
                   4326:         * Basically, without a usage example (which I haven't been able to
                   4327:         * find in the new SVR4 MP STREAMS programmer's guide) I can't tell
                   4328:         * whether the remaining data in the message should be duplicated for
                   4329:         * the new message or not. In order to make this routine a closer
                   4330:         * functional replacement for pullupmsg (), I'm tempted to say "yes",
                   4331:         * but it could be that the new message is a single standalone message
                   4332:         * block. Hence, I'm putting in a switch to select between the two
                   4333:         * interpretations I consider most likely.
                   4334:         *
                   4335:         * This is particularly important for "msgpullup (mp, 0)", which I'd
                   4336:         * like to make an error.
                   4337:         */
                   4338: 
                   4339: #define        MSGPULLUP_DUPMSG
                   4340: 
                   4341:        if (len == 0) {
                   4342: #ifdef MSGPULLUP_DUPMSG
                   4343:                return dupmsg (mp);
                   4344: #else
                   4345:                return MSG_ALLOC (0, BPRI_MED, KM_NOSLEEP);
                   4346: #endif
                   4347:        }
                   4348: 
                   4349:        /*
                   4350:         * Begin by calculating the amount of data of the same message type
                   4351:         * that is present in the message.
                   4352:         */
                   4353: 
                   4354:        msgtype = mp->b_datap->db_type;
                   4355:        size = 0;
                   4356:        scan = mp;
                   4357: 
                   4358:        do
                   4359:                size += scan->b_wptr - scan->b_rptr;
                   4360:        while ((scan = scan->b_cont) != NULL &&
                   4361:               scan->b_datap->db_type == msgtype);
                   4362: 
                   4363:        if (len == -1)
                   4364:                len = size;
                   4365:        else if (len > size)
                   4366:                return NULL;
                   4367: 
                   4368:        /*
                   4369:         * Note that it may be reasonable to interpret the definition of this
                   4370:         * function as implying that data can be shared between the old and
                   4371:         * new message blocks if the old data block does not need to be
                   4372:         * altered (ie, if the previous data was aligned and contiguous up to
                   4373:         * the length "len").
                   4374:         */
                   4375: 
                   4376: /* #define     MSGPULLUP_SHARE */
                   4377: 
                   4378: #ifdef MSGPULLUP_SHARE
                   4379:        if ((mp->b_wptr - mp->b_rptr) >= len &&
                   4380:            ((ulong_t) mp->b_rptr) & (sizeof (int) - 1)) == 0)
                   4381:                return dupmsg (mp);
                   4382: #endif /* defined (MSGPULLUP_SHARE) */
                   4383: 
                   4384: 
                   4385:        if ((scan = MSGB_ALLOC (len, BPRI_MED, KM_NOSLEEP)) == NULL)
                   4386:                return NULL;
                   4387: 
                   4388:        /*
                   4389:         * There are some message attributes other than data that need to be
                   4390:         * copied from the source to the new message.
                   4391:         */
                   4392: 
                   4393:        scan->b_band = mp->b_band;
                   4394:        scan->b_flag |= mp->b_flag & ~ MSGMASK_SYSTEM;
                   4395: 
                   4396: 
                   4397:        /*
                   4398:         * Now transfer the data from the old space to the new space.
                   4399:         *
                   4400:         * More unspecified behaviour deals with how zero-length blocks are
                   4401:         * to be treated. The following loop is coded specifically to skip
                   4402:         * over zero-length message blocks in the source that follow the
                   4403:         * "len" copied bytes of data.
                   4404:         */
                   4405: 
                   4406: #define        MSGPULLUP_DUPMSG
                   4407: 
                   4408:        while (mp != NULL) {
                   4409:                size_t          blklen = mp->b_wptr - mp->b_rptr;
                   4410: 
                   4411:                if (blklen > 0)
                   4412:                        memcpy (scan->b_wptr, mp->b_rptr, blklen);
                   4413: 
                   4414:                scan->b_wptr += blklen;
                   4415:                len -= blklen;
                   4416: 
                   4417: 
                   4418:                if (blklen > len) {
                   4419:                        /*
                   4420:                         * Copy a partial block. Since this must also be the
                   4421:                         * last message block in the source message whose
                   4422:                         * data are being moved to the new message, here is a
                   4423:                         * good place to decide on the dispensation of the
                   4424:                         * remaining data.
                   4425:                         */
                   4426: 
                   4427: #ifdef MSGPULLUP_DUPMSG
                   4428:                        if ((scan->b_cont = dupmsg (mp)) == NULL) {
                   4429:                                /*
                   4430:                                 * The remaining data could not be duplicated,
                   4431:                                 * so we have to fail the call overall.
                   4432:                                 */
                   4433: 
                   4434:                                freeb (scan);
                   4435:                                return NULL;
                   4436:                        }
                   4437: #endif
                   4438:                        break;
                   4439:                }
                   4440: 
                   4441:                mp = mp->b_cont;
                   4442:        }
                   4443: 
                   4444: 
                   4445:        return scan;
                   4446: }
                   4447: 
                   4448: 
                   4449: /*
                   4450:  *-STATUS:
                   4451:  *     DDI/DKI
                   4452:  *
                   4453:  *-NAME:
                   4454:  *     noenable        Prevent a queue from being scheduled.
                   4455:  *
                   4456:  *-SYNOPSIS:
                   4457:  *     #include <sys/stream.h>
                   4458:  *
                   4459:  *     void noenable (queue_t * q);
                   4460:  *
                   4461:  *-ARGUMENTS:
                   4462:  *     q               Pointer to the queue.
                   4463:  *
                   4464:  *-DESCRIPTION:
                   4465:  *     The noenable () function prevents the service routine of the queue
                   4466:  *     pointed to by "q" from being scheduled for service by insq (),
                   4467:  *     putbq (), or putq () when enqueuing a message that is not a high
                   4468:  *     priority message. This restriction can be lifted with the enableok ()
                   4469:  *     function.
                   4470:  *
                   4471:  *     noenable () does not prevent the queue's service routine from being
                   4472:  *     scheduled when a high priority message is enqueued, or by an explicit
                   4473:  *     call to qenable ().
                   4474:  *
                   4475:  *-RETURN VALUE:
                   4476:  *     None.
                   4477:  *
                   4478:  *-LEVEL:
                   4479:  *     Base or interrupt.
                   4480:  *
                   4481:  *-NOTES:
                   4482:  *     Does not sleep.
                   4483:  *
                   4484:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   4485:  *     calling this function.
                   4486:  *
                   4487:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   4488:  *     held across calls to this function.
                   4489:  *
                   4490:  *-SEE ALSO:
                   4491:  *     enableok (), insq (), putbq (), putq (), qenable (), queue
                   4492:  */
                   4493: 
                   4494: #if    __USE_PROTO__
                   4495: void (noenable) (queue_t * q)
                   4496: #else
                   4497: void
                   4498: noenable __ARGS ((q))
                   4499: queue_t              * q;
                   4500: #endif
                   4501: {
                   4502:        pl_t            prev_pl;
                   4503: 
                   4504:        prev_pl = QFREEZE_TRACE (q, "noenable");
                   4505: 
                   4506:        q->q_flag |= QNOENB;
                   4507: 
                   4508:        QUNFREEZE_TRACE (q, prev_pl);
                   4509: }
                   4510: 
                   4511: 
                   4512: /*
                   4513:  *-STATUS:
                   4514:  *     DDI/DKI
                   4515:  *
                   4516:  *-NAME:
                   4517:  *     OTHERQ          Get pointer to queue's partner queue.
                   4518:  *
                   4519:  *-SYNOPSIS:
                   4520:  *     #include <sys/stream.h>
                   4521:  *
                   4522:  *     queue_t * OTHERQ (queue_t * q);
                   4523:  *
                   4524:  *-ARGUMENTS:
                   4525:  *     q               Pointer to the queue.
                   4526:  *
                   4527:  *-DESCRIPTION:
                   4528:  *     The OTHERQ () function returns a pointer to the other of the two
                   4529:  *     queue structures that make up an instance of a STREAMS module or
                   4530:  *     driver. If "q" points to the read queue the write queue will be
                   4531:  *     returned, and vice versa.
                   4532:  *
                   4533:  *-RETURN VALUE:
                   4534:  *     OTHERQ () returns a pointer to the queue's partner.
                   4535:  *
                   4536:  *-LEVEL:
                   4537:  *     Base or interrupt.
                   4538:  *
                   4539:  *-NOTES:
                   4540:  *     Does not sleep.
                   4541:  *
                   4542:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   4543:  *     held across calls to this function.
                   4544:  *
                   4545:  *-SEE ALSO:
                   4546:  *     RD (), WR ()
                   4547:  */
                   4548: 
                   4549: #if    __USE_PROTO__
                   4550: queue_t * (OTHERQ) (queue_t * q)
                   4551: #else
                   4552: queue_t *
                   4553: OTHERQ __ARGS ((q))
                   4554: queue_t              * q;
                   4555: #endif
                   4556: {
                   4557:        return OTHERQ (q);
                   4558: }
                   4559: 
                   4560: 
                   4561: /*
                   4562:  *-STATUS:
                   4563:  *     DDI/DKI
                   4564:  *
                   4565:  *-NAME:
                   4566:  *     pcmsg           Test whether a message is a priority control message.
                   4567:  *
                   4568:  *-SYNOPSIS:
                   4569:  *     #include <sys/types.h>
                   4570:  *     #include <sys/stream.h>
                   4571:  *     #include <sys/ddi.h>
                   4572:  *
                   4573:  *     int pcmsg (uchar_t type);
                   4574:  *
                   4575:  *-ARGUMENTS:
                   4576:  *     type            The type of message to be tested.
                   4577:  *
                   4578:  *-DESCRIPTION:
                   4579:  *     The pcmsg () function tests the type of message to determine if it is
                   4580:  *     a priority control message (also known as a high priority message).
                   4581:  *     The "db_type" field of the "datab" structure contains the message
                   4582:  *     type. This field may be accessed through the message block using
                   4583:  *     "mp->b_datap->db_type".
                   4584:  *
                   4585:  *-RETURN VALUE:
                   4586:  *     pcmsg () returns 1 if the message is a priority control message and
                   4587:  *     0 if the message is any other type.
                   4588:  *
                   4589:  *-LEVEL:
                   4590:  *     Base or interrupt.
                   4591:  *
                   4592:  *-NOTES:
                   4593:  *     Does not sleep.
                   4594:  *
                   4595:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   4596:  *     held across calls to this function.
                   4597:  *
                   4598:  *-SEE ALSO:
                   4599:  *     allocb (), datab, msgb, messages
                   4600:  */
                   4601: 
                   4602: #if    __USE_PROTO__
                   4603: int (pcmsg) (uchar_t type)
                   4604: #else
                   4605: int
                   4606: pcmsg __ARGS ((type))
                   4607: uchar_t                type;
                   4608: #endif
                   4609: {
                   4610:        return pcmsg (type);
                   4611: }
                   4612: 
                   4613: 
                   4614: /*
                   4615:  *-STATUS:
                   4616:  *     Compatibility (pre-MP DDI/DKI)
                   4617:  *
                   4618:  *-NAME:
                   4619:  *     pullupmsg       Concatenate bytes in a message.
                   4620:  *
                   4621:  *-SYNOPSIS:
                   4622:  *     #include <sys/stream.h>
                   4623:  *
                   4624:  *     int pullupmsg (mblk_t * mp, int len);
                   4625:  *
                   4626:  *-ARGUMENTS:
                   4627:  *     mp              Pointer to the message whose blocks are to be
                   4628:  *                     concatenated.
                   4629:  *
                   4630:  *     len             Number of bytes to concatenate.
                   4631:  *
                   4632:  *-DESCRIPTION:
                   4633:  *     pullupmsg () tries to combine multiple data blocks into a single
                   4634:  *     block. pullupmsg () concatenates and aligns the first "len" data bytes
                   4635:  *     of the message pointed to by "mp". If "len" equals -1, all data is
                   4636:  *     concatenated. If "len" bytes of the same message type cannot be found,
                   4637:  *     pullupmsg () fails and returns 0.
                   4638:  *
                   4639:  *-RETURN VALUE:
                   4640:  *     On success, 1 is returned; on failure, 0 is returned.
                   4641:  *
                   4642:  *-LEVEL:
                   4643:  *     Base or interrupt.
                   4644:  *
                   4645:  *-NOTES:
                   4646:  *     Does not sleep.
                   4647:  *
                   4648:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   4649:  *     held across calls to this function.
                   4650:  *
                   4651:  *     This function is provided for compatibility with versions of the
                   4652:  *     DDI/DKI prior to the System V, Release 4 Multiprocessor edition. Calls
                   4653:  *     to this function should be replaced by calls to the msgpullup ()
                   4654:  *     function instead.
                   4655:  *
                   4656:  *-SEE ALSO:
                   4657:  *     allocb (), msgpullup ()
                   4658:  */
                   4659: 
                   4660: #if    __USE_PROTO__
                   4661: int (pullupmsg) (mblk_t * mp, int len)
                   4662: #else
                   4663: int
                   4664: pullupmsg __ARGS ((mp, len))
                   4665: mblk_t       * mp;
                   4666: int            len;
                   4667: #endif
                   4668: {
                   4669:        mblk_t        * newmsg;
                   4670: 
                   4671:        ASSERT (mp != NULL);
                   4672:        ASSERT (mp->b_datap != NULL);
                   4673: 
                   4674:        /*
                   4675:         * If the first block of the old message is sufficiently large to
                   4676:         * encompass the pullup request, then we need do no work. It is not
                   4677:         * clear whether the new msgpullup () function allows this simple
                   4678:         * optimisation, so we test for this here to guarantee it.
                   4679:         */
                   4680: 
                   4681:        if (((mp->b_wptr - mp->b_rptr) > len ||
                   4682:                (len == -1 && mp->b_cont == NULL)) &&
                   4683:            ((ulong_t) mp->b_rptr & (sizeof (int) - 1)) == 0) {
                   4684:                /*
                   4685:                 * Do nothing and return success. Note that the alignment test
                   4686:                 * above is specific to the i386 implementation.
                   4687:                 */
                   4688: 
                   4689:                return 1;
                   4690:        }
                   4691: 
                   4692: 
                   4693:        /*
                   4694:         * Now use the new msgpullup () function to perform the harder task
                   4695:         * of concatenating the message, and then perform some subterfuge to
                   4696:         * ensure that the new message replaces the old message's storage.
                   4697:         *
                   4698:         * This requires some delicate manipulations to avoid disrupting
                   4699:         * the flags and whatnot that support the message-triple storage
                   4700:         * system.
                   4701:         */
                   4702: 
                   4703:        if ((newmsg = msgpullup (mp, len)) == NULL)
                   4704:                return 0;
                   4705: 
                   4706: 
                   4707:        {
                   4708:                dblk_t        * temp = mp->b_datap;
                   4709:                mp->b_datap = newmsg->b_datap;
                   4710:                newmsg->b_datap = temp;
                   4711:        } {
                   4712:                mblk_t        * temp = mp->b_cont;
                   4713:                mp->b_cont = newmsg->b_cont;
                   4714:                newmsg->b_cont = temp;
                   4715:        }
                   4716: 
                   4717:        mp->b_rptr = newmsg->b_rptr;
                   4718:        mp->b_wptr = newmsg->b_wptr;
                   4719: 
                   4720:        /*
                   4721:         * Since we exchanged the "b_datap" and "b_cont" members of the
                   4722:         * message blocks, freeing the "new" message pointer will free those
                   4723:         * elements of the original message that have been made redundant by
                   4724:         * the pull-up operation, leaving the original message block intact
                   4725:         * but pointing to the rearranged data.
                   4726:         */
                   4727: 
                   4728:        freemsg (newmsg);
                   4729:        return 1;
                   4730: }
                   4731: 
                   4732: 
                   4733: /*
                   4734:  *-STATUS:
                   4735:  *     DDI/DKI
                   4736:  *
                   4737:  *-NAME:
                   4738:  *     put             Call a put procedure.
                   4739:  *
                   4740:  *-SYNOPSIS:
                   4741:  *     #include <sys/stream.h>
                   4742:  *
                   4743:  *     void put (queue_t * q, mblk_t * mp);
                   4744:  *
                   4745:  *-ARGUMENTS:
                   4746:  *     q               Pointer to a message queue.
                   4747:  *
                   4748:  *     mp              Pointer to the message block being passed.
                   4749:  *
                   4750:  *-DESCRIPTION:
                   4751:  *     put () calls the "put" procedure for the queue specified by "q",
                   4752:  *     passing it the arguments "q" and "mp". It is typically used by a
                   4753:  *     driver or module to call its own "put" procedure so that the proper
                   4754:  *     accounting is done in the stream.
                   4755:  *
                   4756:  *-RETURN VALUE:
                   4757:  *     None.
                   4758:  *
                   4759:  *-LEVEL:
                   4760:  *     Base or interrupt.
                   4761:  *
                   4762:  *-NOTES:
                   4763:  *     Does not sleep.
                   4764:  *
                   4765:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   4766:  *     calling this function.
                   4767:  *
                   4768:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   4769:  *     held across calls to this function.
                   4770:  *
                   4771:  *     DDI/DKI conforming drivers and modules are no longer permitted to call
                   4772:  *     "put" procedures directly, but must call through the appropriate
                   4773:  *     STREAMS utility function - for example, put (), putnext (), putctl (),
                   4774:  *     putnextctl (), or qreply (). "put (q, mp)" is provided as a DDI/DKI-
                   4775:  *     conforming equivalent to a direct call to a "put" procedure, which is
                   4776:  *     no longer allowed.
                   4777:  *
                   4778:  *-SEE ALSO:
                   4779:  *     putctl (), putctl1 (), putnext (), putnextctl (), putnextctl1 (),
                   4780:  *     qreply ()
                   4781:  */
                   4782: 
                   4783: #if    __USE_PROTO__
                   4784: void (put) (queue_t * q, mblk_t * mp)
                   4785: #else
                   4786: void
                   4787: put __ARGS ((q, mp))
                   4788: queue_t              * q;
                   4789: mblk_t       * mp;
                   4790: #endif
                   4791: {
                   4792:        pl_t            prev_pl;
                   4793: 
                   4794:        ASSERT (mp != NULL);
                   4795:        ASSERT (mp->b_datap != NULL);
                   4796: 
                   4797:        /*
                   4798:         * If a message is put to a queue that either has no put procedure at
                   4799:         * all, or has been disabled with qprocsoff (), then we discard the
                   4800:         * message and return without doing anything.
                   4801:         */
                   4802: 
                   4803:        prev_pl = QFREEZE_TRACE (q, "put");
                   4804: 
                   4805:        if ((q->q_active == 0 && (q->q_flag & QPROCSOFF) != 0) ||
                   4806:            q->q_qinfo->qi_putp == NULL)
                   4807:                cmn_err (CE_WARN, "put () to disabled queue/NULL putp");
                   4808:        else
                   4809:                QUEUE_PUT (q, mp, prev_pl);
                   4810: 
                   4811:        QUNFREEZE_TRACE (q, prev_pl);
                   4812: }
                   4813: 
                   4814: 
                   4815: /*
                   4816:  *-STATUS:
                   4817:  *     DDI/DKI
                   4818:  *
                   4819:  *-NAME:
                   4820:  *     putbq           Place a message at the head of a queue.
                   4821:  *
                   4822:  *-SYNOPSIS:
                   4823:  *     #include <sys/stream.h>
                   4824:  *
                   4825:  *     int putbq (queue_t * q, mblk_t * mp);
                   4826:  *
                   4827:  *-ARGUMENTS:
                   4828:  *     q               Pointer to the queue.
                   4829:  *
                   4830:  *     mp              Pointer to the message.
                   4831:  *
                   4832:  *-DESCRIPTION:
                   4833:  *     putbq () puts a message back at the head of the queue. If messages of
                   4834:  *     a higher priority are present on the queue, then "bp" is placed at the
                   4835:  *     head of its corresponding priority band.
                   4836:  *
                   4837:  *     All flow control parameters are updated. The queue's service routine
                   4838:  *     is scheduled if it has not been disabled by a previous call to
                   4839:  *     noenable ().
                   4840:  *
                   4841:  *     putbq () is usually called when bcanputnext () or canputnext ()
                   4842:  *     determines that the message cannot be passed on to the next stream
                   4843:  *     component.
                   4844:  *
                   4845:  *-RETURN VALUE:
                   4846:  *     putbq () returns 1 on success and 0 on failure.
                   4847:  *
                   4848:  *-LEVEL:
                   4849:  *     Base or interrupt.
                   4850:  *
                   4851:  *-NOTES:
                   4852:  *     Does not sleep.
                   4853:  *
                   4854:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   4855:  *     calling this function.
                   4856:  *
                   4857:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   4858:  *     held across calls to this function.
                   4859:  *
                   4860:  *     putbq () can fail if there is not enough memory to allocate the
                   4861:  *     accounting data structures used with messages whose priority bands are
                   4862:  *     greater than zero.
                   4863:  *
                   4864:  *     High priority messages should never be put back on a queue from within
                   4865:  *     a service routine.
                   4866:  *
                   4867:  *-SEE ALSO:
                   4868:  *     bcanputnext (), canputnext (), getq (), insq (), putq (), rmvq (),
                   4869:  *     msgb, queue
                   4870:  */
                   4871: 
                   4872: #if    __USE_PROTO__
                   4873: int (putbq) (queue_t * q, mblk_t * mp)
                   4874: #else
                   4875: int
                   4876: putbq __ARGS ((q, mp))
                   4877: queue_t              * q;
                   4878: mblk_t       * mp;
                   4879: #endif
                   4880: {
                   4881:        pl_t            prev_pl;
                   4882:        qband_t       * qbandp;
                   4883: 
                   4884:        ASSERT (mp != NULL);
                   4885:        ASSERT (mp->b_datap != NULL);
                   4886:        ASSERT (! pcmsg (mp->b_datap->db_type));
                   4887: 
                   4888:        prev_pl = QFREEZE_TRACE (q, "putbq");
                   4889: 
                   4890:        /*
                   4891:         * The code for high-priority messages has been factored out into a
                   4892:         * completely separate path because such messages do not have their
                   4893:         * size accumulated in the flow control-parameters at all, at all, and
                   4894:         * because the location where such messages are to be queued is
                   4895:         * determined in one step without search.
                   4896:         */
                   4897: 
                   4898:        if (IS_PRI_MSG (mp)) {
                   4899:                /*
                   4900:                 * Since putq () is defined as forcing b_band to 0 for high-
                   4901:                 * priority messages, we do the same.
                   4902:                 */
                   4903: 
                   4904:                if ((mp->b_next = q->q_first) == NULL)
                   4905:                        q->q_last = mp;
                   4906:                else
                   4907:                        mp->b_next->b_prev = mp;
                   4908: 
                   4909:                mp->b_prev = NULL;
                   4910:                mp->b_band = 0;
                   4911:                q->q_first = mp;
                   4912: 
                   4913: 
                   4914:                /*
                   4915:                 * A high-priority message causes a queue to be scheduled
                   4916:                 * even if a noenable () has been performed. For putbq (),
                   4917:                 * this is true whether or not the condition set by getq ()
                   4918:                 * returning null is true or not, which is the reason for the
                   4919:                 * proscription against calling this routine for a high-
                   4920:                 * priority message within a service procedure.
                   4921:                 */
                   4922: 
                   4923:                /*
                   4924:                 *!!! We need help from the STREAMS service-routine scheduler
                   4925:                 *!!! to build a testable assertion for detecting when we are
                   4926:                 *!!! called within the context of a service routine.
                   4927:                 */
                   4928: 
                   4929:                (void) QUEUE_TRYSCHED (q);
                   4930:                goto alldone;
                   4931:        }
                   4932: 
                   4933: 
                   4934:        qbandp = NULL;          /* paranoia */
                   4935: 
                   4936:        if (mp->b_band > 0 &&
                   4937:            (qbandp = QUEUE_BAND (q, mp->b_band)) == NULL &&
                   4938:            (qbandp = QBAND_ALLOC (q, mp->b_band)) == NULL)
                   4939:                return 0;
                   4940:        else if (QUEUE_CHECK_SCHED (q, mp, qbandp)) {
                   4941:                /*
                   4942:                 * Deal with band pointer maintenance now.
                   4943:                 */
                   4944: 
                   4945:                if ((mp->b_next = qbandp->qb_first) != NULL) {
                   4946:                        /*
                   4947:                         * We directly know where we want to put the message.
                   4948:                         */
                   4949: 
                   4950:                        if ((mp->b_prev = mp->b_next->b_prev) == NULL)
                   4951:                                q->q_first = mp;
                   4952:                        else
                   4953:                                mp->b_prev->b_next = mp;
                   4954: 
                   4955:                        mp->b_next->b_prev = mp;
                   4956: 
                   4957:                        qbandp->qb_first = mp;
                   4958: 
                   4959:                        goto alldone;
                   4960:                }
                   4961: 
                   4962: 
                   4963:                /*
                   4964:                 * This is the only message in this band. We will need to
                   4965:                 * search for the correct position to queue this message.
                   4966:                 */
                   4967: 
                   4968:                qbandp->qb_last = qbandp->qb_first = mp;
                   4969:        }
                   4970: 
                   4971: 
                   4972:        /*
                   4973:         * Now use a brute-force search for the position. We could use the
                   4974:         * band structures to speed this up, but we anticipate that there will
                   4975:         * be few band or high-priority messages, so that a brute-force search
                   4976:         * will be suitably short.
                   4977:         */
                   4978: 
                   4979:        QUEUE_PLACE_MSG (q, mp, mp->b_band);
                   4980: 
                   4981: alldone:
                   4982:        QUNFREEZE_TRACE (q, prev_pl);
                   4983:        return 1;
                   4984: }
                   4985: 
                   4986: 
                   4987: /*
                   4988:  *-STATUS:
                   4989:  *     DDI/DKI
                   4990:  *
                   4991:  *-NAME:
                   4992:  *     putctl          Send a control message to a queue.
                   4993:  *
                   4994:  *-SYNOPSIS:
                   4995:  *     #include <sys/stream.h>
                   4996:  *
                   4997:  *     int putctl (queue_t * q, int type);
                   4998:  *
                   4999:  *-ARGUMENTS:
                   5000:  *     q               Pointer to the queue to which the message is to be
                   5001:  *                     sent.
                   5002:  *
                   5003:  *     type            Message type (must be control).
                   5004:  *
                   5005:  *-DESCRIPTION:
                   5006:  *     putctl () tests the "type" argument to make sure a data type has not
                   5007:  *     been specified, and then attempts to allocate a message block.
                   5008:  *     putctl () fails if "type" is M_DATA, M_PROTO, or M_PCPROTO, or if a
                   5009:  *     message block cannot be allocated. If successful, putctl () calls the
                   5010:  *     "put" routine of the queue pointed to by "q", passing it the allocated
                   5011:  *     message.
                   5012:  *
                   5013:  *-RETURN VALUE:
                   5014:  *     On success, 1 is returned. Otherwise, if "type" is a data type, or if
                   5015:  *     a message block cannot be allocated, 0 is returned.
                   5016:  *
                   5017:  *-LEVEL:
                   5018:  *     Base or interrupt.
                   5019:  *
                   5020:  *-NOTES:
                   5021:  *     Does not sleep.
                   5022:  *
                   5023:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5024:  *     calling this function.
                   5025:  *
                   5026:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   5027:  *     held across calls to this function.
                   5028:  *
                   5029:  *     The "q" argument to putctl () and putnextctl () may not reference
                   5030:  *     "q_next" (eg, an argument of "q->q_next" is erroneous on a
                   5031:  *     multiprocessor and is disallowed by the DDI/DKI).
                   5032:  *     "putnextctl (q, type)" is provided as a multiprocessor-safe equivalent
                   5033:  *     to the common call "putctl (q->q_next, type)" which is no longer
                   5034:  *     allowed.
                   5035:  *
                   5036:  *-SEE ALSO:
                   5037:  *     put (), putctl1 (), putnextctl (), putnextctl1 ()
                   5038:  */
                   5039: 
                   5040: #if    __USE_PROTO__
                   5041: int (putctl) (queue_t * q, int type)
                   5042: #else
                   5043: int
                   5044: putctl __ARGS ((q, type))
                   5045: queue_t              * q;
                   5046: int            type;
                   5047: #endif
                   5048: {
                   5049:        mblk_t        * ctlmsg;
                   5050: 
                   5051:        QUEUE_TRACE (q, "putctl");
                   5052: 
                   5053:        /*
                   5054:         * We cannot use datamsg () to test the type because datamsg () is
                   5055:         * specified as testing for M_DATA in addition to M_DATA, M_PROTO, and
                   5056:         * M_PCPROTO.
                   5057:         */
                   5058: 
                   5059:        if ((type & (M_PRI - 1)) <= M_PROTO ||
                   5060:            (ctlmsg = MSGB_ALLOC (0, BPRI_HI, KM_NOSLEEP)) == NULL)
                   5061:                return 0;
                   5062: 
                   5063:        ctlmsg->b_datap->db_type = type;
                   5064:        put (q, ctlmsg);
                   5065: 
                   5066:        return 1;
                   5067: }
                   5068: 
                   5069: 
                   5070: /*
                   5071:  *-STATUS:
                   5072:  *     DDI/DKI
                   5073:  *
                   5074:  *-NAME:
                   5075:  *     putctl1         Send a control message with a one-byte parameter to a
                   5076:  *                     queue.
                   5077:  *
                   5078:  *-SYNOPSIS:
                   5079:  *     #include <sys/stream.h>
                   5080:  *
                   5081:  *     int putctl1 (queue_t * q, int type, int param);
                   5082:  *
                   5083:  *-ARGUMENTS:
                   5084:  *     q               Pointer to the queue to which the message is to be
                   5085:  *                     sent.
                   5086:  *
                   5087:  *     type            Message type (must be control).
                   5088:  *
                   5089:  *     param           One-byte parameter.
                   5090:  *
                   5091:  *-DESCRIPTION:
                   5092:  *     putctl1 (), like putctl (), tests the "type" argument to make sure a
                   5093:  *     data type has not been specified, and attempts to allocate a message
                   5094:  *     block. The "param" parameter can be used, for example, to specify the
                   5095:  *     signal number when an "M_PCSIG" message is being sent. putctl1 ()
                   5096:  *     fails if "type" is M_DATA, M_PROTO, or M_PCPROTO, or if a message
                   5097:  *     block cannot be allocated. If successful, putctl1 () calls the "put"
                   5098:  *     routine of the queue pointed to by "q", passing it the allocated
                   5099:  *     message.
                   5100:  *
                   5101:  *-RETURN VALUE:
                   5102:  *     On success, 1 is returned. Otherwise, if "type" is a data type, or if
                   5103:  *     a message block cannot be allocated, 0 is returned.
                   5104:  *
                   5105:  *-LEVEL:
                   5106:  *     Base or interrupt.
                   5107:  *
                   5108:  *-NOTES:
                   5109:  *     Does not sleep.
                   5110:  *
                   5111:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5112:  *     calling this function.
                   5113:  *
                   5114:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   5115:  *     held across calls to this function.
                   5116:  *
                   5117:  *     The "q" argument to putctl1 () and putnextctl1 () may not reference
                   5118:  *     "q_next" (eg, an argument of "q->q_next" is erroneous on a
                   5119:  *     multiprocessor and is disallowed by the DDI/DKI).
                   5120:  *     "putnextctl1 (q, type)" is provided as a multiprocessor-safe
                   5121:  *     equivalent to the common call "putctl1 (q->q_next, type)" which is no
                   5122:  *     longer allowed.
                   5123:  *
                   5124:  *-SEE ALSO:
                   5125:  *     put (), putctl (), putnextctl (), putnextctl1 ()
                   5126:  */
                   5127: 
                   5128: #if    __USE_PROTO__
                   5129: int (putctl1) (queue_t * q, int type, int param)
                   5130: #else
                   5131: int
                   5132: putctl1 __ARGS ((q, type, param))
                   5133: queue_t              * q;
                   5134: int            type;
                   5135: int            param;
                   5136: #endif
                   5137: {
                   5138:        mblk_t        * ctlmsg;
                   5139: 
                   5140:        QUEUE_TRACE (q, "putctl1");
                   5141: 
                   5142:        /*
                   5143:         * We cannot use datamsg () to test the type because datamsg () is
                   5144:         * specified as testing for M_DATA in addition to M_DATA, M_PROTO, and
                   5145:         * M_PCPROTO.
                   5146:         */
                   5147: 
                   5148:        if ((type & (M_PRI - 1)) <= M_PROTO ||
                   5149:            (ctlmsg = MSGB_ALLOC (1, BPRI_HI, KM_NOSLEEP)) == NULL)
                   5150:                return 0;
                   5151: 
                   5152:        ctlmsg->b_datap->db_type = type;
                   5153:        * ctlmsg->b_wptr ++ = (unsigned char) param;
                   5154: 
                   5155:        put (q, ctlmsg);
                   5156: 
                   5157:        return 1;
                   5158: }
                   5159: 
                   5160: 
                   5161: /*
                   5162:  *-STATUS:
                   5163:  *     DDI/DKI
                   5164:  *
                   5165:  *-NAME:
                   5166:  *     putnext         Send a message to the next queue.
                   5167:  *
                   5168:  *-SYNOPSIS:
                   5169:  *     #include <sys/stream.h>
                   5170:  *
                   5171:  *     int putnext (queue_t * q, mblk_t * mp);
                   5172:  *
                   5173:  *-ARGUMENTS:
                   5174:  *     q               Pointer to the queue from which the message "mp" will
                   5175:  *                     be sent.
                   5176:  *
                   5177:  *     mp              Pointer to the message to be passed.
                   5178:  *
                   5179:  *-DESCRIPTION:
                   5180:  *     The putnext () function is used to pass a message to the "put" routine
                   5181:  *     of the next queue ("q->q_next") in the stream.
                   5182:  *
                   5183:  *-RETURN VALUE:
                   5184:  *     Ignored.
                   5185:  *
                   5186:  *-LEVEL:
                   5187:  *     Base or interrupt.
                   5188:  *
                   5189:  *-NOTES:
                   5190:  *     Does not sleep.
                   5191:  *
                   5192:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5193:  *     calling this function.
                   5194:  *
                   5195:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   5196:  *     held across calls to this function.
                   5197:  *
                   5198:  *-SEE ALSO:
                   5199:  *     putnextctl (), putnextctl1 ()
                   5200:  */
                   5201: 
                   5202: #if    __USE_PROTO__
                   5203: int (putnext) (queue_t * q, mblk_t * mp)
                   5204: #else
                   5205: int
                   5206: putnext __ARGS ((q, mp))
                   5207: queue_t              * q;
                   5208: mblk_t       * mp;
                   5209: #endif
                   5210: {
                   5211:        QUEUE_TRACE (q, "putnext");
                   5212: 
                   5213:        QUEUE_PUTNEXT (q, mp);
                   5214: 
                   5215:        return 0;
                   5216: }
                   5217: 
                   5218: 
                   5219: /*
                   5220:  *-STATUS:
                   5221:  *     DDI/DKI
                   5222:  *
                   5223:  *-NAME:
                   5224:  *     putnextctl      Send a control message to a queue.
                   5225:  *
                   5226:  *-SYNOPSIS:
                   5227:  *     #include <sys/stream.h>
                   5228:  *
                   5229:  *     int putnextctl (queue_t * q, int type);
                   5230:  *
                   5231:  *-ARGUMENTS:
                   5232:  *     q               Pointer to the queue from which the message is to be
                   5233:  *                     sent.
                   5234:  *
                   5235:  *     type            Message type (must be control type).
                   5236:  *
                   5237:  *-DESCRIPTION:
                   5238:  *     putnextctl () tests the "type" argument to make sure a data type has
                   5239:  *     been specified, and then attempts to allocate a message block.
                   5240:  *     putnextctl () fails if "type" is M_DATA, M_PROTO, or M_PCPROTO, or
                   5241:  *     if a message block cannot be allocated. If successful, putnextctl ()
                   5242:  *     calls the "put" procedure of the queue pointed to by "q->q_next",
                   5243:  *     passing it the allocated message.
                   5244:  *
                   5245:  *-RETURN VALUE:
                   5246:  *     Upon successful completion, putnextctl () returns 1. If "type" is a
                   5247:  *     data type, or if a message block cannot be allocated, 0 is returned.
                   5248:  *
                   5249:  *-LEVEL:
                   5250:  *     Base or interrupt.
                   5251:  *
                   5252:  *-NOTES:
                   5253:  *     Does not sleep.
                   5254:  *
                   5255:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5256:  *     calling this function.
                   5257:  *
                   5258:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   5259:  *     held across calls to this function.
                   5260:  *
                   5261:  *     The "q" argument to putctl () and putnextctl () may not reference
                   5262:  *     "q_next" (eg, an argument of "q->q_next" is erroneous on a
                   5263:  *     multiprocessor and is disallowed by the DDI/DKI).
                   5264:  *     "putnextctl (q, type)" is provided as a multiprocessor-safe equivalent
                   5265:  *     to the common call "putctl (q->q_next, type)" which is no longer
                   5266:  *     allowed.
                   5267:  *
                   5268:  *-SEE ALSO:
                   5269:  *     put (), putctl (), putctl1 (), putnextctl1 ()
                   5270:  */
                   5271: 
                   5272: #if    __USE_PROTO__
                   5273: int (putnextctl) (queue_t * q, int type)
                   5274: #else
                   5275: int
                   5276: putnextctl __ARGS ((q, type))
                   5277: queue_t              * q;
                   5278: int            type;
                   5279: #endif
                   5280: {
                   5281:        mblk_t        * ctlmsg;
                   5282: 
                   5283:        QUEUE_TRACE (q, "putnextctl");
                   5284: 
                   5285:        /*
                   5286:         * We cannot use datamsg () to test the type because datamsg () is
                   5287:         * specified as testing for M_DATA in addition to M_DATA, M_PROTO, and
                   5288:         * M_PCPROTO.
                   5289:         */
                   5290: 
                   5291:        if ((type & (M_PRI - 1)) <= M_PROTO ||
                   5292:            (ctlmsg = MSGB_ALLOC (0, BPRI_HI, KM_NOSLEEP)) == NULL)
                   5293:                return 0;
                   5294: 
                   5295:        ctlmsg->b_datap->db_type = type;
                   5296: 
                   5297:        QUEUE_PUTNEXT (q, ctlmsg);
                   5298: 
                   5299:        return 1;
                   5300: }
                   5301: 
                   5302: 
                   5303: /*
                   5304:  *-STATUS:
                   5305:  *     DDI/DKI
                   5306:  *
                   5307:  *-NAME:
                   5308:  *     putnextctl1     Send a control message with a one-byte parameter to a
                   5309:  *                     queue.
                   5310:  *
                   5311:  *-SYNOPSIS:
                   5312:  *     #include <sys/stream.h>
                   5313:  *
                   5314:  *     int putctl1 (queue_t * q, int type, int param);
                   5315:  *
                   5316:  *-ARGUMENTS:
                   5317:  *     q               Pointer to the queue from which the message is to be
                   5318:  *                     sent.
                   5319:  *
                   5320:  *     type            Message type (must be control).
                   5321:  *
                   5322:  *     param           One-byte parameter.
                   5323:  *
                   5324:  *-DESCRIPTION:
                   5325:  *     putnextctl1 () tests the "type" argument to make sure a data type has
                   5326:  *     not been specified, and attempts to allocate a message block.
                   5327:  *     putnext ctl1 () fails if "type" is M_DATA, M_PROTO, or M_PCPROTO, or
                   5328:  *     if a message block cannot be allocated. If successful, putctl1 ()
                   5329:  *     calls the "put" routine of the queue pointed to by "q->q_next",
                   5330:  *     passing it the allocated message with the one byte parameter specified
                   5331:  *     by "param".
                   5332:  *
                   5333:  *-RETURN VALUE:
                   5334:  *     Upon successful completion, putnextctl1 () returns 1. If "type" is a
                   5335:  &     data type, or if a message block cannot be allocated, 0 is returned.
                   5336:  *
                   5337:  *-LEVEL:
                   5338:  *     Base or interrupt.
                   5339:  *
                   5340:  *-NOTES:
                   5341:  *     Does not sleep.
                   5342:  *
                   5343:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5344:  *     calling this function.
                   5345:  *
                   5346:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   5347:  *     held across calls to this function.
                   5348:  *
                   5349:  *     The "q" argument to putctl1 () and putnextctl1 () may not reference
                   5350:  *     "q_next" (eg, an argument of "q->q_next" is erroneous on a
                   5351:  *     multiprocessor and is disallowed by the DDI/DKI).
                   5352:  *     "putnextctl1 (q, type)" is provided as a multiprocessor-safe
                   5353:  *     equivalent to the common call "putctl1 (q->q_next, type)" which is no
                   5354:  *     longer allowed.
                   5355:  *
                   5356:  *-SEE ALSO:
                   5357:  *     put (), putctl (), putctl1 (), putnextctl ()
                   5358:  */
                   5359: 
                   5360: #if    __USE_PROTO__
                   5361: int (putnextctl1) (queue_t * q, int type, int param)
                   5362: #else
                   5363: int
                   5364: putnextctl1 __ARGS ((q, type, param))
                   5365: queue_t              * q;
                   5366: int            type;
                   5367: int            param;
                   5368: #endif
                   5369: {
                   5370:        mblk_t        * ctlmsg;
                   5371: 
                   5372:        QUEUE_TRACE (q, "putnextctl1");
                   5373: 
                   5374:        /*
                   5375:         * We cannot use datamsg () to test the type because datamsg () is
                   5376:         * specified as testing for M_DATA in addition to M_DATA, M_PROTO, and
                   5377:         * M_PCPROTO.
                   5378:         */
                   5379: 
                   5380:        if ((type & (M_PRI - 1)) <= M_PROTO ||
                   5381:            (ctlmsg = MSGB_ALLOC (1, BPRI_HI, KM_NOSLEEP)) == NULL)
                   5382:                return 0;
                   5383: 
                   5384:        ctlmsg->b_datap->db_type = type;
                   5385:        * ctlmsg->b_wptr ++ = (unsigned char) param;
                   5386: 
                   5387:        QUEUE_PUTNEXT (q, ctlmsg);
                   5388: 
                   5389:        return 1;
                   5390: }
                   5391: 
                   5392: 
                   5393: /*
                   5394:  *-STATUS:
                   5395:  *     DDI/DKI
                   5396:  *
                   5397:  *-NAME:
                   5398:  *     putq            Put a message to a queue.
                   5399:  *
                   5400:  *-SYNOPSIS:
                   5401:  *     #include <sys/stream.h>
                   5402:  *
                   5403:  *     int putq (queue_t * q, mblk_t  * mp);
                   5404:  *
                   5405:  *-ARGUMENTS:
                   5406:  *     q               Pointer to the queue.
                   5407:  *
                   5408:  *     mp              Pointer to the message.
                   5409:  *
                   5410:  *-DESCRIPTION:
                   5411:  *     putq () is used to put messages on a queue after the "put" routine has
                   5412:  *     finished processing the message. The message is placed after any other
                   5413:  *     messages of the same priority, and flow control parameters are
                   5414:  *     updated. The queue's service routine is scheduled if it has not been
                   5415:  *     disabled by a previous call to noenable ().
                   5416:  *
                   5417:  *-RETURN VALUE:
                   5418:  *     putq () returns 1 on success and 0 on failure.
                   5419:  *
                   5420:  *-LEVEL:
                   5421:  *     Base or interrupt.
                   5422:  *
                   5423:  *-NOTES:
                   5424:  *     Does not sleep.
                   5425:  *
                   5426:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5427:  *     calling this function.
                   5428:  *
                   5429:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   5430:  *     held across calls to this function.
                   5431:  *
                   5432:  *     putq () can fail if there is not enough memory to allocate the
                   5433:  *     accounting data structures used with messages whose priority bands are
                   5434:  *     greater than zero.
                   5435:  *
                   5436:  *-SEE ALSO:
                   5437:  *     getq (), insq (), putbq (), rmvq (), msgb, queue
                   5438:  */
                   5439: 
                   5440: #if    __USE_PROTO__
                   5441: int (putq) (queue_t * q, mblk_t * mp)
                   5442: #else
                   5443: int
                   5444: putq __ARGS ((q, mp))
                   5445: queue_t              * q;
                   5446: mblk_t       * mp;
                   5447: #endif
                   5448: {
                   5449:        pl_t            prev_pl;
                   5450:        qband_t       * qbandp;
                   5451: 
                   5452:        ASSERT (mp != NULL);
                   5453:        ASSERT (mp->b_datap != NULL);
                   5454: 
                   5455:        prev_pl = QFREEZE_TRACE (q, "putq");
                   5456: 
                   5457:        if (IS_PRI_MSG (mp)) {
                   5458:                /*
                   5459:                 * Since putq () is defined as forcing b_band to 0 for high-
                   5460:                 * priority messages, we do the same. In addition, we also
                   5461:                 * always schedule the queue. No flow-control parameters are
                   5462:                 * updated for high-priority messages.
                   5463:                 */
                   5464: 
                   5465:                mp->b_band = 0;
                   5466:                (void) QUEUE_TRYSCHED (q);
                   5467: 
                   5468:                /*
                   5469:                 * We need to flow into the code that finds the correct
                   5470:                 * insertion point for high-priority and band messages.
                   5471:                 */
                   5472:        } else if (qbandp = NULL, mp->b_band > 0 &&
                   5473:                   (qbandp = QUEUE_BAND (q, mp->b_band)) == NULL &&
                   5474:                   (qbandp = QBAND_ALLOC (q, mp->b_band)) == NULL)
                   5475:                return 0;
                   5476:        else if (QUEUE_CHECK_SCHED (q, mp, qbandp)) {
                   5477:                /*
                   5478:                 * Deal with band pointer maintenance now.
                   5479:                 */
                   5480: 
                   5481:                if ((mp->b_next = qbandp->qb_first) != NULL) {
                   5482:                        /*
                   5483:                         * We directly know where we want to put the message.
                   5484:                         */
                   5485: 
                   5486:                        if ((mp->b_prev = mp->b_next->b_prev) == NULL)
                   5487:                                q->q_first = mp;
                   5488:                        else
                   5489:                                mp->b_prev->b_next = mp;
                   5490: 
                   5491:                        mp->b_next->b_prev = mp;
                   5492: 
                   5493:                        qbandp->qb_first = mp;
                   5494: 
                   5495:                        goto alldone;
                   5496:                }
                   5497: 
                   5498:                /*
                   5499:                 * This is the only message in this band. We will need to
                   5500:                 * search for the correct position to queue this message.
                   5501:                 */
                   5502: 
                   5503:                qbandp->qb_last = qbandp->qb_first = mp;
                   5504:        } else {
                   5505:                /*
                   5506:                 * Since we will always be inserting at the end of the queue,
                   5507:                 * we directly know where we will be inserting the new
                   5508:                 * message.
                   5509:                 */
                   5510: 
                   5511:                mp->b_next = NULL;
                   5512: 
                   5513:                if ((mp->b_prev = q->q_last) == NULL)
                   5514:                        q->q_first = mp;
                   5515:                else
                   5516:                        mp->b_prev->b_next = mp;
                   5517: 
                   5518:                q->q_last = mp;
                   5519: 
                   5520:                goto alldone;
                   5521:        }
                   5522: 
                   5523: 
                   5524:        /*
                   5525:         * Since we want to insert after other messages with the same band
                   5526:         * number, we adjust the band down by one. This introduces a special
                   5527:         * case for high-priority messages, which we want to queue before all
                   5528:         * normal messages. Since we define high-priority messages as having
                   5529:         * a band number of 0, subtracting one makes the band value wrap
                   5530:         * around, yielding the desired behaviour.
                   5531:         */
                   5532: 
                   5533:        QUEUE_PLACE_MSG (q, mp, mp->b_band - 1);
                   5534: 
                   5535: alldone:
                   5536:        QUNFREEZE_TRACE (q, prev_pl);
                   5537:        return 1;
                   5538: }
                   5539: 
                   5540: 
                   5541: /*
                   5542:  *-STATUS:
                   5543:  *     DDI/DKI
                   5544:  *
                   5545:  *-NAME:
                   5546:  *     qenable         Schedule a queue's service routine to be run.
                   5547:  *
                   5548:  *-SYNOPSIS:
                   5549:  *     #include <sys/stream.h>
                   5550:  *
                   5551:  *     void qenable (queue_t * q);
                   5552:  *
                   5553:  *-ARGUMENTS:
                   5554:  *     q               Pointer to the queue.
                   5555:  *
                   5556:  *-DESCRIPTION:
                   5557:  *     qenable () puts the queue pointed to by "q" on the linked list of
                   5558:  *     STREAMS routines that are ready to be called by the STREAMS scheduler.
                   5559:  *     qenable () works regardless of whether the service routine has been
                   5560:  *     disabled by a previous call to noenable ().
                   5561:  *
                   5562:  *-RETURN VALUE:
                   5563:  *     None.
                   5564:  *
                   5565:  *-LEVEL:
                   5566:  *     Base or interrupt.
                   5567:  *
                   5568:  *-NOTES:
                   5569:  *     Does not sleep.
                   5570:  *
                   5571:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5572:  *     calling this function.
                   5573:  *
                   5574:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   5575:  *     held across calls to this function.
                   5576:  *
                   5577:  *-SEE ALSO:
                   5578:  *     enableok (), noenable (), queue
                   5579:  */
                   5580: 
                   5581: #if    __USE_PROTO__
                   5582: void (qenable) (queue_t * q)
                   5583: #else
                   5584: void
                   5585: qenable __ARGS ((q))
                   5586: queue_t              * q;
                   5587: #endif
                   5588: {
                   5589:        pl_t            prev_pl;
                   5590: 
                   5591:        prev_pl = QFREEZE_TRACE (q, "qenable");
                   5592: 
                   5593:        (void) QUEUE_TRYSCHED (q);
                   5594: 
                   5595:        QUNFREEZE_TRACE (q, prev_pl);
                   5596: }
                   5597: 
                   5598: 
                   5599: /*
                   5600:  *-STATUS:
                   5601:  *     DDI/DKI
                   5602:  *
                   5603:  *-NAME:
                   5604:  *     qprocsoff       Disable put and service procedures.
                   5605:  *
                   5606:  *-SYNOPSIS:
                   5607:  *     #include <sys/stream.h>
                   5608:  *
                   5609:  *     void qprocsoff (queue_t * rq);
                   5610:  *
                   5611:  *-ARGUMENTS:
                   5612:  *     rq              Pointer to a read queue.
                   5613:  *
                   5614:  *-DESCRIPTION:
                   5615:  *     qprocsoff () disables the "put" and "service" routines of the driver
                   5616:  *     or module whose read queue is pointed to by "rq". When the routines
                   5617:  *     are disabled in a module, messages flow around the module as if it
                   5618:  *     were not present in the stream.
                   5619:  *
                   5620:  *     qprocsoff () must be called by the "close" routine of a driver or
                   5621:  *     module before deallocating any resources on which the driver/module's
                   5622:  *     put and service procedures depend.
                   5623:  *
                   5624:  *     qprocsoff () will remove the queue's service routines from the list of
                   5625:  *     service routines to be run and waits until any concurrent "put" or
                   5626:  &     "service" routines are finished.
                   5627:  *
                   5628:  *-RETURN VALUE:
                   5629:  *     None.
                   5630:  *
                   5631:  *-LEVEL:
                   5632:  *     Base level only.
                   5633:  *
                   5634:  *-NOTES:
                   5635:  *     May sleep.
                   5636:  *
                   5637:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5638:  *     calling this function.
                   5639:  *
                   5640:  *     Driver-defined basic locks and read/write locks may not be held across
                   5641:  *     calls to this function.
                   5642:  *
                   5643:  *     Driver-defined sleep locks may be held across calls to this function.
                   5644:  *
                   5645:  *-SEE ALSO:
                   5646:  *     qprocson ()
                   5647:  */
                   5648: 
                   5649: #if    __USE_PROTO__
                   5650: void (qprocsoff) (queue_t * rq)
                   5651: #else
                   5652: void
                   5653: qprocsoff __ARGS ((rq))
                   5654: queue_t              * rq;
                   5655: #endif
                   5656: {
                   5657:        pl_t            prev_pl;
                   5658:        int             dosleep;
                   5659:        queue_t       * wq;
                   5660: 
                   5661: 
                   5662: try_rprocsoff:
                   5663:        prev_pl = QFREEZE_TRACE (rq, "qprocsoff");
                   5664: 
                   5665:        rq->q_flag |= QPROCSOFF;
                   5666:        if ((dosleep = rq->q_active > 0) != 0)
                   5667:                (void) LOCK (str_mem->sm_proc_lock, plstr);
                   5668: 
                   5669:        QUNFREEZE_TRACE (rq, prev_pl);
                   5670: 
                   5671:        if (dosleep) {
                   5672:                SV_WAIT (str_mem->sm_proc_sv, prilo, str_mem->sm_proc_lock);
                   5673: 
                   5674:                goto try_rprocsoff;
                   5675:        }
                   5676: 
                   5677:        /*
                   5678:         * Now do the same for the write side.
                   5679:         */
                   5680: 
                   5681:        ASSERT ((rq->q_flag & QREADR) != 0);
                   5682: 
                   5683:        wq = W (rq);
                   5684: 
                   5685: try_wprocsoff:
                   5686:        prev_pl = QFREEZE_TRACE (wq, "qprocsoff");
                   5687: 
                   5688:        wq->q_flag |= QPROCSOFF;
                   5689:        if ((dosleep = wq->q_active > 0) != 0)
                   5690:                (void) LOCK (str_mem->sm_proc_lock, plstr);
                   5691: 
                   5692: 
                   5693:        QUNFREEZE_TRACE (wq, prev_pl);
                   5694: 
                   5695:        if (dosleep) {
                   5696:                SV_WAIT (str_mem->sm_proc_sv, prilo, str_mem->sm_proc_lock);
                   5697: 
                   5698:                goto try_wprocsoff;
                   5699:        }
                   5700: }
                   5701: 
                   5702: 
                   5703: /*
                   5704:  *-STATUS:
                   5705:  *     DDI/DKI
                   5706:  *
                   5707:  *-NAME:
                   5708:  *     qprocson        Enable put and service routines.
                   5709:  *
                   5710:  *-SYNOPSIS:
                   5711:  *     #include <sys/stream.h>
                   5712:  *
                   5713:  *     void qprocson (queue_t * rq);
                   5714:  *
                   5715:  *-ARGUMENTS:
                   5716:  *     rq              Pointer to a read queue.
                   5717:  *
                   5718:  *-DESCRIPTION:
                   5719:  *     qprocson () enables the "put" and "service" routines of the driver or
                   5720:  *     module whose read queue is pointed to by "rq". Prior to the call to
                   5721:  *     qprocson (), the put and service routines of a newly pushed module or
                   5722:  *     driver are disabled. For the module, messages flow around it as if it
                   5723:  *     were not present in the stream.
                   5724:  *
                   5725:  *     qprocson () must be called by the first open of a module or driver
                   5726:  *     after allocation and initialization of any resources on which the put
                   5727:  *     and service routines depend.
                   5728:  *
                   5729:  *-RETURN VALUE:
                   5730:  *     None.
                   5731:  *
                   5732:  *-LEVEL:
                   5733:  *     Base level only.
                   5734:  *
                   5735:  *-NOTES:
                   5736:  *     May sleep.
                   5737:  *
                   5738:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5739:  *     calling this function.
                   5740:  *
                   5741:  *     Driver-defined basic locks and read/write locks may not be held across
                   5742:  *     calls to this function.
                   5743:  *
                   5744:  *     Driver-defined sleep locks may be held across calls to this function.
                   5745:  *
                   5746:  *-SEE ALSO:
                   5747:  *     qprocsoff ()
                   5748:  */
                   5749: 
                   5750: #if    __USE_PROTO__
                   5751: void (qprocson) (queue_t * rq)
                   5752: #else
                   5753: void
                   5754: qprocson __ARGS ((rq))
                   5755: queue_t              * rq;
                   5756: #endif
                   5757: {
                   5758:        pl_t            prev_pl;
                   5759:        queue_t       * wq;
                   5760: 
                   5761:        /*
                   5762:         * Actually, this implementation of qprocsoff () busy-waits rather
                   5763:         * than sleeping, but don't count on that.
                   5764:         */
                   5765: 
                   5766:        prev_pl = QFREEZE_TRACE (rq, "qprocson");
                   5767: 
                   5768:        ASSERT ((rq->q_flag & QREADR) != 0);
                   5769: 
                   5770:        wq = W (rq);
                   5771: 
                   5772:        (void) QFREEZE_TRACE (wq, "qprocson");
                   5773: 
                   5774:        rq->q_flag &= ~ QPROCSOFF;
                   5775:        wq->q_flag &= ~ QPROCSOFF;
                   5776: 
                   5777:        ASSERT (rq->q_active == 0 && wq->q_active == 0);
                   5778: 
                   5779: 
                   5780:        /*
                   5781:         * If there are any messages on the queues, the service procedures
                   5782:         * should be run. If the QWANTW flag is set, we'll back-enable the
                   5783:         * queues.
                   5784:         */
                   5785: 
                   5786:        if (rq->q_first != NULL && (rq->q_flag & QNOENB) != 0)
                   5787:                (void) QUEUE_TRYSCHED (rq);
                   5788: 
                   5789:        if (wq->q_first != NULL && (wq->q_flag & QNOENB) != 0)
                   5790:                (void) QUEUE_TRYSCHED (wq);
                   5791: 
                   5792:        if ((rq->q_flag & QWANTW) != 0) {
                   5793: 
                   5794:                rq->q_flag &= ~ QWANTW;
                   5795:                QUEUE_BACKENAB (rq);
                   5796:        }
                   5797: 
                   5798:        if ((wq->q_flag & QWANTW) != 0) {
                   5799: 
                   5800:                wq->q_flag &= ~ QWANTW;
                   5801:                QUEUE_BACKENAB (wq);
                   5802:        }
                   5803: 
                   5804:        QUNFREEZE_TRACE (wq, plstr);
                   5805:        QUNFREEZE_TRACE (rq, prev_pl);
                   5806: }
                   5807: 
                   5808: 
                   5809: /*
                   5810:  *-STATUS:
                   5811:  *     DDI/DKI
                   5812:  *
                   5813:  *-NAME:
                   5814:  *     qreply          Send a message in the opposite direction on a stream.
                   5815:  *
                   5816:  *-SYNOPSIS:
                   5817:  *     #include <sys/stream.h>
                   5818:  *
                   5819:  *     void qreply (queue_t * q, mblk_t * mp);
                   5820:  *
                   5821:  *-ARGUMENTS:
                   5822:  *     q               Pointer to the queue from which the message is being
                   5823:  *                     sent.
                   5824:  *
                   5825:  *     mp              Pointer to the message to be sent in the opposite
                   5826:  *                     direction.
                   5827:  *
                   5828:  *-DESCRIPTION:
                   5829:  *     qreply () sends a message in the opposite direction from that which
                   5830:  *     "q" is pointing. It calls the OTHERQ () function to find "q"'s
                   5831:  *     partner, and passes the message by calling the "put" routine of the
                   5832:  *     next queue in the stream after "q"'s partner.
                   5833:  *
                   5834:  *-RETURN VALUE:
                   5835:  *     None.
                   5836:  *
                   5837:  *-LEVEL:
                   5838:  *     Base or interrupt.
                   5839:  *
                   5840:  *-NOTES:
                   5841:  *     Does not sleep.
                   5842:  *
                   5843:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5844:  *     calling this function.
                   5845:  *
                   5846:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   5847:  *     held across calls to this function.
                   5848:  *
                   5849:  *-SEE ALSO:
                   5850:  */
                   5851: 
                   5852: #if    __USE_PROTO__
                   5853: void (qreply) (queue_t * q, mblk_t * mp)
                   5854: #else
                   5855: void
                   5856: qreply __ARGS ((q, mp))
                   5857: queue_t              * q;
                   5858: mblk_t       * mp;
                   5859: #endif
                   5860: {
                   5861:        /*
                   5862:         * The DDI/DKI says the caller cannot have the stream frozen, but we
                   5863:         * don't actually need to do anything that would freeze the stream.
                   5864:         * The proscription arises because we need to freeze the other queue
                   5865:         * temporarily, and for one context to freeze both sides of a stream
                   5866:         * may induce deadlock.
                   5867:         */
                   5868: 
                   5869: #ifndef        NDEBUG
                   5870:        pl_t            prev_pl;
                   5871: 
                   5872:        prev_pl = QFREEZE_TRACE (q, "qreply");
                   5873:        QUNFREEZE_TRACE (q, prev_pl);
                   5874: #endif
                   5875: 
                   5876:        ASSERT (mp != NULL);
                   5877:        ASSERT (mp->b_datap != NULL);
                   5878: 
                   5879:        q = OTHERQ (q);
                   5880: 
                   5881:        QUEUE_PUTNEXT (q, mp);
                   5882: }
                   5883: 
                   5884: 
                   5885: /*
                   5886:  *-STATUS:
                   5887:  *     DDI/DKI
                   5888:  *
                   5889:  *-NAME:
                   5890:  *     qsize           Find the number of messages on a queue.
                   5891:  *
                   5892:  *-SYNOPSIS:
                   5893:  *     #include <sys/stream.h>
                   5894:  *
                   5895:  *     int qsize (queue_t * q);
                   5896:  *
                   5897:  *-ARGUMENTS:
                   5898:  *     q               Pointer to the queue to be evaluated.
                   5899:  *
                   5900:  *-DESCRIPTION:
                   5901:  *     qsize () evaluates the queue pointed to by "q" and returns the number
                   5902:  *     of messages it contains.
                   5903:  *
                   5904:  *-RETURN VALUE:
                   5905:  *     If there are no messages on the queue, "qsize" returns 0. Otherwise,
                   5906:  *     it returns the number of messages on the queue.
                   5907:  *
                   5908:  *-LEVEL:
                   5909:  *     Base or interrupt.
                   5910:  *
                   5911:  *-NOTES:
                   5912:  *     Does not sleep.
                   5913:  *
                   5914:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   5915:  *     calling this function.
                   5916:  *
                   5917:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   5918:  *     held across calls to this function.
                   5919:  *
                   5920:  *-SEE ALSO:
                   5921:  *     msgb, queue
                   5922:  */
                   5923: 
                   5924: #if    __USE_PROTO__
                   5925: int (qsize) (queue_t * q)
                   5926: #else
                   5927: int
                   5928: qsize __ARGS ((q))
                   5929: queue_t              * q;
                   5930: #endif
                   5931: {
                   5932:        pl_t            prev_pl;
                   5933:        mblk_t        * scan;
                   5934:        int             count = 0;
                   5935: 
                   5936:        prev_pl = QFREEZE_TRACE (q, "qsize");
                   5937: 
                   5938:        for (scan = q->q_first ; scan != NULL ; scan = scan->b_next)
                   5939:                count ++;
                   5940: 
                   5941:        QUNFREEZE_TRACE (q, prev_pl);
                   5942: 
                   5943:        return count;
                   5944: }
                   5945: 
                   5946: 
                   5947: /*
                   5948:  *-STATUS:
                   5949:  *     DDI/DKI
                   5950:  *
                   5951:  *-NAME:
                   5952:  *     RD              Get a pointer to the read queue.
                   5953:  *
                   5954:  *-SYNOPSIS:
                   5955:  *     #include <sys/stream.h>
                   5956:  *
                   5957:  *     queue_t * RD (queue_t * q);
                   5958:  *
                   5959:  *-ARGUMENTS:
                   5960:  *     q               Pointer to the queue whose read queue is to be
                   5961:  *                     returned.
                   5962:  *
                   5963:  *-DESCRIPTION:
                   5964:  *     The RD () function accepts a queue pointer as an argument and returns
                   5965:  *     a pointer to the read queue of the same module or driver.
                   5966:  *
                   5967:  *-RETURN VALUE:
                   5968:  *     The pointer to the read queue.
                   5969:  *
                   5970:  *-LEVEL:
                   5971:  *     Base or interrupt.
                   5972:  *
                   5973:  *-NOTES:
                   5974:  *     Does not sleep.
                   5975:  *
                   5976:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   5977:  *     held across calls to this function.
                   5978:  *
                   5979:  *-SEE ALSO:
                   5980:  *     OTHERQ (), WR ()
                   5981:  */
                   5982: 
                   5983: #if    __USE_PROTO__
                   5984: queue_t * (RD) (queue_t * q)
                   5985: #else
                   5986: queue_t *
                   5987: RD __ARGS ((q))
                   5988: queue_t              * q;
                   5989: #endif
                   5990: {
                   5991:        QUEUE_TRACE (q, "RD");
                   5992: 
                   5993:        return RD (q);
                   5994: }
                   5995: 
                   5996: 
                   5997: /*
                   5998:  *-STATUS:
                   5999:  *     DDI/DKI
                   6000:  *
                   6001:  *-NAME:
                   6002:  *     rmvb            Remove a message block from a message.
                   6003:  *
                   6004:  *-SYNOPSIS:
                   6005:  *     #include <sys/stream.h>
                   6006:  *
                   6007:  *     mblk_t * rmvb (mblk_t * mp, mblk_t * bp);
                   6008:  *
                   6009:  *-ARGUMENTS:
                   6010:  *     mp              Message from which a message block is to be removed.
                   6011:  *
                   6012:  *     bp              Message block to be removed.
                   6013:  *
                   6014:  *-DESCRIPTION:
                   6015:  *     rmvb () removes a message block ("bp") from a message ("mp"), and
                   6016:  *     returns a pointer to the altered message. The message block is not
                   6017:  *     freed, merely removed from the message. It is the caller's
                   6018:  *     responsibility to free the message block.
                   6019:  *
                   6020:  *-RETURN VALUE:
                   6021:  *     If successful, a pointer to the message (minus the removed block) is
                   6022:  *     returned. If "bp" was the only block in the message before rmvb ()
                   6023:  *     was called, NULL is returned. If the designated message block ("bp")
                   6024:  *     was not in the message, -1 is returned.
                   6025:  *
                   6026:  *-LEVEL:
                   6027:  *     Base or interrupt.
                   6028:  *
                   6029:  *-NOTES:
                   6030:  *     Does not sleep.
                   6031:  *
                   6032:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   6033:  *     held across calls to this function.
                   6034:  */
                   6035: 
                   6036: #if    __USE_PROTO__
                   6037: mblk_t * (rmvb) (mblk_t * mp, mblk_t * bp)
                   6038: #else
                   6039: mblk_t *
                   6040: rmvb __ARGS ((mp, bp))
                   6041: mblk_t       * mp;
                   6042: mblk_t       * bp;
                   6043: #endif
                   6044: {
                   6045:        mblk_t        * scan;
                   6046: 
                   6047:        ASSERT (mp != NULL);
                   6048:        ASSERT (bp != NULL);
                   6049: 
                   6050:        if (mp == bp)
                   6051:                return mp->b_cont;
                   6052: 
                   6053:        for (scan = mp ; scan != NULL ; scan = scan->b_cont)
                   6054:                if (scan->b_cont == bp) {
                   6055: 
                   6056:                        scan->b_cont = bp->b_cont;
                   6057:                        return mp;
                   6058:                }
                   6059: 
                   6060:        return (mblk_t *) -1;
                   6061: }
                   6062: 
                   6063: 
                   6064: /*
                   6065:  *-STATUS:
                   6066:  *     DDI/DKI
                   6067:  *
                   6068:  *-NAME:
                   6069:  *     rmvq            Remove a message from a queue.
                   6070:  *
                   6071:  *-SYNOPSIS:
                   6072:  *     #include <sys/stream.h>
                   6073:  *
                   6074:  *     void rmvq (queue_t * q, mblk_t * mp);
                   6075:  *
                   6076:  *-ARGUMENTS:
                   6077:  *     q               Pointer to the queue containing the message to be
                   6078:  *                     removed.
                   6079:  *
                   6080:  *     mp              Pointer to the message to be removed.
                   6081:  *
                   6082:  *-DESCRIPTION:
                   6083:  *     rmvq () removes a message from a queue. A message can be removed from
                   6084:  *     anywhere in a queue. To prevent modules and drivers from having to
                   6085:  *     deal with the internals of message linkage on a queue, either rmvq ()
                   6086:  *     or getq () should be used to remove a message from a queue.
                   6087:  *
                   6088:  *-RETURN VALUE:
                   6089:  *     None.
                   6090:  *
                   6091:  *-LEVEL:
                   6092:  *     Base or interrupt.
                   6093:  *
                   6094:  *-NOTES:
                   6095:  *     Does not sleep.
                   6096:  *
                   6097:  *     The caller must have the stream frozen [see freezestr ()] when calling
                   6098:  *     this function.
                   6099:  *
                   6100:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   6101:  *     held across calls to this function.
                   6102:  *
                   6103:  *     "mp" must point to an existing message in the queue pointed to by "q",
                   6104:  *     or a system panic will occur.
                   6105:  *
                   6106:  *-SEE ALSO:
                   6107:  *     freezestr (), getq (), insq (), unfreezestr ().
                   6108:  */
                   6109: 
                   6110: #if    __USE_PROTO__
                   6111: void (rmvq) (queue_t * q, mblk_t * mp)
                   6112: #else
                   6113: void
                   6114: rmvq __ARGS ((q, mp))
                   6115: queue_t              * q;
                   6116: mblk_t       * mp;
                   6117: #endif
                   6118: {
                   6119:        ASSERT (mp != NULL);
                   6120: 
                   6121:        QFROZEN_TRACE (q, "rmvq");
                   6122: 
                   6123:        /*
                   6124:         * First, simply dequeue the message based on mp's "b_next" and
                   6125:         * "b_prev" members.
                   6126:         */
                   6127: 
                   6128:        if (mp->b_next == NULL) {
                   6129: 
                   6130:                ASSERT (q->q_last == mp);
                   6131:                if ((q->q_last = mp->b_prev) == NULL)
                   6132:                        QUEUE_DRAINED (q);
                   6133:        } else
                   6134:                mp->b_next->b_prev = mp->b_prev;
                   6135: 
                   6136:        if (mp->b_prev == NULL) {
                   6137: 
                   6138:                ASSERT (q->q_first == mp);
                   6139:                q->q_first = mp->b_next;
                   6140: 
                   6141:                /*
                   6142:                 * Since we are dequeueing a message from the front of the
                   6143:                 * queue, record the message band.
                   6144:                 */
                   6145: 
                   6146:                q->q_lastband = mp->b_band;
                   6147:        } else
                   6148:                mp->b_prev->b_next = mp->b_next;
                   6149: 
                   6150:        /*
                   6151:         * Now we adjust the flow-control parameters and band information.
                   6152:         */
                   6153: 
                   6154:        if (! IS_PRI_MSG (mp)) {
                   6155:                ulong_t         msgsize = MSG_SIZE (mp);
                   6156: 
                   6157:                if (mp->b_band > 0) {
                   6158:                        qband_t       * qbandp = QUEUE_BAND (q, mp->b_band);
                   6159: 
                   6160:                        ASSERT (qbandp->qb_first == mp);
                   6161: 
                   6162:                        QBAND_DEQUEUE (qbandp, mp);
                   6163: 
                   6164:                        QBAND_REDUCE (q, qbandp, msgsize);
                   6165:                } else
                   6166:                        QUEUE_REDUCE (q, msgsize);
                   6167:        }
                   6168: }
                   6169: 
                   6170: 
                   6171: /*
                   6172:  *-STATUS:
                   6173:  *     DDI/DKI
                   6174:  *
                   6175:  *-NAME:
                   6176:  *     SAMESTR         Test if next queue is same type.
                   6177:  *
                   6178:  *-SYNOPSIS:
                   6179:  *     #include <sys/stream.h>
                   6180:  *
                   6181:  *     int SAMESTR (queue_t * q);
                   6182:  *
                   6183:  *-ARGUMENTS:
                   6184:  *     q               Pointer to the queue.
                   6185:  *
                   6186:  *-DESCRIPTION:
                   6187:  *     The SAMESTR () function is used to see if the next queue in a stream
                   6188:  *     (if it exists) is the same type as the current queue (that is, both
                   6189:  *     are read queues or both are write queues). This can be used to
                   6190:  *     determine the point in a STREAMS-based pipe where a read queue is
                   6191:  *     linked to a write queue.
                   6192:  *
                   6193:  *-RETURN VALUE:
                   6194:  *     SAMESTR () returns 1 if the next queue is the same type as the current
                   6195:  *     queue. It returns 0 if the next queue does not exist or if it is not
                   6196:  *     the same type.
                   6197:  *
                   6198:  *-LEVEL:
                   6199:  *     Base or interrupt.
                   6200:  *
                   6201:  *-NOTES:
                   6202:  *     Does not sleep.
                   6203:  *
                   6204:  *     The caller cannot have the stream frozen [see freezestr ()] when
                   6205:  *     calling this function.
                   6206:  *
                   6207:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   6208:  *     held across calls to this function.
                   6209:  *
                   6210:  *     The argument "q" may not reference "q_next" (for example, an argument
                   6211:  *     of "q->q_next" is erroneous on a multiprocessor and is disallowed by
                   6212:  *     the DDI/DKI).
                   6213:  *
                   6214:  *-SEE ALSO:
                   6215:  *     OTHERQ ()
                   6216:  */
                   6217: 
                   6218: #if    __USE_PROTO__
                   6219: int (SAMESTR) (queue_t * q)
                   6220: #else
                   6221: int
                   6222: SAMESTR __ARGS ((q))
                   6223: queue_t              * q;
                   6224: #endif
                   6225: {
                   6226:        int             retval;
                   6227:        pl_t            prev_pl;
                   6228: 
                   6229:        prev_pl = QFREEZE_TRACE (q, "SAMESTR");
                   6230: 
                   6231:        retval = q->q_next == NULL ? 0 :
                   6232:                   (q->q_next->q_flag & QREADR) == (q->q_flag & QREADR);
                   6233: 
                   6234:        QUNFREEZE_TRACE (q, prev_pl);
                   6235: 
                   6236:        return retval;
                   6237: }
                   6238: 
                   6239: 
                   6240: /*
                   6241:  *-STATUS:
                   6242:  *     DDI/DKI
                   6243:  *
                   6244:  *-NAME:
                   6245:  *     strlog          Submit messages to the log driver.
                   6246:  *
                   6247:  *-SYNOPSIS:
                   6248:  *     #include <sys/types.h>
                   6249:  *     #include <sys/stream.h>
                   6250:  *     #include <sys/strlog.h>
                   6251:  *     #include <sys/log.h>    
                   6252:  *
                   6253:  *     int strlog (short mid, short sid, char level, uchar_t flags,
                   6254:  *                 char * fmt, ...);
                   6255:  *
                   6256:  *-ARGUMENTS:
                   6257:  *     mid             Identification number of the module or driver
                   6258:  *                     submitting the message.
                   6259:  *
                   6260:  *     sid             Identification number for a particular minor device.
                   6261:  *
                   6262:  *     flags           Bitmask of flags indicating message purpose. Valid
                   6263:  *                     flags are:
                   6264:  *                       SL_ERROR      Message is for error logger.
                   6265:  *                       SL_TRACE      Message is for tracing.
                   6266:  *                       SL_CONSOLE    Message is for console logger.
                   6267:  *                       SL_NOTIFY     If SL_ERROR is also set, mail copy of
                   6268:  *                                     message to system administrator.
                   6269:  *                       SL_FATAL      Modifier indicating error is fatal.
                   6270:  *                       SL_WARN       Modifier indicating error is a
                   6271:  *                                     warning.
                   6272:  *                       SL_NOTE       Modifier indicating error is a notice.
                   6273:  *
                   6274:  *     fmt             printf () style format string. %s, %e, %g and %G
                   6275:  *                     formats are not allowed.
                   6276:  *
                   6277:  *     ...             Zero or more arguments to printf () (maximum of
                   6278:  *                     NLOGARGS, currently three).
                   6279:  *
                   6280:  *-DESCRIPTION:
                   6281:  *     strlog () submits formatted messages to the "log" driver. The messages
                   6282:  *     can be retrieved with the getmsg () system call. The "flags" argument
                   6283:  *     specifies the type of the message and where it is to be sent.
                   6284:  *
                   6285:  *-RETURN VALUE:
                   6286:  *     strlog () returns 0 if the message is not seen by all the readers, 1
                   6287:  *     otherwise.
                   6288:  *
                   6289:  *-LEVEL:
                   6290:  *     Base or interrupt.
                   6291:  *
                   6292:  *-NOTES:
                   6293:  *     Does not sleep.
                   6294:  *
                   6295:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   6296:  *     held across calls to this function.
                   6297:  *
                   6298:  *-SEE ALSO:
                   6299:  *     log (7) in the "Programmer's Guide: STREAMS"
                   6300:  */
                   6301: 
                   6302: #if    __USE_PROTO__
                   6303: int (strlog) (short mid, short sid, char level, ushort_t flags, char * fmt,
                   6304:              ...)
                   6305: #else
                   6306: int
                   6307: strlog __ARGS ((mid, sid, level, flags, fmt))
                   6308: short          mid;
                   6309: short          sid;
                   6310: char           level;
                   6311: ushort_t       flags;
                   6312: char         * fmt;
                   6313: #endif
                   6314: {
                   6315:        mblk_t        * data;
                   6316:        ulong_t         err_seq, trc_seq, con_seq;
                   6317:        mblk_t        * errmsg, * trcmsg, * conmsg;
                   6318:        int             failures;
                   6319:        int             copies;
                   6320:        int             pri;
                   6321: 
                   6322: # define       SL_ALL  (SL_ERROR | SL_TRACE | SL_CONSOLE | SL_NOTIFY |\
                   6323:                         SL_FATAL | SL_WARN | SL_NOTE)
                   6324: 
                   6325:        ASSERT ((flags & SL_ALL) != 0);
                   6326:        ASSERT ((flags & ~ SL_ALL) == 0);
                   6327:        ASSERT (fmt != NULL);
                   6328: 
                   6329:        /*
                   6330:         * The first thing we do is assign a sequence number to this log item
                   6331:         * so that we can correctly detect when log items have been discarded
                   6332:         * due to lack of available resources. In addition, there are several
                   6333:         * sequence-number spaces available, depending on the destination of
                   6334:         * the log message. We acquire numbers from all the spaces now, and
                   6335:         * write them into the actual log messages later.
                   6336:         */
                   6337: 
                   6338:        {
                   6339:                pl_t            prev_pl;
                   6340:                int             temp;
                   6341: 
                   6342:                prev_pl = LOCK (str_mem->sm_seq_lock, plstr);
                   6343: 
                   6344:                err_seq = trc_seq = con_seq = 0;        /* paranoia */
                   6345: 
                   6346:                if ((flags & SL_ERROR) != 0)
                   6347:                        err_seq = str_mem->sm_err_seq ++;
                   6348:                if ((flags & SL_TRACE) != 0)
                   6349:                        trc_seq = str_mem->sm_trc_seq ++;
                   6350:                if ((flags & SL_CONSOLE) != 0)
                   6351:                        con_seq = str_mem->sm_con_seq ++;
                   6352: 
                   6353:                temp = str_mem->sm_log_rq == NULL;
                   6354: 
                   6355:                UNLOCK (str_mem->sm_seq_lock, prev_pl);
                   6356: 
                   6357: 
                   6358:                /*
                   6359:                 * If the log driver isn't installed yet, don't bother with
                   6360:                 * the rest of this routine.
                   6361:                 */
                   6362: 
                   6363:                if (temp)
                   6364:                        return 0;
                   6365:        }
                   6366: 
                   6367:        /*
                   6368:         * While the documentation for this function doesn't spell it out,
                   6369:         * the log (7) driver traffics in error, trace and console messages,
                   6370:         * with the others being variations on that theme.
                   6371:         *
                   6372:         * Somehow the "flags" have to be mapped into a priority/facility code
                   6373:         * according to some rules that are alluded to in the log (7) manual
                   6374:         * pages.
                   6375:         */
                   6376: 
                   6377:        {
                   6378:                size_t          size;
                   6379:                va_list         args;
                   6380:                uchar_t       * dest;
                   6381:                int             temp;
                   6382: 
                   6383:                if ((flags & (SL_ERROR | SL_FATAL)) != 0)
                   6384:                        pri = BPRI_HI;
                   6385:                else if ((flags & SL_WARN) != 0)
                   6386:                        pri = BPRI_MED;
                   6387:                else
                   6388:                        pri = BPRI_LO;
                   6389: 
                   6390: 
                   6391:                /*
                   6392:                 * The data portion of a STREAMS logger message contains the
                   6393:                 * unexpanded text of the "fmt" string plus NLOGARGS worth of
                   6394:                 * data containing any extra arguments packed after the string
                   6395:                 * aligned to the next word address.
                   6396:                 *
                   6397:                 * We'll also need at least one control message section, which
                   6398:                 * we can copy as necessary later on.
                   6399:                 */
                   6400:                /*
                   6401:                 * ALIGNMENT-DEPENDENT CODE.
                   6402:                 */
                   6403:                size = ((strlen (fmt) + 4) & ~ (sizeof (int) - 1)) +
                   6404:                        NLOGARGS * sizeof (ulong_t);
                   6405: 
                   6406:                if ((data = MSGB_ALLOC (size, pri, KM_NOSLEEP)) == NULL) {
                   6407:                        /*
                   6408:                         * Return a failure indication. This is not a major
                   6409:                         * problem, as the gaps in the sequence space tell a
                   6410:                         * story...
                   6411:                         */
                   6412: 
                   6413:                        return 0;
                   6414:                }
                   6415: 
                   6416:                /*
                   6417:                 * Copy the format string and the argument data to the log
                   6418:                 * buffer.
                   6419:                 */
                   6420: 
                   6421:                dest = data->b_rptr;
                   6422:                while ((* dest ++ = * (uchar_t *) fmt ++) != 0)
                   6423:                        ;
                   6424:                dest += (sizeof (int) - 1) - (((unsigned long) dest - 1) &
                   6425:                                              (sizeof (int) - 1));
                   6426: 
                   6427:                va_start (args, fmt);
                   6428:                for (temp = 0 ; temp < NLOGARGS ; temp ++) {
                   6429:                        * (ulong_t *) dest = va_arg (args, ulong_t);
                   6430:                        dest += sizeof (ulong_t);
                   6431:                }
                   6432:                va_end (args);
                   6433: 
                   6434:                data->b_wptr += size;
                   6435: 
                   6436:                ASSERT (data->b_wptr == dest);
                   6437:        }
                   6438: 
                   6439: 
                   6440:        /*
                   6441:         * Now send the log request to the read side of the log driver. This
                   6442:         * is how we distinguish kernel log requests from user log requests,
                   6443:         * since the user requests will arrive on the write side as usual.
                   6444:         *
                   6445:         * Since the various destinations for log messages expect to see
                   6446:         * messages with sequence numbers tailored to them, we create
                   6447:         * additional copies of the log message as needed. For this to work,
                   6448:         * we work out the copies first, and then send them.
                   6449:         *
                   6450:         * This would be a lot easier if C had nested functions as standard.
                   6451:         * Sadly, only GNU does this now.
                   6452:         */
                   6453: 
                   6454:        failures = 0;
                   6455:        copies = 0;
                   6456: 
                   6457:        errmsg = STRLOG_MAKE (mid, sid, level, flags, err_seq, SL_ERROR,
                   6458:                              & copies, & failures, data);
                   6459: 
                   6460:        trcmsg = STRLOG_MAKE (mid, sid, level, flags, trc_seq, SL_TRACE,
                   6461:                              & copies, & failures, data);
                   6462: 
                   6463:        conmsg = STRLOG_MAKE (mid, sid, level, flags, con_seq, SL_CONSOLE,
                   6464:                              & copies, & failures, data);
                   6465: 
                   6466:        if (errmsg != NULL)
                   6467:                put (str_mem->sm_log_rq, errmsg);
                   6468:        if (trcmsg != NULL)
                   6469:                put (str_mem->sm_log_rq, trcmsg);
                   6470:        if (conmsg != NULL)
                   6471:                put (str_mem->sm_log_rq, conmsg);
                   6472: 
                   6473:        if (copies == 0)
                   6474:                freemsg (data);
                   6475: 
                   6476:        return failures == 0;
                   6477: }
                   6478: 
                   6479: 
                   6480: /*
                   6481:  *-STATUS:
                   6482:  *     DDI/DKI
                   6483:  *
                   6484:  *-NAME:
                   6485:  *     strqget         Get information about a queue or band of the queue.
                   6486:  *
                   6487:  *-SYNOPSIS:
                   6488:  *     #include <sys/stream.h>
                   6489:  *
                   6490:  *     int strqget (queue_t * q, qfields_t what, uchar_t pri, long * valp);
                   6491:  *
                   6492:  *-ARGUMENTS:
                   6493:  *     q               Pointer to the queue.
                   6494:  *
                   6495:  *     what            The field of the queeu about which to return
                   6496:  *                     information. Valid values are:
                   6497:  *
                   6498:  *                     QHIWAT  High water mark of the specified priority
                   6499:  *                             band.
                   6500:  *
                   6501:  *                     QLOWAT  Low water mark of the specified priority band.
                   6502:  *
                   6503:  *                     QMAXPSZ Maximum packet size of the specified priority
                   6504:  *                             band.
                   6505:  *
                   6506:  *                     QMINPSZ Minimum packet size of the specified priority
                   6507:  *                             band.
                   6508:  *
                   6509:  *                     QCOUNT  Number of bytes of data in messages in the
                   6510:  *                             specified priority band.
                   6511:  *
                   6512:  *                     QFIRST  Pointer to the first message in the specified
                   6513:  *                             priority band.
                   6514:  *
                   6515:  *                     QLAST   Pointer to the last message in the specified
                   6516:  *                             priority band.
                   6517:  *
                   6518:  *                     QFLAG   Flags for the specified priority band.
                   6519:  *
                   6520:  *     pri             Priority band of the queue about which to obtain
                   6521:  *                     information.
                   6522:  *
                   6523:  *     valp            Pointer to the memory locatation where the value is
                   6524:  *                     to be stored.
                   6525:  *
                   6526:  *-DESCRIPTION:
                   6527:  *     strqget () gives drivers and modules a way to get information about
                   6528:  *     a queue or a particular priority band of a queue without directly
                   6529:  *     accessing STREAMS data structures.
                   6530:  *
                   6531:  *-RETURN VALUE:
                   6532:  *     On success, 0 is returns. An error number is returned on failure. The
                   6533:  *     actual value of the requested field is returned through the reference
                   6534:  *     parameter "valp".
                   6535:  *
                   6536:  *-LEVEL:
                   6537:  *     Base or interrupt.
                   6538:  *
                   6539:  *-NOTES:
                   6540:  *     Does not sleep.
                   6541:  *
                   6542:  *     The caller must have the stream frozen [see freezestr ()] when calling
                   6543:  *     this function.
                   6544:  *
                   6545:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   6546:  *     held across calls to this function.
                   6547:  *
                   6548:  *-SEE ALSO:
                   6549:  *     freezestr (), strqset (), unfreezestr (), queue
                   6550:  */
                   6551: 
                   6552: #if    __USE_PROTO__
                   6553: int (strqget) (queue_t * q, qfields_t what, uchar_t pri, long * valp)
                   6554: #else
                   6555: int
                   6556: strqget __ARGS ((q, what, pri, valp))
                   6557: queue_t              * q;
                   6558: qfields_t      what;
                   6559: uchar_t                pri;
                   6560: long         * valp;
                   6561: #endif
                   6562: {
                   6563:        QFROZEN_TRACE (q, "strqget");
                   6564: 
                   6565:        if (pri > 0)
                   6566:                switch (what) {
                   6567: 
                   6568:                case QHIWAT:
                   6569:                        * valp = q->q_hiwat;
                   6570:                        break;
                   6571: 
                   6572:                case QLOWAT:
                   6573:                        * valp = q->q_lowat;
                   6574:                        break;
                   6575: 
                   6576:                case QMAXPSZ:
                   6577:                        * valp = q->q_maxpsz;
                   6578:                        break;
                   6579: 
                   6580:                case QMINPSZ:
                   6581:                        * valp = q->q_minpsz;
                   6582:                        break;
                   6583: 
                   6584:                case QCOUNT:
                   6585:                        * valp = q->q_count;
                   6586:                        break;
                   6587: 
                   6588:                case QFIRST:
                   6589:                        * valp = (long) q->q_first;
                   6590:                        break;
                   6591: 
                   6592:                case QLAST:
                   6593:                        * valp = (long) q->q_last;
                   6594:                        break;
                   6595: 
                   6596:                case QFLAG:
                   6597:                        * valp = q->q_flag;
                   6598:                        break;
                   6599: 
                   6600:                default:
                   6601:                        return EINVAL;
                   6602:                }
                   6603:        else {
                   6604:                qband_t      *  qbandp;
                   6605: 
                   6606:                if ((qbandp = QUEUE_BAND (q, pri)) == NULL &&
                   6607:                    (qbandp = QBAND_ALLOC (q, pri)) == NULL)
                   6608:                        return ENOMEM;
                   6609: 
                   6610:                switch (what) {
                   6611: 
                   6612:                case QHIWAT:
                   6613:                        * valp = qbandp->qb_hiwat;
                   6614:                        break;
                   6615: 
                   6616:                case QLOWAT:
                   6617:                        * valp = qbandp->qb_lowat;
                   6618:                        break;
                   6619: 
                   6620:                case QCOUNT:
                   6621:                        * valp = qbandp->qb_count;
                   6622:                        break;
                   6623: 
                   6624:                case QFIRST:
                   6625:                        * valp = (long) qbandp->qb_first;
                   6626:                        break;
                   6627: 
                   6628:                case QLAST:
                   6629:                        * valp = (long) qbandp->qb_last;
                   6630:                        break;
                   6631: 
                   6632:                case QFLAG:
                   6633:                        * valp = qbandp->qb_flag;
                   6634:                        break;
                   6635: 
                   6636:                default:
                   6637:                        return EINVAL;
                   6638:                }
                   6639:        }
                   6640: 
                   6641:        return 0;
                   6642: }
                   6643: 
                   6644: 
                   6645: /*
                   6646:  *-STATUS:
                   6647:  *     DDI/DKI
                   6648:  *
                   6649:  *-NAME:
                   6650:  *     strqset         Change information about a queue or band of the queue.
                   6651:  *
                   6652:  *-SYNOPSIS:
                   6653:  *     #include <sys/types.h>
                   6654:  *     #include <sys/stream.h>
                   6655:  *
                   6656:  *     int strqset (queue_t * q, qfields_t what, uchar_t pri, long val);
                   6657:  *
                   6658:  *-ARGUMENTS:
                   6659:  *     q               Pointer to the queue.
                   6660:  *
                   6661:  *     what            The field of the queue to change. Value values are:
                   6662:  *
                   6663:  *                     QHIWAT  High water mark of the specified priority
                   6664:  *                             band.
                   6665:  *
                   6666:  *                     QLOWAT  Low water mark of the specified priority band.
                   6667:  *
                   6668:  *                     QMAXPSZ Maximum packet size of the specified priority
                   6669:  *                             band.
                   6670:  *
                   6671:  *                     QMINPSZ Minimum packet size of the specified priority
                   6672:  *                             band.
                   6673:  *
                   6674:  *     pri             Priority band of the queue to be changed.
                   6675:  *
                   6676:  *     val             New value for the field to be changed.
                   6677:  *
                   6678:  *-DESCRIPTION:
                   6679:  *     strqset () gives drivers and modules a way to change information about
                   6680:  *     a queue or a particular priority band of a queue without directly
                   6681:  *     accessing STREAMS data structures.
                   6682:  *
                   6683:  *-RETURN VALUE:
                   6684:  *     On success, 0 is returned. An error number is returned on failure.
                   6685:  *
                   6686:  *-LEVEL:
                   6687:  *     Base or interrupt.
                   6688:  *
                   6689:  *-NOTES:
                   6690:  *     Does not sleep.
                   6691:  *
                   6692:  *     The caller must have the stream frozen [see freezestr ()] when calling
                   6693:  *     this function.
                   6694:  *
                   6695:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   6696:  *     held across calls to this function.
                   6697:  *
                   6698:  *-SEE ALSO:
                   6699:  */
                   6700: 
                   6701: #if    __USE_PROTO__
                   6702: int (strqset) (queue_t * q, qfields_t what, uchar_t pri, long val)
                   6703: #else
                   6704: int
                   6705: strqset __ARGS ((q, what, pri, val))
                   6706: queue_t              * q;
                   6707: qfields_t      what;
                   6708: uchar_t                pri;
                   6709: long           val;
                   6710: #endif
                   6711: {
                   6712:        QFROZEN_TRACE (q, "strqset");
                   6713: 
                   6714:        if (pri > 0)
                   6715:                switch (what) {
                   6716: 
                   6717:                case QHIWAT:
                   6718:                        q->q_hiwat = val;
                   6719:                        break;
                   6720: 
                   6721:                case QLOWAT:
                   6722:                        q->q_lowat = val;
                   6723:                        break;
                   6724: 
                   6725:                case QMAXPSZ:
                   6726:                        q->q_maxpsz = val;
                   6727:                        break;
                   6728: 
                   6729:                case QMINPSZ:
                   6730:                        q->q_minpsz = val;
                   6731:                        break;
                   6732: 
                   6733:                case QCOUNT:
                   6734:                case QFIRST:
                   6735:                case QLAST:
                   6736:                case QFLAG:
                   6737:                        return EPERM;
                   6738: 
                   6739:                default:
                   6740:                        return EINVAL;
                   6741:                }
                   6742:        else {
                   6743:                qband_t       * qbandp;
                   6744: 
                   6745:                if ((qbandp = QUEUE_BAND (q, pri)) == NULL &&
                   6746:                    (qbandp = QBAND_ALLOC (q, pri)) == NULL)
                   6747:                        return ENOMEM;
                   6748: 
                   6749:                switch (what) {
                   6750: 
                   6751:                case QHIWAT:
                   6752:                        qbandp->qb_hiwat = val;
                   6753:                        break;
                   6754: 
                   6755:                case QLOWAT:
                   6756:                        qbandp->qb_lowat = val;
                   6757:                        break;
                   6758: 
                   6759:                case QCOUNT:
                   6760:                case QFIRST:
                   6761:                case QLAST:
                   6762:                case QFLAG:
                   6763:                        return EPERM;
                   6764: 
                   6765:                default:
                   6766:                        return EINVAL;
                   6767:                }
                   6768:         }
                   6769: 
                   6770:         return 0;
                   6771: }
                   6772: 
                   6773: 
                   6774: /*
                   6775:  *-STATUS:
                   6776:  *     Compatibility (pre-MP DDI/DKI)
                   6777:  *
                   6778:  *-NAME:
                   6779:  *     testb           Check for an available buffer.
                   6780:  *
                   6781:  *-SYNOPSIS:
                   6782:  *     #include <sys/stream.h>
                   6783:  *
                   6784:  *     int testb (int size, int pri);
                   6785:  *
                   6786:  *-ARGUMENTS:
                   6787:  *     size            Size of the requested buffer.
                   6788:  *
                   6789:  *     pri             Priority of the allocb () request.
                   6790:  *
                   6791:  *-DESCRIPTION:
                   6792:  *     testb () checks to see if an allocb () call is likely to succeed if
                   6793:  *     a buffer of "size" bytes at priority "pri" is requested. Even if
                   6794:  *     testb () returns successfully, the call to allocb () can fail.
                   6795:  *
                   6796:  *-RETURN VALUE:
                   6797:  *     Returns 1 if a buffer of the requested size is available, and 0 if
                   6798:  *     one is not.
                   6799:  *
                   6800:  *-LEVEL:
                   6801:  *     Base or interrupt.
                   6802:  *
                   6803:  *-NOTES:
                   6804:  *     Does not sleep.
                   6805:  *
                   6806:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   6807:  *     held across calls to this function.
                   6808:  *
                   6809:  *     This function is provided purely as a porting convenience for
                   6810:  *     developers working with drivers developed under earlier releases of
                   6811:  *     the System V DDI/DKI or under STREAMS from System V, Release 3. Calls
                   6812:  *     to this function should be replaced with calls to functions that do
                   6813:  *     the real work.
                   6814:  *
                   6815:  *-SEE ALSO:
                   6816:  *     allocb (), bufcall ().
                   6817:  */
                   6818: 
                   6819: #if    __USE_PROTO__
                   6820: int (testb) (int size, int pri)
                   6821: #else
                   6822: int
                   6823: testb __ARGS ((size, pri))
                   6824: int            size;
                   6825: int            pri;
                   6826: #endif
                   6827: {
                   6828:        pl_t            prev_pl;
                   6829:        int             return_val;
                   6830: 
                   6831:        /*
                   6832:         * This function is one of the most braindead peices of STREAMS. It
                   6833:         * may not have been initially, but by the SVR4 DDI/DKI, it was
                   6834:         * *totally* useless. The example code given in that DDI/DKI issue is
                   6835:         * so bad it's unbelievable, and they admit it too...
                   6836:         */
                   6837: 
                   6838:        ASSERT (size > 0);
                   6839:        ASSERT (pri == BPRI_LO || pri == BPRI_HI || pri == BPRI_LO);
                   6840: 
                   6841:        pri = MAP_PRI_LEVEL (pri);
                   6842:        size = MSGB_SIZE (pri);
                   6843: 
                   6844: 
                   6845:        /*
                   6846:         * Lock the basic lock protecting access to the memory pool
                   6847:         * and attempt to acquire the memory we desire.
                   6848:         */
                   6849: 
                   6850:        prev_pl = LOCK (str_mem->sm_msg_lock, str_msg_pl);
                   6851: 
                   6852:        /*
                   6853:         * Before allocating any memory, we check to see that it makes sense
                   6854:         * to give out that memory to the given priority level.
                   6855:         */
                   6856: 
                   6857:        return_val = str_mem->sm_used + size < str_mem->sm_max [pri] &&
                   6858:                        st_maxavail (str_mem->sm_msg_heap) >= size;
                   6859: 
                   6860:        UNLOCK (str_mem->sm_msg_lock, prev_pl);
                   6861: 
                   6862:        return return_val;
                   6863: }
                   6864: 
                   6865: 
                   6866: /*
                   6867:  *-STATUS:
                   6868:  *     DDI/DKI
                   6869:  *
                   6870:  *-NAME:
                   6871:  *     unbufcall       Cancel a pending bufcall () request.
                   6872:  *
                   6873:  *-SYNOPSIS:
                   6874:  *     #include <sys/stream.h>
                   6875:  *
                   6876:  *     void unbufcall (toid_t id);
                   6877:  *
                   6878:  *-ARGUMENTS:
                   6879:  *     id              Identifier returned from bufcall () or esbbcall ().
                   6880:  *
                   6881:  *-DESCRIPTION:
                   6882:  *     unbufcall () cancels a pending bufcall () or esbbcall () request. The
                   6883:  *     argument "id" is a non-zero identifier for the request to be
                   6884:  *     cancelled. "id" is returned from the bufcall () or esbbcall ()
                   6885:  *     function used to issue the request.
                   6886:  *
                   6887:  *-RETURN VALUE:
                   6888:  *     None.
                   6889:  *
                   6890:  *-LEVEL:
                   6891:  *     Base or interrupt.
                   6892:  *
                   6893:  *-NOTES:
                   6894:  *     Does not sleep.
                   6895:  *
                   6896:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   6897:  *     held across calls to this function.
                   6898:  *
                   6899:  *-SEE ALSO:
                   6900:  *     bufcall (), esbbcall ()
                   6901:  */
                   6902: 
                   6903: #if    __USE_PROTO__
                   6904: void (unbufcall) (toid_t id)
                   6905: #else
                   6906: void
                   6907: unbufcall __ARGS ((id))
                   6908: toid_t         id;
                   6909: #endif
                   6910: {
                   6911:        pl_t            prev_pl;
                   6912:        selist_t      * selistp;
                   6913:        sevent_t      * sscan;
                   6914:        sevent_t      * sprev;
                   6915: 
                   6916:        ASSERT (id != 0);
                   6917: 
                   6918:        /*
                   6919:         * Let's lock the list that we are going to search for the new event
                   6920:         * on.
                   6921:         */
                   6922: 
                   6923:        selistp = & str_mem->sm_bcevents [MAP_PRI_LEVEL (TOID_TO_PRI (id))];
                   6924: 
                   6925:        prev_pl = SELIST_LOCK (selistp);
                   6926: 
                   6927:        for (sscan = selistp->sl_head, sprev = NULL ; sscan != NULL ;
                   6928:             sscan = (sprev = sscan)->se_next) {
                   6929:                /*
                   6930:                 * If we find it, dequeue it.
                   6931:                 */
                   6932: 
                   6933:                if (sscan->se_id == id) {
                   6934:                        if (sprev == NULL)
                   6935:                                selistp->sl_head = sscan->se_next;
                   6936:                        else
                   6937:                                sprev->se_next = sscan->se_next;
                   6938: #if _FIFO_BUFCALL
                   6939:                        if (selistp->sl_tail == sscan) {
                   6940: 
                   6941:                                ASSERT (sscan->se_next == NULL);
                   6942:                                selistp->sl_tail = sprev;
                   6943:                        } else
                   6944:                                ASSERT (sscan->se_next != NULL);
                   6945: #endif
                   6946:                        break;
                   6947:                }
                   6948:        }
                   6949: 
                   6950:        SELIST_UNLOCK (selistp, prev_pl);
                   6951: }
                   6952: 
                   6953: 
                   6954: /*
                   6955:  *-STATUS:
                   6956:  *     DDI/DKI
                   6957:  *
                   6958:  *-NAME:
                   6959:  *     unfreezestr     Unfreeze the state of a stream.
                   6960:  *
                   6961:  *-SYNOPSIS:
                   6962:  *     #include <sys/types.h>
                   6963:  *     #include <sys/stream.h>
                   6964:  *
                   6965:  *     void unfreezestr (queue_t * q, pl_t prev_pl);
                   6966:  *
                   6967:  *-ARGUMENTS:
                   6968:  *     q               Pointer to a message queue.
                   6969:  *
                   6970:  *     pl              The interrupt priority level to be set (if the
                   6971:  *                     implementation requires that interrupts be blocked in
                   6972:  *                     order to prevent deadlock) after unfreezing the
                   6973:  *                     stream. See LOCK_ALLOC () for a list of valid values
                   6974:  *                     for "pl". "pl" should be the value that was returned
                   6975:  *                     from the corresponding call to freezestr () unless the
                   6976:  *                     caller has a specific need to set some other interrupt
                   6977:  *                     priority level. Although portable drivers must always
                   6978:  *                     specify an appropriate "pl" argument, implementations
                   6979:  *                     which do not require that the interrupt priority be
                   6980:  *                     raised while the stream is frozen may choose to ignore
                   6981:  *                     this argument.
                   6982:  *
                   6983:  *-DESCRIPTION:
                   6984:  *     unfreezestr () unfreezes the state of the stream containing the queue
                   6985:  *     specified by "q", and sets the interrupt priority level to the value
                   6986:  *     specified by "pl". Unfreezing the state of the stream allows
                   6987:  *     continuation of all activities that were forced to wait while the
                   6988:  *     stream was frozen.
                   6989:  *
                   6990:  *-RETURN VALUE:
                   6991:  *     None.
                   6992:  *
                   6993:  *-LEVEL:
                   6994:  *     Base or interrupt.
                   6995:  *
                   6996:  *-NOTES:
                   6997:  *     Does not sleep.
                   6998:  *
                   6999:  *     The caller must have the stream frozen [see freezestr ()] when calling
                   7000:  *     this function.
                   7001:  *
                   7002:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   7003:  *     held across calls to this function.
                   7004:  *
                   7005:  *-SEE ALSO:
                   7006:  *     freezestr ()
                   7007:  */
                   7008: 
                   7009: #if    __USE_PROTO__
                   7010: void (unfreezestr) (queue_t * q, pl_t pl)
                   7011: #else
                   7012: void
                   7013: unfreezestr __ARGS ((q, pl))
                   7014: queue_t              * q;
                   7015: pl_t           pl;
                   7016: #endif
                   7017: {
                   7018:        unsigned long   back;
                   7019: 
                   7020:        QFROZEN_TRACE (q, "unfreezestr");
                   7021: 
                   7022:        /*
                   7023:         * Since the caller might have used rmvq () to cause a condition where
                   7024:         * queues behind the current one need back-enabling, test for this.
                   7025:         */
                   7026: 
                   7027:        if ((back = q->q_flag & QBACK) != 0)
                   7028:                q->q_flag &= ~ QBACK;
                   7029: 
                   7030:        QUNFREEZE_TRACE (q, pl);
                   7031: 
                   7032:        if (back)
                   7033:                QUEUE_BACKENAB (q);
                   7034: }
                   7035: 
                   7036: 
                   7037: /*
                   7038:  *-STATUS:
                   7039:  *     DDI/DKI
                   7040:  *
                   7041:  *-NAME:
                   7042:  *     unlinkb         Remove a message block from the head of a message.
                   7043:  *
                   7044:  *-SYNOPSIS:
                   7045:  *     #include <sys/stream.h>
                   7046:  *
                   7047:  *     mblk_t * unlinkb (mblk_t * mp);
                   7048:  *
                   7049:  *-ARGUMENTS:
                   7050:  *     mp              Pointer to the message.
                   7051:  *
                   7052:  *-DESCRIPTION:
                   7053:  *     unlinkb () removes the first message block from the message pointed to
                   7054:  *     by "mp". The removed message block is not freed. It is the caller's
                   7055:  *     responsibility to free it.
                   7056:  *
                   7057:  *-RETURN VALUE:
                   7058:  *     unlinkb () returns a pointer to the remainder of the message after the
                   7059:  *     first message block has been removed. If there is only one message
                   7060:  *     block in the message, NULL is returned.
                   7061:  *
                   7062:  *-LEVEL:
                   7063:  *     Base or interrupt.
                   7064:  *
                   7065:  *-NOTES:
                   7066:  *     Does not sleep.
                   7067:  *
                   7068:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   7069:  *     held across calls to this function.
                   7070:  *
                   7071:  *-SEE ALSO:
                   7072:  *     linkb ()
                   7073:  */
                   7074: 
                   7075: #if    __USE_PROTO__
                   7076: mblk_t * (unlinkb) (mblk_t * mp)
                   7077: #else
                   7078: mblk_t *
                   7079: unlinkb __ARGS ((mp))
                   7080: mblk_t       * mp;
                   7081: #endif
                   7082: {
                   7083:        mblk_t        * retval;
                   7084: 
                   7085:        ASSERT (mp != NULL);
                   7086: 
                   7087:        retval = mp->b_cont;
                   7088:        mp->b_cont = NULL;
                   7089: 
                   7090:        return retval;
                   7091: }
                   7092: 
                   7093: 
                   7094: /*
                   7095:  *-STATUS:
                   7096:  *     DDI/DKI
                   7097:  *
                   7098:  *-NAME:
                   7099:  *     WR              Get a pointer to the write queue.
                   7100:  *
                   7101:  *-SYNOPSIS:
                   7102:  *     #include <sys/stream.h>
                   7103:  *
                   7104:  *     queue_t * WR (queue_t * q);
                   7105:  *
                   7106:  *-ARGUMENTS:
                   7107:  *     q               Pointer to the queue whose write queue is to be
                   7108:  *                     returned.
                   7109:  *
                   7110:  *-DESCRIPTION:
                   7111:  *     The WR () function accepts a queue pointer as an argument and returns
                   7112:  *     a pointer to the write queue of the same module.
                   7113:  *
                   7114:  *-RETURN VALUE:
                   7115:  *     To pointer to the write queue.
                   7116:  *
                   7117:  *-LEVEL:
                   7118:  *     Base or interrupt.
                   7119:  *
                   7120:  *-NOTES:
                   7121:  *     Does not sleep.
                   7122:  *
                   7123:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   7124:  *     held across calls to this function.
                   7125:  *
                   7126:  *-SEE ALSO:
                   7127:  *     OTHERQ (), RD ().
                   7128:  */
                   7129: 
                   7130: #if    __USE_PROTO__
                   7131: queue_t * (WR) (queue_t * q)
                   7132: #else
                   7133: queue_t *
                   7134: WR __ARGS ((q))
                   7135: queue_t              * q;
                   7136: #endif
                   7137: {
                   7138:        QUEUE_TRACE (q, "WR");
                   7139: 
                   7140:        return WR (q);
                   7141: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.