Annotation of coherent/f/etc/conf/streams/src/strmlib.c, revision 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.