Annotation of coherent/b/STREAMS/conf/streams/src/struser.c, revision 1.1

1.1     ! root        1: #define        _DDI_DKI        1
        !             2: #define        _DDI_DKI_IMPL   1
        !             3: #define        _SYSV4          1
        !             4: 
        !             5: /*
        !             6:  */
        !             7: 
        !             8: #include <common/ccompat.h>
        !             9: #include <kernel/fhsys.h>
        !            10: #include <kernel/strmlib.h>
        !            11: #include <sys/confinfo.h>
        !            12: #include <sys/types.h>
        !            13: #include <sys/kmem.h>
        !            14: #include <sys/poll.h>
        !            15: #include <sys/ksynch.h>
        !            16: #include <sys/file.h>
        !            17: #include <sys/uio.h>
        !            18: #include <sys/cmn_err.h>
        !            19: #include <sys/errno.h>
        !            20: #include <sys/signal.h>
        !            21: #include <stropts.h>
        !            22: #include <string.h>
        !            23: #include <poll.h>
        !            24: 
        !            25: /*
        !            26:  * The following function (local to this module) is forward-referenced due to
        !            27:  * the mutual recursion between the final close process and the streams unlink
        !            28:  * code.
        !            29:  */
        !            30: 
        !            31: __LOCAL__ int  SHEAD_DO_CLOSE  __PROTO ((shead_t * sheadp, int mode,
        !            32:                                          cred_t * credp));
        !            33: 
        !            34: 
        !            35: lkinfo_t __stream_schedule_lkinfo = {
        !            36:        "STREAMS queue schedule", INTERNAL_LOCK
        !            37: };
        !            38: 
        !            39: lkinfo_t __stream_event_lkinfo = {
        !            40:        "STREAMS bufcall ()/esbbcall () event list", INTERNAL_LOCK
        !            41: };
        !            42: 
        !            43: __LOCAL__ lkinfo_t _stream_head_lkinfo = {
        !            44:        "stream head lock", INTERNAL_LOCK
        !            45: };
        !            46: 
        !            47: 
        !            48: /*
        !            49:  * Allocate and initialize a queue pair. This function only performs a partial
        !            50:  * initialization; many other fields are filled in by the caller, usually from
        !            51:  * fields supplied in the "streamtab" structure.
        !            52:  *
        !            53:  * Since at initial stream open time we we be allocating at least two queue
        !            54:  * pairs and one or two stream head structures, we try to satisfy all those
        !            55:  * allocations in one step here.
        !            56:  *
        !            57:  * The "npairs" argument indicates the number of queue pairs to be allocated.
        !            58:  * The "extra" argument is the number of additional bytes to allocate over and
        !            59:  * above the memory for the queue pairs.
        !            60:  *
        !            61:  * Call only from base level. This function may sleep.
        !            62:  */
        !            63: 
        !            64: #if    __USE_PROTO__
        !            65: __LOCAL__ queue_t * (QUEUE_ALLOC) (int npairs, size_t extra)
        !            66: #else
        !            67: __LOCAL__ queue_t *
        !            68: QUEUE_ALLOC __ARGS ((npairs, extra))
        !            69: int            npairs;
        !            70: size_t         extra;
        !            71: #endif
        !            72: {
        !            73:        queue_t       * q;
        !            74:        queue_t       * init;
        !            75:        int             count;
        !            76: 
        !            77:        ASSERT (npairs > 0 && npairs < 3);
        !            78: 
        !            79:        /*
        !            80:         * We use kmem_zalloc () to allocate this space so we can sleaze our
        !            81:         * way out of most of the initialization work.
        !            82:         */
        !            83: 
        !            84:        if ((q = (queue_t *) kmem_zalloc (2 * npairs * sizeof (* q) + extra,
        !            85:                                          KM_SLEEP)) == NULL)
        !            86:                return NULL;
        !            87: 
        !            88:        init = q;
        !            89:        count = npairs;
        !            90: 
        !            91:        do {
        !            92:                /*
        !            93:                 * First, initialise the read side of the queue. While we are
        !            94:                 * at it, we link the "q_next" members of multiple queues for
        !            95:                 * a read side; if we treat the value "q" that we are going to
        !            96:                 * return to the caller as the stream head, the links run from
        !            97:                 * the last entry we initialize towards the first one.
        !            98:                 */
        !            99: 
        !           100:                if (count > 1)
        !           101:                        (init + 2)->q_next = init;
        !           102: 
        !           103:                init->q_flag = QWANTR | QREADR | QPROCSOFF;
        !           104: 
        !           105:                SFREEZE_INIT (init);
        !           106: 
        !           107:                init ++;
        !           108: 
        !           109: 
        !           110:                /*
        !           111:                 * Next, work on the write side. For multiple queues, the
        !           112:                 * write size "q_next" links run from the "head" to the device.
        !           113:                 */
        !           114: 
        !           115:                if (count > 1)
        !           116:                        init->q_next = init + 2;
        !           117: 
        !           118:                init->q_flag = QWANTR | QPROCSOFF;
        !           119: 
        !           120:                SFREEZE_INIT (init);
        !           121: 
        !           122:                init ++;
        !           123:        } while (-- count > 0);
        !           124: 
        !           125: 
        !           126:        /*
        !           127:         * We put a pointer to any "extra" space that the caller requested in
        !           128:         * the "q_ptr" fields of the first two queues allocated, since they
        !           129:         * will almost always be the stream head queue pair.
        !           130:         */
        !           131: 
        !           132:        if (extra > 0) {
        !           133: 
        !           134:                q->q_ptr = (char *) q + 2 * sizeof (* q) * npairs;
        !           135:                W (q)->q_ptr = q->q_ptr;
        !           136:        }
        !           137: 
        !           138:        return q;
        !           139: }
        !           140: 
        !           141: 
        !           142: /*
        !           143:  * Set a queue's initial watermark data and some other stuff.
        !           144:  */
        !           145: 
        !           146: #if    __USE_PROTO__
        !           147: __LOCAL__ void (QUEUE_INITOPT) (queue_t * q)
        !           148: #else
        !           149: __LOCAL__ void
        !           150: QUEUE_INITOPT __ARGS ((q))
        !           151: queue_t              * q;
        !           152: #endif
        !           153: {
        !           154:        struct module_info
        !           155:                      * mi = q->q_qinfo->qi_minfo;
        !           156: 
        !           157:        q->q_minpsz = mi->mi_minpsz;
        !           158:        q->q_maxpsz = mi->mi_maxpsz;
        !           159:        q->q_hiwat = mi->mi_hiwat;
        !           160:        q->q_lowat = mi->mi_lowat;
        !           161: }
        !           162: 
        !           163: 
        !           164: /*
        !           165:  * Set up a queue pair's initial options.
        !           166:  */
        !           167: 
        !           168: typedef enum {
        !           169:        QI_NORMAL,
        !           170:        QI_MUX
        !           171: } qiflag_t;
        !           172: 
        !           173: #if    __USE_PROTO__
        !           174: __LOCAL__ void (QUEUE_INIT) (queue_t * q, struct streamtab * stab,
        !           175:                             qiflag_t mux)
        !           176: #else
        !           177: void
        !           178: QUEUE_INIT __ARGS ((q, stab, mux))
        !           179: queue_t              * q;
        !           180: struct streamtab
        !           181:              * stab;
        !           182: qiflag_t       mux;
        !           183: #endif
        !           184: {
        !           185:        q->q_qinfo = mux == QI_NORMAL ? stab->st_rdinit : stab->st_muxrinit;
        !           186:        QUEUE_INITOPT (q);
        !           187: 
        !           188:        q = W (q);
        !           189: 
        !           190:        q->q_qinfo = mux == QI_NORMAL ? stab->st_wrinit : stab->st_muxwinit;
        !           191:        QUEUE_INITOPT (q);
        !           192: }
        !           193: 
        !           194: 
        !           195: /*
        !           196:  * This function is the dual to the QBAND_ALLOC () function, freeing any
        !           197:  * allocated "qband" structures associated with the given queue.
        !           198:  *
        !           199:  * The caller must have the queue frozen or not linked on any stream.
        !           200:  */
        !           201: 
        !           202: #if    __USE_PROTO__
        !           203: void (QBAND_FREE) (queue_t * q)
        !           204: #else
        !           205: void
        !           206: QBAND_FREE __ARGS ((q))
        !           207: queue_t              * q;
        !           208: #endif
        !           209: {
        !           210:        qband_t       * scan;
        !           211:        qband_t       * prev;
        !           212:        int             nbands;
        !           213: 
        !           214:        QUEUE_TRACE (q, "QBAND_FREE");
        !           215: 
        !           216:        /*
        !           217:         * We use flags in the "qband" entries to locate allocation
        !           218:         * boundaries rather than trying to recover this information purely
        !           219:         * from comparing addresses (although since the address comparisons
        !           220:         * provide an extra check we do that too). In theory, an allocator
        !           221:         * might not need extra information stored in the arena yet might
        !           222:         * fail if adjacent allocations are coalesced into a single free ().
        !           223:         *
        !           224:         * I don't know of any allocators with this property, but one might
        !           225:         * exist.
        !           226:         *
        !           227:         * This code will work just fine under the allocation scheme which
        !           228:         * keeps the QBAND entries in a single vector, so we don't need to
        !           229:         * conditionalize this code at all.
        !           230:         */
        !           231: 
        !           232:        nbands = 0;
        !           233: 
        !           234:        for (prev = scan = q->q_bandp ; scan != NULL ; scan = scan->qb_next) {
        !           235: 
        !           236:                if ((scan->qb_flag & QB_FIRST) != 0) {
        !           237: 
        !           238:                        ASSERT (nbands > 0);
        !           239: 
        !           240:                        kmem_free (prev, sizeof (* prev) * nbands);
        !           241: 
        !           242:                        nbands = 1;
        !           243:                        prev = scan;
        !           244:                } else {
        !           245: 
        !           246:                        ASSERT (scan == prev + nbands);
        !           247:                        nbands ++;
        !           248:                }
        !           249:        }
        !           250: 
        !           251:        if (nbands > 0)
        !           252:                kmem_free (prev, sizeof (* prev) * nbands);
        !           253: }
        !           254: 
        !           255: 
        !           256: /*
        !           257:  * Destroy an individual queue.
        !           258:  */
        !           259: 
        !           260: #if    __USE_PROTO__
        !           261: __LOCAL__ void (QUEUE_DESTROY) (queue_t * q)
        !           262: #else
        !           263: __LOCAL__ void
        !           264: QUEUE_DESTROY __ARGS ((q))
        !           265: queue_t              * q;
        !           266: #endif
        !           267: {
        !           268:        mblk_t        * mp;
        !           269:        mblk_t        * next;
        !           270: 
        !           271:        QSCHED_UNSCHEDULE (q, str_mem->sm_sched);
        !           272: 
        !           273:        /*
        !           274:         * Free all the memory allocated to messages that remain on the queue.
        !           275:         */
        !           276: 
        !           277:        for (mp = q->q_first ; mp != NULL ; mp = next) {
        !           278: 
        !           279:                next = mp->b_next;
        !           280:                freemsg (mp);
        !           281:        }
        !           282: 
        !           283:        if ((q->q_flag & QWANTW) != 0)
        !           284:                QUEUE_BACKENAB (q);
        !           285: 
        !           286:        SFREEZE_DESTROY (q);
        !           287: 
        !           288:        if (q->q_nband > 0)
        !           289:                QBAND_FREE (q);
        !           290: }
        !           291: 
        !           292: 
        !           293: /*
        !           294:  * Destroy and release the memory for a queue pair or group of pairs. The
        !           295:  * arguments passed to this function should match those used to allocate a
        !           296:  * pair or group of pairs exactly. This can easily be done by recognising the
        !           297:  * various canonical forms for stream structures; modules are always lone
        !           298:  * queue pairs, regular streams match a driver and stream head (with
        !           299:  * associated extra data for the stream head), and stream pipes consist of
        !           300:  * two pairs of queue structures with two head structures.
        !           301:  */
        !           302: 
        !           303: #if    __USE_PROTO__
        !           304: __LOCAL__ void (QUEUE_FREE) (queue_t * rq, int npairs, size_t extra)
        !           305: #else
        !           306: __LOCAL__ void
        !           307: QUEUE_FREE __ARGS ((rq, npairs, extra))
        !           308: queue_t              * rq;
        !           309: int            npairs;
        !           310: size_t         extra;
        !           311: #endif
        !           312: {
        !           313:        queue_t       * destroy;
        !           314:        int             count;
        !           315: 
        !           316:        ASSERT (rq != NULL);
        !           317:        ASSERT (npairs > 0 && npairs < 3);
        !           318: 
        !           319:        destroy = rq;
        !           320:        count = npairs * 2;
        !           321: 
        !           322:        do {
        !           323: 
        !           324:                QUEUE_DESTROY (destroy);
        !           325:                destroy ++;
        !           326:        } while (-- count > 0);
        !           327: 
        !           328:        kmem_free (rq, 2 * sizeof (* rq) * npairs + extra);
        !           329: }
        !           330: 
        !           331: 
        !           332: /*
        !           333:  * STREAM HEAD MANAGEMENT NOTES:
        !           334:  *
        !           335:  * The management of stream head structures introduces some interesting
        !           336:  * synchronization problems arising from the interaction of the rules
        !           337:  * associated with driver close routines and the fact that stream head
        !           338:  * structures are dynamically allocated.
        !           339:  *
        !           340:  * The first problem is really one of specification; what does it mean for a
        !           341:  * driver close () entry point to return EINTR? System V does not talk about
        !           342:  * this case specifically, so we prohibit it by treating error returns from
        !           343:  * the close () entry point uniformly by still actually closing the device.
        !           344:  *
        !           345:  * The second problem is this; a driver should not be re-opened until the
        !           346:  * close process has completed. However, completion of the close process will
        !           347:  * normally involve deallocation of the stream head (where presumably the
        !           348:  * open routines are waiting).
        !           349:  *
        !           350:  * Our problem is that it is not possible to reliably determine whether there
        !           351:  * are any other contexts waiting on a sleep lock. While it might be possible
        !           352:  * to do so using SLEEP_LOCKAVAIL (), this would require that the calling
        !           353:  * context release the lock. Under a plausible implementation of SLEEP_LOCK ()
        !           354:  * where sleep locks are basically implemented with the sleep () and wakeup ()
        !           355:  * functions and a "locked" flag, there will be no way for a process to find
        !           356:  * out whether there are any functions waiting on the lock, since the unlock
        !           357:  * implementation could simply clear the "locked" flag and issue wakeup (),
        !           358:  * so that there could be any number of contexts waiting to run and test the
        !           359:  * "locked" flag, yet SLEEP_LOCKAVAIL () in the calling context would return
        !           360:  * true. Deallocating the lock at this time would be potentially disastrous.
        !           361:  *
        !           362:  * Actually, even a quality implementation of sleep locks (such as is provided
        !           363:  * with this STREAMS system) cannot be easily used this way, since it is very
        !           364:  * difficult to ensure that the information returned by SLEEP_LOCKAVAIL () is
        !           365:  * current.
        !           366:  *
        !           367:  * The situation can be resolved by maintaining a count of processes wishing
        !           368:  * to lock the item. The count can be maintained by using the basic-lock
        !           369:  * action associated with DDI/DKI synchronization variables, and the new
        !           370:  * SV_SIGNAL () operation can be used to pass the ownership of the lock to
        !           371:  * a waiting process reliably.
        !           372:  *
        !           373:  * Once this is in place, it becomes clear how the count of waiting processes
        !           374:  * can be used to simplify the destruction of stream heads; essentially,
        !           375:  * when a process wishes to release the "lock" on the stream head, if both
        !           376:  * the open count and the waiting count are 0, then the memory for the item
        !           377:  * can be safely released. Otherwise, control simply passes to the next
        !           378:  * waiting process.
        !           379:  *
        !           380:  * So, if a process is performing a final close on a stream, and some open
        !           381:  * requests are queued, the close will leave the stream's memory alone and
        !           382:  * simply pass it on to the waiting open (which can detect that the stream
        !           383:  * needs to be treated as new since the open count is 0). If the waiting open
        !           384:  * was interrupted by a signal, it would still have to decrement the count of
        !           385:  * waiting processes before it releases its lock, at which time it would know
        !           386:  * to remove the item from the directory and release the memory.
        !           387:  *
        !           388:  * For this to work properly takes some coordination in the policy for the
        !           389:  * directory; the basic lock used to guard lock operations should be held
        !           390:  * during searches of the directory to ensure that the count value is correct
        !           391:  * with respect to all processes; a process that has a pointer to the stream
        !           392:  * head (obtained from the directory) which it has not incremented the count
        !           393:  * for is an error. Note that this only applies to operations which might
        !           394:  * later affect the count, of course.
        !           395:  *
        !           396:  *
        !           397:  * STREAM OPERATIONS AND LOCKS:
        !           398:  *
        !           399:  * open ()     This operation cannot begin while there is a final close in
        !           400:  *             progress. If this operation increments the "open count" before
        !           401:  *             calling the device open routines, it is possible that it will
        !           402:  *             also have to perform final close duties if a driver or module
        !           403:  *             fails the open. This function may cause the creation of a new
        !           404:  *             queue pair and directory entry.
        !           405:  *
        !           406:  *             The multiprocessor DDI/DKI also mandates that a particular
        !           407:  *             device number's open () routine only have one instance active
        !           408:  *             at any given time.
        !           409:  *
        !           410:  * close ()    Normally, this does not require extended locking, but the case
        !           411:  *             of beginning a final close is special, since only then will
        !           412:  *             the queue drain and final close procedures begin. Since there
        !           413:  *             cannot be outstanding ioctl ()s during final close, the timer
        !           414:  *             code used to control ioctl ()s can be shared with this for
        !           415:  *             timing out while waiting for a write queue to drain.
        !           416:  *
        !           417:  * read (), getmsg (), getpmsg ()
        !           418:  *             Under normal circumstances, these functions require no special
        !           419:  *             treatment. It would be desirable to support an extension to
        !           420:  *             STREAMS which supported "safe" multiple readers, where the
        !           421:  *             serialization of reads is guaranteed.
        !           422:  *
        !           423:  * write (), putmsg (), putpmsg ()
        !           424:  *             These functions require little special treatment. It would be
        !           425:  *             desirable to support an extension to STREAMS which guaranteed
        !           426:  *             serialization of writes, for instance to guarantee unlimited-
        !           427:  *             length atomic pipe writes.
        !           428:  *
        !           429:  * ioctl ()    Depending on the details of the operation, we may need
        !           430:  *
        !           431:  *                     a read lock on the stream head (eg. I_GETCLTIME).
        !           432:  *                     a write lock on the stream head (eg. I_SRDOPT).
        !           433:  *                     a block on open and pop (I_PUSH).
        !           434:  *                     a block on close and push (I_POP).
        !           435:  *                     a long-term lock on the message queue.
        !           436:  *
        !           437:  *             The long-term lock operations revolve around the operations
        !           438:  *             that send messages downstream : I_LINK, I_UNLINK, I_PLINK,
        !           439:  *             I_PUNLINK, and I_STR. These operations are also special in
        !           440:  *             that they are capable of timing out.
        !           441:  *
        !           442:  *             Since the close or open routines invoked by an I_PUSH or I_POP
        !           443:  *             operation may block, they require analagous locking to the
        !           444:  *             open () and close () cases.
        !           445:  *
        !           446:  * LOCK SUMMARY:
        !           447:  *     EXCLUSIVE LONG-TERM LOCK WITH OPTIONAL TIMEOUT:
        !           448:  *         open/close category:
        !           449:  *             open (), close (), I_PUSH, I_POP
        !           450:  *         ioctl category:
        !           451:  *             I_LINK, I_UNLINK, I_PLINK, I_PUNLINK, I_STR
        !           452:  *
        !           453:  *         In theory, a single lock will do. However, once we take into
        !           454:  *         account terminal behaviour w.r.t. CLOCAL and other similar
        !           455:  *         situations, it seems that creating the subcategories above will
        !           456:  *         suit us better.
        !           457:  *
        !           458:  *         Final close is a special case that blocks all other cases, which
        !           459:  *         can be distinguished fairly clearly.
        !           460:  *
        !           461:  *     STREAM HEAD WRITE LOCK:
        !           462:  *             I_SRDOPT, I_SETSIG, I_SWROPT, I_SETCLTIME
        !           463:  *             Certain stream head message processing routines may also write
        !           464:  *             lock the stream head, such as M_SETOPT processing.
        !           465:  *
        !           466:  *     All other streams operations should acquire a stream head read lock
        !           467:  *     before reading stream head variables.
        !           468:  */
        !           469: /*
        !           470:  * STREAM HEAD WAIT NOTES:
        !           471:  *
        !           472:  * In addition to the above discussion about locking, there are other
        !           473:  * operations that may cause a process to block while at the stream head. For
        !           474:  * instance, read (), write (), I_RECVFD, and I_STR operations may cause the
        !           475:  * outer context to block until some kind of message arrives.
        !           476:  *
        !           477:  * The question we are immediately faced with is what level of specificity to
        !           478:  * provide in the arrangement of synchronization variables and basic locks.
        !           479:  * Until the implementation is complete and we can perform detailed
        !           480:  * measurements with a variety of (pathological) loads on a variety of
        !           481:  * systems, we really don't know. For simplicity, the current system performs
        !           482:  * all stream head blocking by sleeping on the "sh_wait_sv" synchronization
        !           483:  * variable that is also used by the above locking operations.
        !           484:  *
        !           485:  * However, to give some isolation from changes in this scheme, we mandate a
        !           486:  * generic layer to deal with this. Not only does this insulate operations
        !           487:  * from the details of synchronization, but it allows us to perform some
        !           488:  * simple optimizations that may allow this simple scheme to perform better.
        !           489:  */
        !           490: 
        !           491: 
        !           492: /*
        !           493:  * Initialize a stream head structure, assuming that memory was allocated with
        !           494:  * kmem_zalloc () and so NULL pointers and 0-value fields need not be filled
        !           495:  * in.
        !           496:  *
        !           497:  * This function may sleep waiting for memory to become available to allocate
        !           498:  * the locks needed by the stream head.
        !           499:  */
        !           500: 
        !           501: #if    __USE_PROTO__
        !           502: __LOCAL__ void (SHEAD_INIT) (shead_t * sheadp, struct streamtab * stabp,
        !           503:                             n_dev_t dev, queue_t * rq)
        !           504: #else
        !           505: __LOCAL__ void
        !           506: SHEAD_INIT __ARGS ((sheadp, stabp, dev, rq))
        !           507: shead_t              * sheadp;
        !           508: struct streamtab
        !           509:              * stabp;
        !           510: n_dev_t                dev;
        !           511: queue_t              * rq;
        !           512: #endif
        !           513: {
        !           514:        ASSERT (sheadp != NULL);
        !           515:        ASSERT (rq != NULL);
        !           516: 
        !           517:        /*
        !           518:         * The sh_lock_count and sh_time_count members are initialized in the
        !           519:         * lock code.
        !           520:         */
        !           521: 
        !           522:        ASSERT (sheadp->sh_open_count == 0);
        !           523:        ASSERT (sheadp->sh_attach_count == 0);
        !           524:        ASSERT (sheadp->sh_lock_count == 0);
        !           525:        ASSERT (sheadp->sh_time_count == 0);
        !           526:        ASSERT (sheadp->sh_rerrcode == 0);
        !           527:        ASSERT (sheadp->sh_werrcode == 0);
        !           528:        ASSERT (sheadp->sh_wroff == 0);
        !           529: 
        !           530:        ASSERT (sheadp->sh_read_bufcall == 0);
        !           531:        ASSERT (sheadp->sh_timeout_id == 0);
        !           532: 
        !           533:        ASSERT (sheadp->sh_sigs == NULL);
        !           534:        ASSERT (sheadp->sh_linked == NULL);
        !           535:        ASSERT (sheadp->sh_ioc_msg == NULL);
        !           536: 
        !           537:        ASSERT (rq->q_ptr == sheadp);
        !           538: 
        !           539:        sheadp->sh_dev = dev;
        !           540:        sheadp->sh_tab = stabp;
        !           541:        sheadp->sh_head = rq;
        !           542: 
        !           543:        sheadp->sh_pollhead = phalloc (KM_SLEEP);
        !           544:        sheadp->sh_flags = SH_MASTER;
        !           545:        sheadp->sh_readopt = RNORM | RPROTNORM;
        !           546: 
        !           547:        sheadp->sh_basic_lockp = LOCK_ALLOC (stream_head_hierarchy, plstr,
        !           548:                                             & _stream_head_lkinfo, KM_SLEEP);
        !           549:        sheadp->sh_wait_sv = SV_ALLOC (KM_SLEEP);
        !           550: 
        !           551:        ASSERT (sheadp->sh_basic_lockp != NULL || sheadp->sh_wait_sv != NULL);
        !           552: 
        !           553: 
        !           554:        /*
        !           555:         * The default time to wait for a queue to drain while closing is 15s.
        !           556:         */
        !           557: 
        !           558:        sheadp->sh_cltime = drv_usectohz (15000000L);
        !           559: }
        !           560: 
        !           561: 
        !           562: /*
        !           563:  * Turn a stream head structure back into raw bits.
        !           564:  */
        !           565: 
        !           566: #if    __USE_PROTO__
        !           567: __LOCAL__ void (SHEAD_DESTROY) (shead_t * sheadp)
        !           568: #else
        !           569: __LOCAL__ void
        !           570: SHEAD_DESTROY __ARGS((sheadp))
        !           571: shead_t              * sheadp;
        !           572: #endif
        !           573: {
        !           574:        ASSERT (sheadp != NULL);
        !           575:        ASSERT (sheadp->sh_sigs == NULL);
        !           576:        ASSERT (sheadp->sh_linked == NULL);
        !           577: 
        !           578:        ASSERT (sheadp->sh_open_count == 0);
        !           579:        ASSERT (sheadp->sh_attach_count == 0);
        !           580:        ASSERT (sheadp->sh_lock_count == 0);
        !           581: 
        !           582:        ASSERT (sheadp->sh_timeout_id == 0);
        !           583: 
        !           584:        if (sheadp->sh_read_bufcall != 0)
        !           585:                unbufcall (sheadp->sh_read_bufcall);
        !           586: 
        !           587:        LOCK_DEALLOC (sheadp->sh_basic_lockp);
        !           588:        SV_DEALLOC (sheadp->sh_wait_sv);
        !           589: 
        !           590:        phfree (sheadp->sh_pollhead);
        !           591: }
        !           592: 
        !           593: 
        !           594: /*
        !           595:  * This function attempts to determine the appropriate id queue for a stream
        !           596:  * head based on cues in the stream head.
        !           597:  */
        !           598: 
        !           599: #if    __USE_PROTO__
        !           600: __LOCAL__ slist_id_t (SHEAD_ID) (shead_t * sheadp)
        !           601: #else
        !           602: __LOCAL__ slist_id_t
        !           603: SHEAD_ID __ARGS ((sheadp))
        !           604: shead_t              * sheadp;
        !           605: #endif
        !           606: {
        !           607:        ASSERT (sheadp != NULL);
        !           608: 
        !           609:        if (SHEAD_IS_PIPE (sheadp))
        !           610:                return PIPE_SLIST;
        !           611: 
        !           612:        return DEV_SLIST;
        !           613: }
        !           614: 
        !           615: 
        !           616: /*
        !           617:  * This function finds a stream head by looking up its device number, but
        !           618:  * nothing else. To call this function, the caller must have good reason to
        !           619:  * suspect that an open reference to the stream exists and isn't going to go
        !           620:  * away.
        !           621:  *
        !           622:  * If this routine returns NULL, then that is a serious error (which may be
        !           623:  * diagnosed by console messages), because it indicates that the caller has
        !           624:  * not got the claimed knowledge of the state of the system!
        !           625:  */
        !           626: 
        !           627: #if    __USE_PROTO__
        !           628: shead_t * (SHEAD_FIND) (n_dev_t dev, slist_id_t id)
        !           629: #else
        !           630: shead_t *
        !           631: SHEAD_FIND __ARGS ((dev, id))
        !           632: n_dev_t                dev;
        !           633: slist_id_t     id;
        !           634: #endif
        !           635: {
        !           636:        shead_t       * scan;
        !           637:        pl_t            prev_pl;
        !           638: 
        !           639:        prev_pl = RW_RDLOCK (str_mem->sm_head_lock, plstr);
        !           640: 
        !           641:        for (scan = str_mem->sm_streams [id] ; scan != NULL ;
        !           642:             scan = scan->sh_next) {
        !           643: 
        !           644:                if (scan->sh_dev == dev)
        !           645:                        break;
        !           646:        }
        !           647: 
        !           648:        RW_UNLOCK (str_mem->sm_head_lock, prev_pl);
        !           649: 
        !           650:        if (scan == NULL)
        !           651:                cmn_err (CE_WARN, "Unable to locate stream in SHEAD_FIND ()");
        !           652:        else
        !           653:                ASSERT (SHEAD_ID (scan) == id);
        !           654: 
        !           655:        return scan;
        !           656: }
        !           657: 
        !           658: 
        !           659: /*
        !           660:  * This function attempts to locate an existing entry and increment its lock
        !           661:  * count atomically.
        !           662:  */
        !           663: 
        !           664: #if    __USE_PROTO__
        !           665: __LOCAL__ shead_t * (SHEAD_FIND_AND_LOCK) (n_dev_t dev, slist_id_t id)
        !           666: #else
        !           667: __LOCAL__ shead_t *
        !           668: SHEAD_FIND_AND_LOCK __ARGS ((dev, id))
        !           669: n_dev_t                dev;
        !           670: slist_id_t     id;
        !           671: #endif
        !           672: {
        !           673:        shead_t       * scan;
        !           674:        pl_t            prev_pl;
        !           675: 
        !           676:        prev_pl = RW_RDLOCK (str_mem->sm_head_lock, plstr);
        !           677: 
        !           678:        for (scan = str_mem->sm_streams [id] ; scan != NULL ;
        !           679:             scan = scan->sh_next) {
        !           680: 
        !           681:                if (scan->sh_dev == dev) {
        !           682:                        /*
        !           683:                         * Now we have found the entry we want, increment the
        !           684:                         * reference count atomically. We know that it will
        !           685:                         * not disappear because of the read lock we have on
        !           686:                         * the containing list.
        !           687:                         */
        !           688: 
        !           689:                        (void) SHEAD_LOCK (scan);
        !           690: 
        !           691:                        scan->sh_lock_count ++;
        !           692:                        break;
        !           693:                }
        !           694:        }
        !           695: 
        !           696:        RW_UNLOCK (str_mem->sm_head_lock, prev_pl);
        !           697:        return scan;
        !           698: }
        !           699: 
        !           700: 
        !           701: /*
        !           702:  * This function adds a stream head to the global list. If an entry with the
        !           703:  * same ID is present on the list, this operation fails.
        !           704:  *
        !           705:  * The stream head should be locked against further opens at this point.
        !           706:  *
        !           707:  * The return value is 0 on success, -1 on error.
        !           708:  */
        !           709: 
        !           710: #if    __USE_PROTO__
        !           711: __LOCAL__ int (SHEAD_ADD) (shead_t * sheadp)
        !           712: #else
        !           713: __LOCAL__ int
        !           714: SHEAD_ADD __ARGS ((sheadp))
        !           715: shead_t              * sheadp;
        !           716: #endif
        !           717: {
        !           718:        pl_t            prev_pl;
        !           719:        shead_t       * scan;
        !           720:        slist_id_t      id;
        !           721: 
        !           722:        id = SHEAD_ID (sheadp);
        !           723: 
        !           724:        ASSERT (sheadp->sh_ref_count == 1);
        !           725:        ASSERT ((sheadp->sh_lock_mask & SH_OPENCLOSE) != 0);
        !           726: 
        !           727:        prev_pl = RW_WRLOCK (str_mem->sm_head_lock, plstr);
        !           728: 
        !           729:        for (scan = str_mem->sm_streams [id] ; scan != NULL ;
        !           730:             scan = scan->sh_next)  {
        !           731: 
        !           732:                if (scan->sh_dev == sheadp->sh_dev) {
        !           733:                        /*
        !           734:                         * We have found a conflict. Unlock the list and
        !           735:                         * return an error.
        !           736:                         */
        !           737: 
        !           738:                        RW_UNLOCK (str_mem->sm_head_lock, prev_pl);
        !           739:                        return -1;
        !           740:                }
        !           741:        }
        !           742: 
        !           743:        sheadp->sh_next = str_mem->sm_streams [id];
        !           744:        str_mem->sm_streams [id] = sheadp;
        !           745: 
        !           746:        RW_UNLOCK (str_mem->sm_head_lock, prev_pl);
        !           747:        return 0;
        !           748: }
        !           749: 
        !           750: 
        !           751: /*
        !           752:  * This function changes the device number of a stream head for a clone open
        !           753:  * situation. The "st_dev" field of the stream head has to be changed with
        !           754:  * the stream head list lock held for writing to avoid confusing anyone who
        !           755:  * is looking for the original device number.
        !           756:  *
        !           757:  * Furthermore, the rename can fail because the new number is already in use.
        !           758:  * The return value is -1 on error, or 0 on success.
        !           759:  */
        !           760: 
        !           761: #if    __USE_PROTO__
        !           762: __LOCAL__ int (SHEAD_RENAME) (shead_t * sheadp, n_dev_t dev)
        !           763: #else
        !           764: __LOCAL__ int
        !           765: SHEAD_RENAME __ARGS ((sheadp, dev))
        !           766: shead_t              * sheadp;
        !           767: n_dev_t                dev;
        !           768: #endif
        !           769: {
        !           770:        pl_t            prev_pl;
        !           771:        shead_t       * scan;
        !           772:        int             ok = 0;         /* flag whether stream is on list */
        !           773:        slist_id_t      id;
        !           774: 
        !           775:        id = SHEAD_ID (sheadp);
        !           776: 
        !           777:        prev_pl = RW_WRLOCK (str_mem->sm_head_lock, plstr);
        !           778: 
        !           779:        for (scan = str_mem->sm_streams [id] ; scan != NULL ;
        !           780:             scan = scan->sh_next) {
        !           781: 
        !           782:                if (scan->sh_dev == dev) {
        !           783:                        /*
        !           784:                         * We have found a conflict. Unlock the list and
        !           785:                         * return an error.
        !           786:                         */
        !           787: 
        !           788:                        RW_UNLOCK (str_mem->sm_head_lock, prev_pl);
        !           789:                        return -1;
        !           790:                }
        !           791: 
        !           792:                if (scan == sheadp)
        !           793:                        ok ++;          /* Ok, we saw the item */
        !           794:        }
        !           795: 
        !           796:        /*
        !           797:         * All OK, now change the name of the original stream head.
        !           798:         */
        !           799: 
        !           800:        sheadp->sh_dev = dev;
        !           801:        RW_UNLOCK (str_mem->sm_head_lock, prev_pl);
        !           802: 
        !           803:        if (! ok)
        !           804:                cmn_err (CE_WARN, "SHEAD_RENAME () of unlisted stream head");
        !           805: 
        !           806:        return 0;
        !           807: }
        !           808: 
        !           809: 
        !           810: /*
        !           811:  * This function decrements the link count of the stream head; this may cause
        !           812:  * the stream head to become unreferened, which means that the memory will be
        !           813:  * reclaimed.
        !           814:  */
        !           815: 
        !           816: #if    __USE_PROTO__
        !           817: __LOCAL__ void (SHEAD_UNREFERENCE) (shead_t * sheadp)
        !           818: #else
        !           819: __LOCAL__ void
        !           820: SHEAD_UNREFERENCE __ARGS ((sheadp))
        !           821: shead_t              * sheadp;
        !           822: #endif
        !           823: {
        !           824:        slist_id_t      id;
        !           825:        int             unlink;
        !           826: 
        !           827:        SHEAD_ASSERT_LOCKED (sheadp);
        !           828:        ASSERT (sheadp == SHEAD_MASTER (sheadp));
        !           829:        ASSERT (sheadp->sh_lock_count > 0);
        !           830: 
        !           831:        id = SHEAD_ID (sheadp);
        !           832: 
        !           833:        /*
        !           834:         * We will delete a stream if there are no references holding it open,
        !           835:         * either pending locks or open references. If this is a stream pipe,
        !           836:         * then we need to check boths ends of the stream pipe. Because this
        !           837:         * function is called from the sleep-locking code, we know that
        !           838:         * "sheadp" points to the master end.
        !           839:         */
        !           840: 
        !           841:        unlink = sheadp->sh_open_count == 0 ||
        !           842:                        (SHEAD_IS_PIPE (sheadp) &&
        !           843:                                SHEAD_M2SLAVE (sheadp->sh_open_count) == 0);
        !           844: 
        !           845:        /*
        !           846:         * We normally assume that we won't be unlinking the stream, because
        !           847:         * to do that we need a lock on a global list (which is more expensive
        !           848:         * that a list on an individual stream).
        !           849:         *
        !           850:         * However, due to the relative hierarchy positions of the locks, if
        !           851:         * we discover we are likely to be the ones to dequeue the item, we
        !           852:         * take out a write lock then.
        !           853:         */
        !           854: 
        !           855:        if (sheadp->sh_lock_count > 1 && ! unlink) {
        !           856:                /*
        !           857:                 * Take the short path out.
        !           858:                 */
        !           859: 
        !           860:                sheadp->sh_lock_count --;
        !           861:                SHEAD_UNLOCK (sheadp, plbase);
        !           862:                return;
        !           863:        }
        !           864: 
        !           865:        /*
        !           866:         * Escalate to a write lock on the stream head; we will need
        !           867:         * to recheck to unlink condition after we escalate.
        !           868:         */
        !           869: 
        !           870:        SHEAD_UNLOCK (sheadp, plbase);
        !           871: 
        !           872:        (void) RW_WRLOCK (str_mem->sm_head_lock, plstr);
        !           873:        (void) SHEAD_LOCK (sheadp);
        !           874: 
        !           875:        unlink = -- sheadp->sh_lock_count == 0 &&
        !           876:                        (sheadp->sh_open_count == 0 ||
        !           877:                         (SHEAD_IS_PIPE (sheadp) &&
        !           878:                          SHEAD_M2SLAVE (sheadp)->sh_open_count == 0));
        !           879: 
        !           880:        SHEAD_UNLOCK (sheadp, plstr);
        !           881: 
        !           882:        if (unlink) {
        !           883:                shead_t       * scan;
        !           884: 
        !           885:                /*
        !           886:                 * Remove from the singly-threaded list by searching for the
        !           887:                 * immediate predecessor entry in the list (if any).
        !           888:                 */
        !           889: 
        !           890:                if ((scan = str_mem->sm_streams [id]) == sheadp)
        !           891:                        str_mem->sm_streams [id] = sheadp->sh_next;
        !           892:                else
        !           893:                        do {
        !           894:                                if (scan->sh_next == sheadp) {
        !           895: 
        !           896:                                        scan->sh_next = sheadp->sh_next;
        !           897:                                        break;
        !           898:                                }
        !           899:                        } while ((scan = scan->sh_next) != NULL);
        !           900: 
        !           901:                if (scan == NULL)
        !           902:                        cmn_err (CE_WARN, "Failure unlinking stream from global directory");
        !           903: 
        !           904:                /*
        !           905:                 * Note that stream pipes consist of four queues and
        !           906:                 * two stream heads!
        !           907:                 */
        !           908: 
        !           909:                SHEAD_DESTROY (sheadp);
        !           910: 
        !           911:                if (SHEAD_IS_PIPE (sheadp))
        !           912:                        QUEUE_FREE (sheadp->sh_head, 4,
        !           913:                                    2 * sizeof (* sheadp));
        !           914:                else
        !           915:                        QUEUE_FREE (sheadp->sh_head, 2, sizeof (* sheadp));
        !           916:        }
        !           917: 
        !           918:        RW_UNLOCK (str_mem->sm_head_lock, plbase);
        !           919: }
        !           920: 
        !           921: 
        !           922: /*
        !           923:  * This function attempts to locate a stream linked below another stream based
        !           924:  * on the multiplexor ID. If the multiplexor ID is -1, then this function
        !           925:  * returns the first stream found linked below the given upper stream. In
        !           926:  * addition, the "cmd" value is used to distinguish between the persistent and
        !           927:  * regular multiplexor ID spaces.
        !           928:  */
        !           929: 
        !           930: #if    __USE_PROTO__
        !           931: __LOCAL__ shead_t * (SHEAD_FIND_MUXID) (shead_t * upper, int cmd,
        !           932:                                        muxid_t muxid)
        !           933: #else
        !           934: __LOCAL__ shead_t *
        !           935: SHEAD_FIND_MUXID __ARGS ((upper, cmd, muxid))
        !           936: shead_t              * upper;
        !           937: int            cmd;
        !           938: muxid_t                muxid;
        !           939: #endif
        !           940: {
        !           941:        shead_t       * scan;
        !           942:        pl_t            prev_pl;
        !           943:        int             checklist;
        !           944: 
        !           945:        /*
        !           946:         * Precook "cmd" for easier testing below.
        !           947:         */
        !           948: 
        !           949:        cmd = (cmd == I_PLINK || cmd == I_PUNLINK) ? SH_PLINK : 0;
        !           950: 
        !           951: 
        !           952:        /*
        !           953:         * Now take out a lock to protect our list walking.
        !           954:         */
        !           955: 
        !           956:        prev_pl = RW_RDLOCK (str_mem->sm_head_lock, plstr);
        !           957: 
        !           958:        for (checklist = DEV_SLIST ; checklist < SLIST_MAX ; checklist ++) {
        !           959: 
        !           960:                for (scan = str_mem->sm_streams [checklist] ; scan != NULL ;
        !           961:                     scan = scan->sh_next) {
        !           962: 
        !           963:                        if (scan->sh_linked == upper &&
        !           964:                            (scan->sh_flags & SH_PLINK) == cmd &&
        !           965:                            ((scan->sh_muxid == muxid) || muxid == -1)) {
        !           966: 
        !           967:                                goto done;
        !           968:                        }
        !           969:                }
        !           970:        }
        !           971: 
        !           972: done:
        !           973:        RW_UNLOCK (str_mem->sm_head_lock, prev_pl);
        !           974: 
        !           975:        return scan;
        !           976: }
        !           977: 
        !           978: 
        !           979: /*
        !           980:  * A local helper function for stream head timeouts.
        !           981:  */
        !           982: 
        !           983: #if    __USE_PROTO__
        !           984: __LOCAL__ void shead_timer_func (_VOID * arg)
        !           985: #else
        !           986: __LOCAL__ void
        !           987: shead_timer_func (arg)
        !           988: _VOID        * arg;
        !           989: #endif
        !           990: {
        !           991:        shead_t       * sheadp = (shead_t *) arg;
        !           992:        unsigned        locks;
        !           993: 
        !           994:        SHEAD_ASSERT_LOCKED (sheadp);
        !           995: 
        !           996:        SV_BROADCAST (sheadp->sh_wait_sv, 0);
        !           997: 
        !           998:        sheadp->sh_lock_mask &= ~ SH_TIMEFLAG;
        !           999:        sheadp->sh_timeout_id = 0;
        !          1000:        sheadp->sh_time_count = 0;
        !          1001: 
        !          1002:        /*
        !          1003:         * Note that we advance "sh_time_count" on behalf of the processes
        !          1004:         * that have the stream head locked.
        !          1005:         */
        !          1006: 
        !          1007:        locks = sheadp->sh_lock_mask & SH_LOCK_MASK;
        !          1008: 
        !          1009:        while (locks != 0) {
        !          1010: 
        !          1011:                if ((locks & 1) != 0)
        !          1012:                        sheadp->sh_time_count ++;
        !          1013:                locks >>= 1;
        !          1014:        }
        !          1015: }
        !          1016: 
        !          1017: 
        !          1018: /*
        !          1019:  * This function is called when the time has come to actually initiate a
        !          1020:  * timeout.
        !          1021:  */
        !          1022: 
        !          1023: #if    __USE_PROTO__
        !          1024: int (SHEAD_START_TIMEOUT) (shead_t * sheadp)
        !          1025: #else
        !          1026: int
        !          1027: SHEAD_START_TIMEOUT __ARGS ((sheadp))
        !          1028: shead_t              * sheadp;
        !          1029: #endif
        !          1030: {
        !          1031:        __clock_t       the_time;
        !          1032: 
        !          1033:        SHEAD_ASSERT_LOCKED (sheadp);
        !          1034: 
        !          1035:        if ((sheadp->sh_lock_mask & SH_TIMEFLAG) == 0 ||
        !          1036:            sheadp->sh_timeout_id != 0)
        !          1037:                return 1;               /* do nothing */
        !          1038: 
        !          1039:        (void) drv_getparm (LBOLT, & the_time);
        !          1040: 
        !          1041:        sheadp->sh_timeout_id = ltimeout (shead_timer_func, sheadp,
        !          1042:                                          sheadp->sh_timeout_tick - the_time,
        !          1043:                                          sheadp->sh_basic_lockp, plstr);
        !          1044: 
        !          1045:        /*
        !          1046:         * If the timeout could not be scheduled, we return 0 to indicate to
        !          1047:         * the caller that it should timeout immediately, and run the timeout
        !          1048:         * function to fake a normal timeout.
        !          1049:         */
        !          1050: 
        !          1051:        if (sheadp->sh_timeout_id == 0) {
        !          1052: 
        !          1053:                shead_timer_func (sheadp);
        !          1054:                return 0;
        !          1055:        }
        !          1056: 
        !          1057:        return 1;
        !          1058: }
        !          1059: 
        !          1060: 
        !          1061: /*
        !          1062:  * Indicate that no timeout will be necessary for this lock item.
        !          1063:  */
        !          1064: 
        !          1065: #if    __USE_PROTO__
        !          1066: void (SHEAD_NO_TIMEOUT) (shead_t * sheadp)
        !          1067: #else
        !          1068: void
        !          1069: SHEAD_NO_TIMEOUT __ARGS ((sheadp))
        !          1070: shead_t              * sheadp;
        !          1071: #endif
        !          1072: {
        !          1073:        SHEAD_ASSERT_LOCKED (sheadp);
        !          1074: 
        !          1075:        ASSERT (sheadp->sh_time_count < sheadp->sh_lock_count);
        !          1076: 
        !          1077:        if (++ sheadp->sh_time_count == sheadp->sh_lock_count) {
        !          1078:                /*
        !          1079:                 * Since we are the last process to register an end time, we
        !          1080:                 * get to actually initiate a timeout for the stream head.
        !          1081:                 */
        !          1082: 
        !          1083:                (void) SHEAD_START_TIMEOUT (sheadp);
        !          1084:        }
        !          1085: }
        !          1086: 
        !          1087: 
        !          1088: /*
        !          1089:  * Indicate that a timeout is desired for this lock item at the given clock
        !          1090:  * tick.
        !          1091:  */
        !          1092: 
        !          1093: #if    __USE_PROTO__
        !          1094: int (SHEAD_LOCK_TIMEOUT) (shead_t * sheadp, __clock_t end_time)
        !          1095: #else
        !          1096: int
        !          1097: SHEAD_LOCK_TIMEOUT __ARGS ((sheadp, end_time))
        !          1098: shead_t              * sheadp;
        !          1099: __clock_t      end_time;
        !          1100: #endif
        !          1101: {
        !          1102:        __clock_t       the_time;
        !          1103: 
        !          1104:        SHEAD_ASSERT_LOCKED (sheadp);
        !          1105: 
        !          1106:        ASSERT (sheadp->sh_time_count < sheadp->sh_lock_count);
        !          1107: 
        !          1108: 
        !          1109:        /*
        !          1110:         * If our horizon falls before the current latest value (or if there
        !          1111:         * is no latest value), select our horizon time. If the horizon time
        !          1112:         * is *before* the current time, return 0.
        !          1113:         *
        !          1114:         * Comparing time values introduces the usual problems when dealing
        !          1115:         * with sequence spaces in C. While the following expression is not
        !          1116:         * as efficient as relying on the semantics of unsigned->signed
        !          1117:         * casting, avoiding implementation-defined behaviour is important.
        !          1118:         *
        !          1119:         * "clock_t" MUST be unsigned for this to work.
        !          1120:         */
        !          1121: 
        !          1122:        ASSERT ((__clock_t) -1 > 0);
        !          1123: 
        !          1124:        (void) drv_getparm (LBOLT, & the_time);
        !          1125: 
        !          1126:        if ((__clock_t) (the_time - end_time) < ((__clock_t) -1 >> 1)) {
        !          1127:                /*
        !          1128:                 * The indicated time has already passed, so we return a
        !          1129:                 * timeout indication directly.
        !          1130:                 */
        !          1131: 
        !          1132:                sheadp->sh_time_count ++;
        !          1133:                return 0;
        !          1134:        }
        !          1135: 
        !          1136: 
        !          1137:        if ((sheadp->sh_lock_mask & SH_TIMEFLAG) == 0 ||
        !          1138:            (__clock_t) (sheadp->sh_timeout_tick - end_time) <
        !          1139:                        ((__clock_t) -1 >> 1)) {
        !          1140:                /*
        !          1141:                 * "end_time" will occur before the current latest time. If
        !          1142:                 * a timeout has been scheduled, we cancel it because we want
        !          1143:                 * to post a more recent one.
        !          1144:                 */
        !          1145: 
        !          1146:                if (sheadp->sh_timeout_id != 0) {
        !          1147: 
        !          1148:                        untimeout (sheadp->sh_timeout_id);
        !          1149:                        sheadp->sh_timeout_id = 0;
        !          1150:                }
        !          1151: 
        !          1152:                sheadp->sh_lock_mask |= SH_TIMEFLAG;
        !          1153:        }
        !          1154: 
        !          1155:        if (++ sheadp->sh_time_count == sheadp->sh_lock_count) {
        !          1156:                /*
        !          1157:                 * Since we are the last process to register an end time, we
        !          1158:                 * get to actually initiate a timeout for the stream head.
        !          1159:                 */
        !          1160: 
        !          1161:                return SHEAD_START_TIMEOUT (sheadp);
        !          1162:        } else {
        !          1163:                /*
        !          1164:                 * We can go to sleep and rely on someone else to actually
        !          1165:                 * intiate the timeout.
        !          1166:                 */
        !          1167: 
        !          1168:                return 1;
        !          1169:        }
        !          1170: }
        !          1171: 
        !          1172: 
        !          1173: /*
        !          1174:  * This function is used when a process wants to cancel a timeout after having
        !          1175:  * registered one.
        !          1176:  */
        !          1177: 
        !          1178: #if    __USE_PROTO__
        !          1179: void (SHEAD_END_TIMEOUT) (shead_t * sheadp)
        !          1180: #else
        !          1181: void
        !          1182: SHEAD_END_TIMEOUT __ARGS ((sheadp))
        !          1183: shead_t              * sheadp;
        !          1184: #endif
        !          1185: {
        !          1186:        SHEAD_ASSERT_LOCKED (sheadp);
        !          1187: 
        !          1188:        if (sheadp->sh_timeout_id != 0) {
        !          1189: 
        !          1190:                ASSERT (sheadp->sh_time_count == sheadp->sh_lock_count + 1);
        !          1191:                sheadp->sh_time_count --;
        !          1192:        }
        !          1193: }
        !          1194: 
        !          1195: 
        !          1196: /*
        !          1197:  * This function is used when a lock holder wishes to sleep waiting for a
        !          1198:  * timeout.
        !          1199:  */
        !          1200: 
        !          1201: #if    __USE_PROTO__
        !          1202: int (SHEAD_LOCKED_TIMEOUT) (shead_t * sheadp, __clock_t end_time)
        !          1203: #else
        !          1204: int
        !          1205: SHEAD_LOCKED_TIMEOUT __ARGS ((sheadp, end_time))
        !          1206: shead_t              * sheadp;
        !          1207: __clock_t      end_time;
        !          1208: #endif
        !          1209: {
        !          1210:        SHEAD_ASSERT_LOCKED (sheadp);
        !          1211: 
        !          1212:        ASSERT (sheadp->sh_time_count > 0);
        !          1213: 
        !          1214:        sheadp->sh_time_count --;
        !          1215: 
        !          1216:        return SHEAD_LOCK_TIMEOUT (sheadp, end_time);
        !          1217: }
        !          1218: 
        !          1219: 
        !          1220: /*
        !          1221:  * Common code to test whether a stream has experienced an error condition.
        !          1222:  */
        !          1223: 
        !          1224: #define        _shead_error(sheadp,mode) \
        !          1225:                (SHEAD_ASSERT_LOCKED (sheadp), \
        !          1226:                 sheadp->sh_linked != NULL ? EINVAL : \
        !          1227:                   ((mode) & FWRITE) != 0 && sheadp->sh_werrcode != 0 ? \
        !          1228:                        sheadp->sh_werrcode : \
        !          1229:                     ((mode) & FREAD) != 0 ? sheadp->sh_rerrcode : 0)
        !          1230: 
        !          1231: /*
        !          1232:  * This function tests for error or hangup conditions on the stream head given
        !          1233:  * by "sheadp". It assumes that the caller holds a basic lock on the stream
        !          1234:  * head. If an error or hangup condition exists then the basic lock is
        !          1235:  * unlocked and a non-zero error number is returned.
        !          1236:  */
        !          1237: 
        !          1238: #if    __USE_PROTO__
        !          1239: __LOCAL__ int (SHEAD_ERRHUP_LOCKED) (shead_t * sheadp, int mode)
        !          1240: #else
        !          1241: __LOCAL__ int
        !          1242: SHEAD_ERRHUP_LOCKED __ARGS ((sheadp, mode))
        !          1243: shead_t              * sheadp;
        !          1244: int            mode;
        !          1245: #endif
        !          1246: {
        !          1247:        int             retval;
        !          1248: 
        !          1249:        SHEAD_ASSERT_LOCKED (sheadp);
        !          1250: 
        !          1251:        if ((retval = _shead_error (sheadp, mode)) != 0 ||
        !          1252:            ((mode & (FREAD | FWRITE)) != 0 &&
        !          1253:                    (retval = ENXIO, SHEAD_HANGUP (sheadp) != 0))) {
        !          1254: 
        !          1255:                SHEAD_UNLOCK (sheadp, plbase);
        !          1256:                return retval;
        !          1257:        }
        !          1258: 
        !          1259:        return 0;
        !          1260: }
        !          1261: 
        !          1262: 
        !          1263: /*
        !          1264:  * Definitions use for the "interruptible" parameter to SHEAD_WAIT () and
        !          1265:  * SHEAD_LOCK ().
        !          1266:  */
        !          1267: 
        !          1268: enum {
        !          1269:        DONT_SIGNAL = 0,
        !          1270:        CHECK_SIGNALS = 1
        !          1271: };
        !          1272: 
        !          1273: 
        !          1274: /*
        !          1275:  * This function is the common interface to waiting for an event at a stream
        !          1276:  * head. It borrows the same synchronization variable used by the stream head
        !          1277:  * locking code in this implementation.
        !          1278:  *
        !          1279:  * We return 0 on success or an error number on failure.
        !          1280:  */
        !          1281: 
        !          1282: #if    __USE_PROTO__
        !          1283: __LOCAL__ int (SHEAD_WAIT) (shead_t * sheadp, int mode, cat_t category,
        !          1284:                            int interruptible)
        !          1285: #else
        !          1286: __LOCAL__ int
        !          1287: SHEAD_WAIT __ARGS ((sheadp, mode, category, interruptible))
        !          1288: shead_t              * sheadp;
        !          1289: int            mode;
        !          1290: cat_t          category;
        !          1291: int            interruptible;
        !          1292: #endif
        !          1293: {
        !          1294:        int             retval;
        !          1295: 
        !          1296:        SHEAD_ASSERT_LOCKED (sheadp);
        !          1297: 
        !          1298:        /*
        !          1299:         * Test for error/hangup conditions before we sleep.
        !          1300:         */
        !          1301: 
        !          1302:        if ((retval = SHEAD_ERRHUP_LOCKED (sheadp, mode)) != 0)
        !          1303:                return retval;
        !          1304: 
        !          1305:        /*
        !          1306:         * Register our interest in the kind of event that we are waiting for.
        !          1307:         */
        !          1308: 
        !          1309:        sheadp->sh_lock_mask |= category;
        !          1310: 
        !          1311:        if (interruptible == CHECK_SIGNALS)
        !          1312:                return SV_WAIT_SIG (sheadp->sh_wait_sv, primed,
        !          1313:                                    sheadp->sh_basic_lockp) == 0 ? EINTR : 0;
        !          1314:        else {
        !          1315:                SV_WAIT (sheadp->sh_wait_sv, primed, sheadp->sh_basic_lockp);
        !          1316:                return 0;
        !          1317:        }
        !          1318: }
        !          1319: 
        !          1320: 
        !          1321: /*
        !          1322:  * This function is a slightly different interface to SHEAD_WAIT (), used when
        !          1323:  * the caller has been examining some property of a queue and wishes to go
        !          1324:  * to sleep atomically. A frozen queue is not suitable for passing to
        !          1325:  * SV_WAIT_SIG (), so we acquire the stream head global lock and then unfreeze
        !          1326:  * the queue on behalf of the caller. This yields correct behaviour because
        !          1327:  * SHEAD_WAKE () also attempts to acquire the stream head global lock; any
        !          1328:  * modification to a stream queue resulting in a wakeup request will follow
        !          1329:  * the same locking sequence.
        !          1330:  */
        !          1331: 
        !          1332: #if    __USE_PROTO__
        !          1333: __LOCAL__ int (SHEAD_WAIT_NONBLOCK) (shead_t * sheadp, int mode,
        !          1334:                                     cat_t category, int interruptible)
        !          1335: #else
        !          1336: __LOCAL__ int
        !          1337: SHEAD_WAIT_NONBLOCK __ARGS ((sheadp, mode, category, interruptible))
        !          1338: shead_t              * sheadp;
        !          1339: int            mode;
        !          1340: cat_t          category;
        !          1341: int            interruptible;
        !          1342: #endif
        !          1343: {
        !          1344:        SHEAD_ASSERT_LOCKED (sheadp);
        !          1345: 
        !          1346:        if ((mode & (FNDELAY | FNONBLOCK)) != 0) {
        !          1347: 
        !          1348:                SHEAD_UNLOCK (sheadp, plbase);
        !          1349:                return EAGAIN;
        !          1350:        }
        !          1351: 
        !          1352:        return SHEAD_WAIT (sheadp, mode, category, interruptible);
        !          1353: }
        !          1354: 
        !          1355: 
        !          1356: /*
        !          1357:  * This function is used by lower-level code to signal events to functions
        !          1358:  * that have waited via SHEAD_WAIT (), above.
        !          1359:  */
        !          1360: 
        !          1361: #if    __USE_PROTO__
        !          1362: void (SHEAD_WAKE) (shead_t * sheadp, cat_t category)
        !          1363: #else
        !          1364: void
        !          1365: SHEAD_WAKE __ARGS ((sheadp, category))
        !          1366: shead_t              * sheadp;
        !          1367: cat_t          category;
        !          1368: #endif
        !          1369: {
        !          1370:        pl_t            prev_pl;
        !          1371: 
        !          1372:        prev_pl = SHEAD_LOCK (sheadp);
        !          1373: 
        !          1374:        if ((sheadp->sh_lock_mask & category) != 0) {
        !          1375: 
        !          1376:                sheadp->sh_lock_mask &= ~ category;
        !          1377:                SV_BROADCAST (sheadp->sh_wait_sv, 0);
        !          1378:        }
        !          1379: 
        !          1380:        SHEAD_UNLOCK (sheadp, prev_pl);
        !          1381: }
        !          1382: 
        !          1383: 
        !          1384: /*
        !          1385:  * Common code for locking stream head, shared between open-style locks (which
        !          1386:  * may need to allocate new head structures and need special coordination
        !          1387:  * with the stream head destruction code) and other kinds.
        !          1388:  *
        !          1389:  * We expect that the caller will have taken out a basic lock on the stream
        !          1390:  * head and that the caller will have incremented the lock count of the item
        !          1391:  * to prevent it from being deallocated while we wait.
        !          1392:  */
        !          1393: 
        !          1394: #if    __USE_PROTO__
        !          1395: int (SHEAD_SLEEP_LOCKED) (shead_t * sheadp, cat_t category, __clock_t timeout,
        !          1396:                          int interruptible)
        !          1397: #else
        !          1398: int
        !          1399: SHEAD_SLEEP_LOCKED __ARGS ((sheadp, category, timeout, interruptible))
        !          1400: shead_t              * sheadp;
        !          1401: cat_t          category;
        !          1402: __clock_t      timeout;
        !          1403: int            interruptible;
        !          1404: #endif
        !          1405: {
        !          1406:        __clock_t       end_time;       /* LBOLT when we time out */
        !          1407:        n_dev_t         devno;
        !          1408:        int             retval;
        !          1409: 
        !          1410:        SHEAD_ASSERT_LOCKED (sheadp);
        !          1411: 
        !          1412:        /*
        !          1413:         * Since we expect the caller to have incremented the lock count, then
        !          1414:         * the caller must have selected the master end of the stream pipe.
        !          1415:         */
        !          1416: 
        !          1417:        ASSERT (sheadp == SHEAD_MASTER (sheadp));
        !          1418: 
        !          1419:        /*
        !          1420:         * If we are going to be (possibly) timing out, calculate the time
        !          1421:         * when that will happen.
        !          1422:         */
        !          1423: 
        !          1424:        if (timeout > 0) {
        !          1425: 
        !          1426:                (void) drv_getparm (LBOLT, & end_time);
        !          1427:                end_time += timeout;
        !          1428:        }
        !          1429: 
        !          1430: 
        !          1431:        /*
        !          1432:         * There is a special case that we have to note; in the case of a
        !          1433:         * clone open, the device number of a stream head may be altered by
        !          1434:         * the driver open routine. In this case, drivers waiting on the old
        !          1435:         * number will have to be notified and give up on their lock attempts.
        !          1436:         */
        !          1437: 
        !          1438:        devno = sheadp->sh_dev;
        !          1439: 
        !          1440: 
        !          1441:        /*
        !          1442:         * Now we begin the actual business of locking the stream head.
        !          1443:         */
        !          1444: 
        !          1445:        for (;;) {
        !          1446:                int             sigflg;
        !          1447: 
        !          1448:                /*
        !          1449:                 * Check to see whether our category is blocked. At this point
        !          1450:                 * we hold "global_lock".
        !          1451:                 *
        !          1452:                 * An earlier verson of this code had an explicit check for
        !          1453:                 * final close. I have no idea why, because if a stream is in
        !          1454:                 * final close, what else can happen?
        !          1455:                 */
        !          1456: 
        !          1457:                if ((sheadp->sh_lock_mask & category) == 0) {
        !          1458:                        /*
        !          1459:                         * We can acquire a lock on the stream head in our
        !          1460:                         * chosen category, so we do so. Since we will not
        !          1461:                         * need a timeout, we increment the timeout count.
        !          1462:                         *
        !          1463:                         * If during later processing we need a timeout, we
        !          1464:                         * hook into this mechanism, but for simplicity we
        !          1465:                         * assume we won't.
        !          1466:                         */
        !          1467: 
        !          1468:                        SHEAD_NO_TIMEOUT (sheadp);
        !          1469: 
        !          1470:                        SHEAD_UNLOCK (sheadp, plbase);
        !          1471: 
        !          1472:                        sheadp->sh_lock_mask |= category;
        !          1473: 
        !          1474:                        return 0;
        !          1475:                }
        !          1476: 
        !          1477: 
        !          1478:                /*
        !          1479:                 * We need to wait, interruptibly. We might also want to time
        !          1480:                 * out at some stage.
        !          1481:                 *
        !          1482:                 * We (optionally) call a function to register the time we
        !          1483:                 * want to expire; this function also takes care of checking
        !          1484:                 * for timeout expiry.
        !          1485:                 */
        !          1486: 
        !          1487:                if (timeout == 0)
        !          1488:                        SHEAD_NO_TIMEOUT (sheadp);
        !          1489:                else if (SHEAD_LOCK_TIMEOUT (sheadp, end_time) == 0) {
        !          1490:                        /*
        !          1491:                         * Our horizon time has passed, so we return ETIME.
        !          1492:                         */
        !          1493: 
        !          1494:                        retval = ETIME;
        !          1495:                        break;
        !          1496:                }
        !          1497: 
        !          1498: 
        !          1499:                /*
        !          1500:                 * Now we can wait. No matter how we wake up, we will need
        !          1501:                 * to relock the global basic lock.
        !          1502:                 *
        !          1503:                 * The caller may not want this wait to be interruptible; this
        !          1504:                 * is reasonable when the lock is being acquired in some
        !          1505:                 * nested context where things are difficult to back out.
        !          1506:                 */
        !          1507: 
        !          1508:                if (interruptible != DONT_SIGNAL)
        !          1509:                        sigflg = SV_WAIT_SIG (sheadp->sh_wait_sv, primed,
        !          1510:                                              sheadp->sh_basic_lockp);
        !          1511:                else {
        !          1512:                        SV_WAIT (sheadp->sh_wait_sv, primed,
        !          1513:                                 sheadp->sh_basic_lockp);
        !          1514:                        sigflg = 1;
        !          1515:                }
        !          1516: 
        !          1517:                (void) SHEAD_LOCK (sheadp);
        !          1518: 
        !          1519:                if (sigflg == 0) {
        !          1520:                        /*
        !          1521:                         * We have been interrupted by a signal, so bang out
        !          1522:                         * to the caller with EINTR.
        !          1523:                         */
        !          1524: 
        !          1525:                        retval = EINTR;
        !          1526:                        break;
        !          1527:                } else if (sheadp->sh_dev != devno) {
        !          1528:                        /*
        !          1529:                         * The device number has been altered. Flag the fact
        !          1530:                         * to the caller and give up this lock attempt.
        !          1531:                         */
        !          1532: 
        !          1533:                        retval = ENODEV;
        !          1534:                        break;
        !          1535:                }
        !          1536: 
        !          1537: 
        !          1538:                /*
        !          1539:                 * Now we have the global basic lock, we can wrap around to
        !          1540:                 * the start of the loop to recheck all our conditions.
        !          1541:                 */
        !          1542:        }
        !          1543: 
        !          1544: 
        !          1545:        /*
        !          1546:         * For some reason we are aborting the lock attempt. The code which
        !          1547:         * make us take this exit path should have set "* retvalp" with an
        !          1548:         * error code.
        !          1549:         */
        !          1550: 
        !          1551:        if (sheadp->sh_time_count > sheadp->sh_lock_count) {
        !          1552: 
        !          1553:                sheadp->sh_time_count --;
        !          1554:                ASSERT (sheadp->sh_time_count == sheadp->sh_lock_count);
        !          1555: 
        !          1556:                SHEAD_START_TIMEOUT (sheadp);
        !          1557:        }
        !          1558: 
        !          1559:        SHEAD_UNREFERENCE (sheadp);
        !          1560:        return retval;
        !          1561: }
        !          1562: 
        !          1563: 
        !          1564: /*
        !          1565:  * Entry point for the stream head locking system for use by routines that
        !          1566:  * already have a reference to the stream head. This entry performs checks for
        !          1567:  * routine errors including linked streams.
        !          1568:  */
        !          1569: 
        !          1570: #if    __USE_PROTO__
        !          1571: int (SHEAD_SLEEP_LOCK) (shead_t * sheadp, cat_t category, __clock_t timeout,
        !          1572:                        int interruptible)
        !          1573: #else
        !          1574: int
        !          1575: SHEAD_SLEEP_LOCK __ARGS ((sheadp, category, timeout, interruptible))
        !          1576: shead_t              * sheadp;
        !          1577: cat_t          category;
        !          1578: __clock_t      timeout;
        !          1579: int            interruptible;
        !          1580: #endif
        !          1581: {
        !          1582:        SHEAD_LOCK (sheadp);
        !          1583: 
        !          1584:        /*
        !          1585:         * The read and write lock modes are experimental. We have a mode bit
        !          1586:         * that says whether or not we are really interested in honouring
        !          1587:         * these lock types.
        !          1588:         */
        !          1589: 
        !          1590:        if (((sheadp->sh_flags & SH_RWLOCKING) == 0 &&
        !          1591:             (category & ~ (SH_READ_LOCK | SH_WRITE_LOCK)) == 0)) {
        !          1592: 
        !          1593:                SHEAD_UNLOCK (sheadp, plbase);
        !          1594:                return 0;
        !          1595:        }
        !          1596: 
        !          1597: 
        !          1598:        /*
        !          1599:         * If the caller wishes to lock a stream head that is part of a stream
        !          1600:         * pipe, we direct the lock attempt to the master stream head of the
        !          1601:         * pair that form the pipe. This ensures that any attempt to modify
        !          1602:         * the state of the pipe from either end will be properly single-
        !          1603:         * threaded.
        !          1604:         *
        !          1605:         * Note that we *must* perform a similar redirection in the unlock.
        !          1606:         */
        !          1607: 
        !          1608:        sheadp = SHEAD_MASTER (sheadp);
        !          1609: 
        !          1610: 
        !          1611:        /*
        !          1612:         * We have a pointer to the stream head and hold a global basic lock.
        !          1613:         *
        !          1614:         * With the protection of the basic lock, we increment the lock count.
        !          1615:         */
        !          1616: 
        !          1617:        sheadp->sh_lock_count ++;
        !          1618: 
        !          1619:        /*
        !          1620:         * Now we begin the actual business of locking the stream head.
        !          1621:         */
        !          1622: 
        !          1623:        return SHEAD_SLEEP_LOCKED (sheadp, category, timeout, interruptible);
        !          1624: }
        !          1625: 
        !          1626: 
        !          1627: /*
        !          1628:  * This is a special form of the stream head locking code for open () access,
        !          1629:  * which specially coordinates with the close code to discover when to
        !          1630:  * allocate a new stream head, and carefully avoids the problems that can
        !          1631:  * occur if the stream head were to be deallocated which we are waiting for
        !          1632:  * it to be unlocked.
        !          1633:  *
        !          1634:  * We also have to do some funky stuff here because of clone opens.
        !          1635:  */
        !          1636: 
        !          1637: #if    __USE_PROTO__
        !          1638: shead_t * (SHEAD_OPEN_LOCK) (n_dev_t dev, struct streamtab * stabp,
        !          1639:                             int * retvalp)
        !          1640: #else
        !          1641: shead_t *
        !          1642: SHEAD_OPEN_LOCK __ARGS ((dev, stabp, retvalp))
        !          1643: n_dev_t                dev;
        !          1644: struct streamtab
        !          1645:              * stabp;
        !          1646: int          * retvalp;
        !          1647: #endif
        !          1648: {
        !          1649:        shead_t       * sheadp;
        !          1650: 
        !          1651:        ASSERT (retvalp != NULL);
        !          1652: 
        !          1653:        /*
        !          1654:         * PHASE 1: Locate the stream head. If the stream head did not
        !          1655:         * previously exist, we might be able to lock it immediately by virtue
        !          1656:         * of being able to create it that way. Of course, simultaneous open
        !          1657:         * attempts might result in this looping as only once of the created
        !          1658:         * stream heads will be entered in the stream directory.
        !          1659:         */
        !          1660: 
        !          1661:        * retvalp = 0;
        !          1662: 
        !          1663:        for (;;) {
        !          1664:                queue_t       * q;
        !          1665: 
        !          1666:                /*
        !          1667:                 * The first thing we need to do is *find* the stream. We call
        !          1668:                 * a find routine that increments a reference count so that
        !          1669:                 * we can be sure that the stream will not be deallocated
        !          1670:                 * while we wait.
        !          1671:                 */
        !          1672: 
        !          1673:                if ((sheadp = SHEAD_FIND_AND_LOCK (dev, DEV_SLIST)) != NULL) {
        !          1674:                        /*
        !          1675:                         * Sleep lock time; our call to SHEAD_FIND_AND_LOCK ()
        !          1676:                         * will have incremented the lock count of the stream
        !          1677:                         * head so it won't disappear underneath us.
        !          1678:                         */
        !          1679: 
        !          1680:                        * retvalp = SHEAD_SLEEP_LOCKED (sheadp, SH_OPENCLOSE,
        !          1681:                                                        0, CHECK_SIGNALS);
        !          1682: 
        !          1683:                        if (retvalp != 0) {
        !          1684:                                /*
        !          1685:                                 * If the lock attempt failed because of a
        !          1686:                                 * clone open changing the stream head's
        !          1687:                                 * device number, we need to try again.
        !          1688:                                 */
        !          1689: 
        !          1690:                                sheadp = NULL;
        !          1691: 
        !          1692:                                if (* retvalp == ENODEV)
        !          1693:                                        continue;
        !          1694:                        }
        !          1695: 
        !          1696:                        return sheadp;
        !          1697:                }
        !          1698: 
        !          1699: 
        !          1700:                /*
        !          1701:                 * There ain't no such stream, so we have to allocate a queue
        !          1702:                 * pair.
        !          1703:                 */
        !          1704: 
        !          1705:                if ((q = QUEUE_ALLOC (2, sizeof (* sheadp))) == NULL) {
        !          1706: 
        !          1707:                        * retvalp = ENFILE;
        !          1708:                        return NULL;
        !          1709:                }
        !          1710: 
        !          1711:                sheadp = (shead_t *) q->q_ptr;
        !          1712: 
        !          1713:                SHEAD_INIT (sheadp, stabp, dev, q);
        !          1714: 
        !          1715:                sheadp->sh_ref_count = 1;
        !          1716:                sheadp->sh_lock_mask = SH_OPENCLOSE;
        !          1717:                sheadp->sh_time_count = sheadp->sh_lock_count = 1;
        !          1718: 
        !          1719:                if (SHEAD_ADD (sheadp) == 0)
        !          1720:                        return sheadp;
        !          1721: 
        !          1722:                /*
        !          1723:                 * The new queue could not be added to the stream
        !          1724:                 * directory, presumably because of a nearly
        !          1725:                 * simultaneous open attempt.
        !          1726:                 *
        !          1727:                 * We undo the allocation we wrought before retrying.
        !          1728:                 */
        !          1729: 
        !          1730:                SHEAD_DESTROY (sheadp);
        !          1731:                QUEUE_FREE (q, 2, sizeof (* sheadp));
        !          1732:        }
        !          1733: }
        !          1734: 
        !          1735: 
        !          1736: /*
        !          1737:  * Unlock a stream head.
        !          1738:  */
        !          1739: 
        !          1740: #if    __USE_PROTO__
        !          1741: void (SHEAD_SLEEP_UNLOCK) (shead_t * sheadp, cat_t category)
        !          1742: #else
        !          1743: void
        !          1744: SHEAD_SLEEP_UNLOCK __ARGS ((sheadp, category))
        !          1745: shead_t              * sheadp;
        !          1746: cat_t          category;
        !          1747: #endif
        !          1748: {
        !          1749:        ASSERT (sheadp != NULL);
        !          1750:        ASSERT (category != 0);
        !          1751: 
        !          1752:        /*
        !          1753:         * See if locking is necessary for the read and write operations.
        !          1754:         */
        !          1755: 
        !          1756:        if ((sheadp->sh_flags & SH_RWLOCKING) == 0 &&
        !          1757:            (category & ~ (SH_READ_LOCK | SH_WRITE_LOCK)) == 0) {
        !          1758:                /*
        !          1759:                 * Since we don't actually acquire any locks, we return early.
        !          1760:                 */
        !          1761: 
        !          1762:                ASSERT (sheadp->sh_open_count > 0);
        !          1763:                return;
        !          1764:        }
        !          1765: 
        !          1766:        ASSERT (sheadp->sh_lock_count > 0);
        !          1767:        ASSERT ((sheadp->sh_lock_mask & category) == category);
        !          1768: 
        !          1769: 
        !          1770:        /*
        !          1771:         * We direct all locking operations on the slave part of a stream pipe
        !          1772:         * to the master end.
        !          1773:         */
        !          1774: 
        !          1775:        sheadp = SHEAD_MASTER (sheadp);
        !          1776: 
        !          1777:        (void) SHEAD_LOCK (sheadp);
        !          1778: 
        !          1779: 
        !          1780:        /*
        !          1781:         * Unlike SHEAD_WAKE (), we can assume that our category mask will not
        !          1782:         * be NULL because of the difference in interpretation between lock
        !          1783:         * flags (indicating a holder) and wait flags (indicating a waiter).
        !          1784:         */
        !          1785: 
        !          1786:        sheadp->sh_lock_mask &= ~ category;
        !          1787:        SV_BROADCAST (sheadp->sh_wait_sv, 0);
        !          1788: 
        !          1789: 
        !          1790:        /*
        !          1791:         * We don't use SHEAD_END_TIMEOUT () here since we are a lock holder
        !          1792:         * and shead_time_func () makes sure to keep our "sh_time_count" entry
        !          1793:         * greater than 0.
        !          1794:         */
        !          1795: 
        !          1796:        ASSERT (sheadp->sh_time_count > 0);
        !          1797:        sheadp->sh_time_count --;
        !          1798: 
        !          1799:        if (sheadp->sh_time_count == 0 && sheadp->sh_timeout_id != 0) {
        !          1800:                /*
        !          1801:                 * Since there is no-one waiting for anything, cancel any
        !          1802:                 * pending timeouts.
        !          1803:                 */
        !          1804: 
        !          1805:                untimeout (sheadp->sh_timeout_id);
        !          1806: 
        !          1807:                sheadp->sh_lock_mask &= SH_TIMEFLAG;
        !          1808:                sheadp->sh_timeout_id = 0;
        !          1809:        }
        !          1810: 
        !          1811: 
        !          1812:        /*
        !          1813:         * Now that we have done everything that requires access to the stream
        !          1814:         * head, decrement the lock count.
        !          1815:         */
        !          1816: 
        !          1817:         SHEAD_UNREFERENCE (sheadp);
        !          1818: }
        !          1819: 
        !          1820: 
        !          1821: /*
        !          1822:  * This local function asserts that the caller holds a lock on the stream head.
        !          1823:  * Since we can't really determine that, we actually just assert that someone
        !          1824:  * has a lock on the stream head.
        !          1825:  */
        !          1826: 
        !          1827: #if    __USE_PROTO__
        !          1828: __LOCAL__ void (ASSERT_SLEEP_LOCKED) (shead_t * sheadp, cat_t category)
        !          1829: #else
        !          1830: __LOCAL__ void
        !          1831: ASSERT_SLEEP_LOCKED __ARGS ((sheadp, category))
        !          1832: shead_t              * sheadp;
        !          1833: cat_t          category;
        !          1834: #endif
        !          1835: {
        !          1836:        ASSERT (sheadp != NULL);
        !          1837: 
        !          1838:        if (SHEAD_IS_PIPE (sheadp))
        !          1839:                sheadp = SHEAD_MASTER (sheadp);
        !          1840: 
        !          1841:        ASSERT ((sheadp->sh_lock_mask & category) == category);
        !          1842: }
        !          1843: 
        !          1844: 
        !          1845: /*
        !          1846:  * Wait for a queue to drain. The caller must have the stream head locked when
        !          1847:  * calling this function.
        !          1848:  */
        !          1849: 
        !          1850: #if    __USE_PROTO__
        !          1851: __LOCAL__ void (DRAIN_QUEUE) (shead_t * sheadp, queue_t * q)
        !          1852: #else
        !          1853: __LOCAL__ void
        !          1854: DRAIN_QUEUE __ARGS ((sheadp, q))
        !          1855: shead_t              * sheadp;
        !          1856: queue_t              * q;
        !          1857: #endif
        !          1858: {
        !          1859:        __clock_t       end_time;
        !          1860: 
        !          1861:        ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE);
        !          1862: 
        !          1863:        /*
        !          1864:         * When we are in final close, the STREAMS specification says we
        !          1865:         * should wait for up to 15 seconds for the write-side queue to be
        !          1866:         * drained of data, unless we are in O_NONBLOCK mode.
        !          1867:         *
        !          1868:         * If we can't post the timeout, then don't wait.
        !          1869:         */
        !          1870: 
        !          1871:        if (sheadp->sh_cltime == 0)
        !          1872:                return;
        !          1873: 
        !          1874:        (void) drv_getparm (LBOLT, & end_time);
        !          1875:        end_time += sheadp->sh_cltime;
        !          1876: 
        !          1877:        for (;;) {
        !          1878:                /*
        !          1879:                 * We need to acquire a basic lock to pass to SV_WAIT (), and
        !          1880:                 * the code that wakes us up will attempt to acquire the same
        !          1881:                 * lock (see QUEUE_DRAINED ()). Since the wakeup code must
        !          1882:                 * acquire the lock while holding the stream frozen, we must
        !          1883:                 * do things in the same order to prevent the possibility of
        !          1884:                 * deadlock.
        !          1885:                 */
        !          1886: 
        !          1887:                (void) QFREEZE_TRACE (q, "DRAIN_QUEUE");
        !          1888: 
        !          1889:                if (q->q_first == NULL) {
        !          1890:                        /*
        !          1891:                         * No messages on the queue => our job is done.
        !          1892:                         */
        !          1893: 
        !          1894:                        QUNFREEZE_TRACE (q, plbase);
        !          1895:                        break;
        !          1896:                }
        !          1897: 
        !          1898: 
        !          1899:                /*
        !          1900:                 * We are going to wait for this queue to become empty, so we
        !          1901:                 * set a flag to indicate that we are interested in finding
        !          1902:                 * out when that happens. Note that we don't ever clear the
        !          1903:                 * flag in this routine; that is the responsibility of the
        !          1904:                 * code which will wake us up.
        !          1905:                 */
        !          1906: 
        !          1907:                q->q_flag |= QDRAIN;
        !          1908: 
        !          1909: 
        !          1910:                /*
        !          1911:                 * We don't build on SHEAD_WAIT (), although we do expect to
        !          1912:                 * be woken up via SHEAD_WAKE (). We transfer our lock from
        !          1913:                 * the queue to the stream head.
        !          1914:                 */
        !          1915: 
        !          1916:                (void) SHEAD_LOCK (sheadp);
        !          1917: 
        !          1918:                QUNFREEZE_TRACE (q, plstr);
        !          1919: 
        !          1920: 
        !          1921:                /*
        !          1922:                 * Register when we want to time out. If that time has already
        !          1923:                 * passed, then exit to the caller.
        !          1924:                 */
        !          1925: 
        !          1926:                if (SHEAD_LOCKED_TIMEOUT (sheadp, end_time) == 0) {
        !          1927: 
        !          1928:                        SHEAD_UNLOCK (sheadp, plbase);
        !          1929:                        return;
        !          1930:                }
        !          1931: 
        !          1932:                sheadp->sh_lock_mask |= SH_DRAIN_WAIT;
        !          1933: 
        !          1934:                SV_WAIT (sheadp->sh_wait_sv, primed, sheadp->sh_basic_lockp);
        !          1935: 
        !          1936:                /*
        !          1937:                 * We were signalled, so we try again.
        !          1938:                 */
        !          1939:        }
        !          1940: }
        !          1941: 
        !          1942: 
        !          1943: /*
        !          1944:  * This function (used in the implementation of I_LIST ioctl ()) returns a
        !          1945:  * count of the number of modules on the stream, including the topmost driver.
        !          1946:  */
        !          1947: 
        !          1948: #if    __USE_PROTO__
        !          1949: __LOCAL__ int (SHEAD_MODCOUNT) (shead_t * sheadp)
        !          1950: #else
        !          1951: __LOCAL__ int
        !          1952: SHEAD_MODCOUNT __ARGS ((sheadp))
        !          1953: shead_t              * sheadp;
        !          1954: #endif
        !          1955: {
        !          1956:        pl_t            prev_pl;
        !          1957:        int             count;
        !          1958:        queue_t       * scan;
        !          1959: 
        !          1960:        ASSERT (sheadp != NULL);
        !          1961: 
        !          1962:        /*
        !          1963:         * Note that we use SHEAD_MASTER () because this walk can be affected
        !          1964:         * by attempts to push or pop queues from either end of a stream pipe.
        !          1965:         * Using a single lock at the master end avoids problems with this.
        !          1966:         */
        !          1967: 
        !          1968:        prev_pl = SHEAD_LOCK (SHEAD_MASTER (sheadp));
        !          1969: 
        !          1970:        count = 0;
        !          1971: 
        !          1972:        for (scan = W (sheadp->sh_head)->q_next ; scan != NULL ;
        !          1973:             scan = scan->q_next) {
        !          1974: 
        !          1975:                if ((scan->q_flag & QPROCSOFF) == 0)
        !          1976:                        count ++;
        !          1977:        }
        !          1978: 
        !          1979:        SHEAD_UNLOCK (SHEAD_MASTER (sheadp), prev_pl);
        !          1980: 
        !          1981:        return count;
        !          1982: }
        !          1983: 
        !          1984: 
        !          1985: /*
        !          1986:  * Utility routine to return the next write queue below the stream head. This
        !          1987:  * routine deals with locking the stream head for the duration of the walk and
        !          1988:  * also check whether the queue has been disabled with qprocsoff ().
        !          1989:  */
        !          1990: 
        !          1991: #if    __USE_PROTO__
        !          1992: __LOCAL__ queue_t * (TOP_QUEUE) (shead_t * sheadp)
        !          1993: #else
        !          1994: __LOCAL__ queue_t *
        !          1995: TOP_QUEUE __ARGS ((sheadp))
        !          1996: shead_t              * sheadp;
        !          1997: #endif
        !          1998: {
        !          1999:        pl_t            prev_pl;
        !          2000:        queue_t       * scan;
        !          2001: 
        !          2002:        ASSERT (sheadp != NULL);
        !          2003: 
        !          2004:        /*
        !          2005:         * Note that we use SHEAD_MASTER () because this walk can be affected
        !          2006:         * by attempts to push or pop queues from either end of a stream pipe.
        !          2007:         * Using a single lock at the master end avoids problems with this.
        !          2008:         */
        !          2009: 
        !          2010:        prev_pl = SHEAD_LOCK (SHEAD_MASTER (sheadp));
        !          2011: 
        !          2012:        scan = W (sheadp->sh_head)->q_next;
        !          2013: 
        !          2014:        while ((scan->q_flag & QPROCSOFF) != 0)
        !          2015:                if ((scan = scan->q_next) == NULL)
        !          2016:                        cmn_err (CE_PANIC, "Off end of stream in TOP_QUEUE ()");
        !          2017: 
        !          2018:        SHEAD_UNLOCK (SHEAD_MASTER (sheadp), prev_pl);
        !          2019: 
        !          2020:        return scan;
        !          2021: }
        !          2022: 
        !          2023: 
        !          2024: /*
        !          2025:  * Utility routine for POP_MODULE () and the I_LOOK processing code that finds
        !          2026:  * the queue entry for the first module on the stream (if any).
        !          2027:  */
        !          2028: 
        !          2029: #if    __USE_PROTO__
        !          2030: __LOCAL__ queue_t * (TOP_MODULE) (shead_t * sheadp)
        !          2031: #else
        !          2032: __LOCAL__ queue_t *
        !          2033: TOP_MODULE __ARGS ((sheadp))
        !          2034: shead_t              * sheadp;
        !          2035: #endif
        !          2036: {
        !          2037:        queue_t       * scan;           /* module queue */
        !          2038: 
        !          2039:        /*
        !          2040:         * We return the queue pointer if and only if the thing below the
        !          2041:         * stream head is a module (not a driver) AND the module's read and
        !          2042:         * write queues are not interchanged (as they would be at the
        !          2043:         * crossover point of a STREAMS-based FIFO).
        !          2044:         */
        !          2045: 
        !          2046:        scan = TOP_QUEUE (sheadp);
        !          2047: 
        !          2048:        if ((scan->q_flag & QREADR) !=
        !          2049:                        (W (sheadp->sh_head)->q_flag & QREADR))
        !          2050:                return NULL;
        !          2051: 
        !          2052:        /*
        !          2053:         * The test to see whether "scan" is a module or driver does not need
        !          2054:         * to involve QUEUE_NEXT (), since the exact value of 'q->q_next'
        !          2055:         * isn't important to us, just whether or not it's NULL.
        !          2056:         */
        !          2057: 
        !          2058:        {
        !          2059:                pl_t            prev_pl;
        !          2060:                queue_t       * next;
        !          2061: 
        !          2062:                prev_pl = QFREEZE_TRACE (scan, "TOP_MODULE");
        !          2063: 
        !          2064:                next = scan->q_next;
        !          2065: 
        !          2066:                QUNFREEZE_TRACE (scan, prev_pl);
        !          2067: 
        !          2068:                if (next == NULL)
        !          2069:                        return NULL;
        !          2070:        }
        !          2071: 
        !          2072:        return R (scan);
        !          2073: }
        !          2074: 
        !          2075: 
        !          2076: /*
        !          2077:  * Code common to both POP_MODULE () and PUSH_MODULE () for removing and
        !          2078:  * deallocating a queue pair from a stream.
        !          2079:  */
        !          2080: 
        !          2081: #if    __USE_PROTO__
        !          2082: __LOCAL__ void (POP_AND_FREE) (shead_t * sheadp, queue_t * module)
        !          2083: #else
        !          2084: __LOCAL__ void
        !          2085: POP_AND_FREE __ARGS ((sheadp, module))
        !          2086: shead_t              * sheadp;
        !          2087: queue_t              * module;
        !          2088: #endif
        !          2089: {
        !          2090:        pl_t            prev_pl;
        !          2091:        pl_t            q_pl;
        !          2092:        queue_t       * next;
        !          2093: 
        !          2094: 
        !          2095:        /*
        !          2096:         * Now we must unlink the module queue from the stream. To do this, we
        !          2097:         * freeze each queue before we change it. However, that is not enough
        !          2098:         * if we are on a stream pipe, since the stream head at the other end
        !          2099:         * of the pipe could be trying to modify the same stream, and thus the
        !          2100:         * same queue pointers that we are going to change.
        !          2101:         *
        !          2102:         * We work our way around this by defining a master/slave relationship
        !          2103:         * between the ends of a pipe, and requiring that the slave end
        !          2104:         * acquire an exclusive lock on the "sh_rwlockp" lock belonging to the
        !          2105:         * master. Since the master and slave contend for the same lock, we
        !          2106:         * can be confident no other concurrent modifications to the stream
        !          2107:         * are possible.
        !          2108:         */
        !          2109: 
        !          2110:        prev_pl = SHEAD_LOCK (SHEAD_MASTER (sheadp));
        !          2111: 
        !          2112:        next = W (sheadp->sh_head);
        !          2113: 
        !          2114:        ASSERT (next->q_next == W (module));
        !          2115: 
        !          2116:        q_pl = QFREEZE_TRACE (next, "POP_AND_FREE");
        !          2117:        next->q_next = W (module)->q_next;
        !          2118:        QUNFREEZE_TRACE (next, q_pl);
        !          2119: 
        !          2120: 
        !          2121:        next = OTHERQ (next->q_next);
        !          2122: 
        !          2123:        ASSERT (next->q_next == module);
        !          2124: 
        !          2125:        q_pl = QFREEZE_TRACE (next, "POP_AND_FREE");
        !          2126:        next->q_next = sheadp->sh_head;
        !          2127:        QUNFREEZE_TRACE (next, q_pl);
        !          2128: 
        !          2129: 
        !          2130:        SHEAD_UNLOCK (SHEAD_MASTER (sheadp), prev_pl);
        !          2131: 
        !          2132: 
        !          2133:        /*
        !          2134:         * Now we can de-initialize the queue pair and free the memory.
        !          2135:         */
        !          2136: 
        !          2137:        QUEUE_FREE (module, 1, 0);
        !          2138: }
        !          2139: 
        !          2140: 
        !          2141: /*
        !          2142:  * Pop a module from a stream. In order to request this, the caller must have
        !          2143:  * the stream head sleep-locked for modification (see SHEAD_SLEEP_LOCK ()
        !          2144:  * above).
        !          2145:  *
        !          2146:  * Returns 0 on success or an error number on failure.
        !          2147:  */
        !          2148: 
        !          2149: #if    __USE_PROTO__
        !          2150: int (POP_MODULE) (shead_t * sheadp, queue_t * q, int mode, cred_t * credp)
        !          2151: #else
        !          2152: int
        !          2153: POP_MODULE __ARGS ((sheadp, q, mode, credp))
        !          2154: shead_t              * sheadp;
        !          2155: queue_t              * q;
        !          2156: int            mode;
        !          2157: cred_t       * credp;
        !          2158: #endif
        !          2159: {
        !          2160:        int             retval;
        !          2161: 
        !          2162:        ASSERT (q != NULL);
        !          2163:        ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE);
        !          2164: 
        !          2165:        /*
        !          2166:         * When a module is popped, it is blown away. If the module needs to
        !          2167:         * be drained first (as in final close) then the caller has to do it.
        !          2168:         */
        !          2169: 
        !          2170:        retval = (* q->q_qinfo->qi_qclose) (q, mode, credp);
        !          2171: 
        !          2172:        if (retval != 0)
        !          2173:                cmn_err (CE_WARN, "module close returned %d in POP_MODULE",
        !          2174:                         retval);
        !          2175: 
        !          2176:        /*
        !          2177:         * In case the module didn't turn off put and service routines.
        !          2178:         */
        !          2179: 
        !          2180:        if ((q->q_flag & QPROCSOFF) == 0) {
        !          2181: 
        !          2182:                cmn_err (CE_WARN, "Module %s did not call qprocsoff ()",
        !          2183:                         q->q_qinfo->qi_minfo->mi_idname);
        !          2184:                qprocsoff (q);
        !          2185:        }
        !          2186: 
        !          2187: 
        !          2188:        /*
        !          2189:         * And now we can release the module. We do this whether or not the
        !          2190:         * caller returned an error.
        !          2191:         */
        !          2192: 
        !          2193:        POP_AND_FREE (sheadp, q);
        !          2194: 
        !          2195:        return retval;
        !          2196: }
        !          2197: 
        !          2198: 
        !          2199: /*
        !          2200:  * This function pushes the indicated module onto a stream. The caller must
        !          2201:  * have the stream head sleep-locked for modification.
        !          2202:  */
        !          2203: 
        !          2204: #if    __USE_PROTO__
        !          2205: int (PUSH_MODULE) (shead_t * sheadp, int mode, cred_t * credp,
        !          2206:                   modsw_t * module)
        !          2207: #else
        !          2208: int
        !          2209: PUSH_MODULE __ARGS ((sheadp, mode, credp, module))
        !          2210: shead_t              * sheadp;
        !          2211: int            mode;
        !          2212: cred_t       * credp;
        !          2213: modsw_t              * module;
        !          2214: #endif
        !          2215: {
        !          2216:        queue_t       * q;
        !          2217:        queue_t       * prev;
        !          2218:        pl_t            prev_pl;
        !          2219:        pl_t            q_pl;
        !          2220:        int             retval;
        !          2221:        n_dev_t         dev;
        !          2222:        char          * modname;
        !          2223: 
        !          2224:        ASSERT (module != NULL);
        !          2225:        ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE);
        !          2226: 
        !          2227:        if ((q = QUEUE_ALLOC (1, 0)) == NULL)
        !          2228:                return ENOSR;
        !          2229: 
        !          2230:        QUEUE_INIT (q, module->mod_stream, QI_NORMAL);
        !          2231: 
        !          2232:        /*
        !          2233:         * First we have to link the module into the stream. The newly
        !          2234:         * allocated queues will have the QPROCSOFF flag set so that they are
        !          2235:         * ignored by other stream elements until the new module has been
        !          2236:         * opened.
        !          2237:         *
        !          2238:         * As above in POP_MODULE (), we acquire a write lock on the stream
        !          2239:         * head, which must be a master end if a stream pipe.
        !          2240:         */
        !          2241: 
        !          2242:        prev_pl = SHEAD_LOCK (SHEAD_MASTER (sheadp));
        !          2243: 
        !          2244:        prev = W (sheadp->sh_head);
        !          2245:        W (q)->q_next = prev->q_next;
        !          2246: 
        !          2247:        q_pl = QFREEZE_TRACE (prev, "PUSH_MODULE");
        !          2248:        prev->q_next = W (q);
        !          2249:        QUNFREEZE_TRACE (prev, q_pl);
        !          2250: 
        !          2251:        prev = OTHERQ (W (q)->q_next);
        !          2252:        q->q_next = sheadp->sh_head;
        !          2253: 
        !          2254:        ASSERT (prev->q_next == sheadp->sh_head);
        !          2255: 
        !          2256:        q_pl = QFREEZE_TRACE (prev, "PUSH_MODULE");
        !          2257:        prev->q_next = q;
        !          2258:        QUNFREEZE_TRACE (prev, q_pl);
        !          2259: 
        !          2260:        SHEAD_UNLOCK (SHEAD_MASTER (sheadp), prev_pl);
        !          2261: 
        !          2262: 
        !          2263:        /*
        !          2264:         * Ask the module to set itself up.
        !          2265:         */
        !          2266: 
        !          2267:        dev = sheadp->sh_dev;
        !          2268: 
        !          2269:        retval = (* q->q_qinfo->qi_qopen) (q, & dev, mode, MODOPEN,
        !          2270:                                           credp);
        !          2271: 
        !          2272:        modname = q->q_qinfo->qi_minfo->mi_idname;
        !          2273: 
        !          2274:        if (dev != sheadp->sh_dev)
        !          2275:                cmn_err (CE_WARN, "Module \"%s\" altered its \"dev\" parameter",
        !          2276:                         modname);
        !          2277: 
        !          2278:        if (retval != 0) {
        !          2279:                /*
        !          2280:                 * OK, don't really open this. The module should not have
        !          2281:                 * turned on it's put and service routines.
        !          2282:                 */
        !          2283: 
        !          2284:                if ((q->q_flag & QPROCSOFF) == 0) {
        !          2285: 
        !          2286:                        cmn_err (CE_WARN, "PUSH_MODULE () : Module %s enabled queue!",
        !          2287:                                 modname);
        !          2288:                        qprocson (q);
        !          2289:                }
        !          2290: 
        !          2291:                POP_AND_FREE (sheadp, q);
        !          2292:        } else if ((q->q_flag & QPROCSOFF) != 0) {
        !          2293: 
        !          2294:                cmn_err (CE_WARN, "PUSH_MODULE () : Module %s did not enable queue!",
        !          2295:                         modname);
        !          2296:                qprocson (q);
        !          2297:        }
        !          2298: 
        !          2299:        return retval;
        !          2300: }
        !          2301: 
        !          2302: 
        !          2303: /*
        !          2304:  * This function sends an IOCTL message downstream, then blocks until either
        !          2305:  * a reply arrives at the stream head, the (optional) timeout has expired, or
        !          2306:  * a signal is received.
        !          2307:  *
        !          2308:  * The caller must have the stream head locked for ioctl () processing.
        !          2309:  */
        !          2310: 
        !          2311: #if    __USE_PROTO__
        !          2312: mblk_t * (IOCTL_SEND) (shead_t * sheadp, int mode, mblk_t * msg,
        !          2313:                       int * errretp, __clock_t timeout_time)
        !          2314: #else
        !          2315: mblk_t *
        !          2316: IOCTL_SEND __ARGS ((sheadp, mode, msg, errretp, timeout_time))
        !          2317: shead_t              * sheadp;
        !          2318: int            mode;
        !          2319: mblk_t       * msg;
        !          2320: int          * errretp;
        !          2321: __clock_t      timeout_time;
        !          2322: #endif
        !          2323: {
        !          2324:        __clock_t       end_time;
        !          2325:        int             retval;
        !          2326: 
        !          2327:        ASSERT_SLEEP_LOCKED (sheadp, SH_IOCTL_LOCK);
        !          2328:        ASSERT (errretp != NULL);
        !          2329:        ASSERT (msg != NULL);
        !          2330: 
        !          2331:        /*
        !          2332:         * Set the optional timeout up first. If the timeout cannot be
        !          2333:         * allocated, we have to return failure.
        !          2334:         */
        !          2335: 
        !          2336:        if (timeout_time > 0) {
        !          2337: 
        !          2338:                (void) drv_getparm (LBOLT, & end_time);
        !          2339:                end_time += timeout_time;
        !          2340:        }
        !          2341: 
        !          2342: 
        !          2343:        /*
        !          2344:         * Now send the client's message downstream. We queue the message on
        !          2345:         * the write queue rather than directly putting it to avoid the
        !          2346:         * possibility of deadlock if an acknowledgement is sent back to us
        !          2347:         * while we are holding the basic lock below.
        !          2348:         *
        !          2349:         * We also have to check for the possibility that an error has occurred
        !          2350:         * on the stream.
        !          2351:         */
        !          2352: 
        !          2353:        (void) SHEAD_LOCK (sheadp);
        !          2354: 
        !          2355:        for (;;) {
        !          2356:                if (sheadp->sh_ioc_msg != NULL) {
        !          2357:                        /*
        !          2358:                         * If there is some stale ioctl () message lying
        !          2359:                         * around, dispose of it.
        !          2360:                         */
        !          2361: 
        !          2362:                        freemsg (sheadp->sh_ioc_msg);
        !          2363:                        sheadp->sh_ioc_msg = NULL;
        !          2364:                }
        !          2365: 
        !          2366:                if (msg != NULL)
        !          2367:                        putq (W (sheadp->sh_head), msg);
        !          2368: 
        !          2369:                msg = NULL;
        !          2370: 
        !          2371: 
        !          2372:                /*
        !          2373:                 * Before we go to sleep, we schedule our timeout.
        !          2374:                 */
        !          2375: 
        !          2376:                if (timeout_time > 0 &&
        !          2377:                    SHEAD_LOCKED_TIMEOUT (sheadp, end_time) == 0) {
        !          2378:                        /*
        !          2379:                         * We have timed out.
        !          2380:                         */
        !          2381: 
        !          2382:                        retval = ETIME;
        !          2383:                        break;
        !          2384:                }
        !          2385: 
        !          2386: 
        !          2387:                if (sheadp->sh_open_count == 0) {
        !          2388:                        /*
        !          2389:                         * This is a kernel-generated ioctl () and signalling
        !          2390:                         * is not allowed to interrupt us. We pass a NULL mode
        !          2391:                         * to avoid detecting errors.
        !          2392:                         */
        !          2393: 
        !          2394:                        ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE);
        !          2395: 
        !          2396:                        retval = SHEAD_WAIT (sheadp, 0, SH_IOCTL_WAIT,
        !          2397:                                             DONT_SIGNAL);
        !          2398:                } else {
        !          2399:                        /*
        !          2400:                         * SHEAD_WAIT () checks for hangups as well, if the
        !          2401:                         * mode includes read or write.
        !          2402:                         */
        !          2403: 
        !          2404:                        ASSERT ((mode & (FREAD | FWRITE)) != 0);
        !          2405: 
        !          2406:                        retval = SHEAD_WAIT (sheadp, mode, SH_IOCTL_WAIT,
        !          2407:                                             CHECK_SIGNALS);
        !          2408:                }
        !          2409: 
        !          2410: 
        !          2411:                /*
        !          2412:                 * We take out the basic lock here again so we can read
        !          2413:                 * "sheadp->sh_ioc_msg" atomically.
        !          2414:                 */
        !          2415: 
        !          2416:                (void) SHEAD_LOCK (sheadp);
        !          2417: 
        !          2418:                msg = sheadp->sh_ioc_msg;
        !          2419:                sheadp->sh_ioc_msg = NULL;
        !          2420: 
        !          2421:                if (retval != 0 || msg != NULL)
        !          2422:                        break;
        !          2423: 
        !          2424:                /*
        !          2425:                 * We have been woken up either by a timeout, or for some
        !          2426:                 * activity at the stream head not related to us. We loop to
        !          2427:                 * deal with this.
        !          2428:                 */
        !          2429:        }
        !          2430: 
        !          2431:        if (retval != 0) {
        !          2432: 
        !          2433:                if (errretp != NULL)
        !          2434:                        * errretp = retval;
        !          2435: 
        !          2436:                if (msg != NULL)
        !          2437:                        freemsg (msg);
        !          2438: 
        !          2439:                msg = NULL;
        !          2440:        }
        !          2441: 
        !          2442:        SHEAD_UNLOCK (sheadp, plbase);
        !          2443: 
        !          2444:        return msg;
        !          2445: }
        !          2446: 
        !          2447: 
        !          2448: /*
        !          2449:  * This function manages transparent ioctl () processing; it sets itself up
        !          2450:  * to service M_COPYIN and M_COPYOUT requests from a driver until it sees an
        !          2451:  * M_IOCACK or M_IOCNAK.
        !          2452:  */
        !          2453: 
        !          2454: typedef union {
        !          2455:        struct iocblk   ioc;
        !          2456:        struct copyreq  req;
        !          2457:        struct copyresp resp;
        !          2458: } x_ioc_t;
        !          2459: 
        !          2460: #if    __USE_PROTO__
        !          2461: __LOCAL__ int (TRANSPARENT_IOCTL) (shead_t * sheadp, int mode, int cmd,
        !          2462:                                   _VOID * arg, cred_t * credp, int * rvalp)
        !          2463: #else
        !          2464: __LOCAL__ int
        !          2465: TRANSPARENT_IOCTL __ARGS ((sheadp, mode, cmd, arg, credp, rvalp))
        !          2466: shead_t              * sheadp;
        !          2467: int            mode;
        !          2468: int            cmd;
        !          2469: _VOID        * arg;
        !          2470: cred_t       * credp;
        !          2471: int          * rvalp;
        !          2472: #endif
        !          2473: {
        !          2474:        mblk_t        * msg;
        !          2475:        mblk_t        * data;
        !          2476:        int             retval;
        !          2477:        x_ioc_t       * ioc;
        !          2478: 
        !          2479:        ASSERT_SLEEP_LOCKED (sheadp, SH_IOCTL_LOCK);
        !          2480: 
        !          2481:        /*
        !          2482:         * The message block allocated for a transparent ioctl () must be
        !          2483:         * large enough to hold any of the ioctl-related message types so that
        !          2484:         * modules and drivers (and the stream head) can just change the
        !          2485:         * message type to reply to a message.
        !          2486:         */
        !          2487: 
        !          2488:        if ((msg = MSGB_ALLOC (sizeof (* ioc), BPRI_LO, KM_SLEEP)) == NULL)
        !          2489:                return ENOSR;
        !          2490: 
        !          2491:        ioc = (x_ioc_t *) msg->b_rptr;
        !          2492:        msg->b_wptr = (unsigned char *) (ioc + 1);
        !          2493: 
        !          2494:        msg->b_datap->db_type = M_IOCTL;
        !          2495: 
        !          2496:        ioc->ioc.ioc_cmd = cmd;
        !          2497:        ioc->ioc.ioc_cr = credp;
        !          2498:        ioc->ioc.ioc_id = ++ sheadp->sh_ioc_seq;
        !          2499:        ioc->ioc.ioc_count = TRANSPARENT;
        !          2500:        ioc->ioc.ioc_rval = ioc->ioc.ioc_error = 0;
        !          2501: 
        !          2502: 
        !          2503:        /*
        !          2504:         * A transparent ioctl () gets a single data block containing the
        !          2505:         * value of "arg".
        !          2506:         */
        !          2507: 
        !          2508:        if ((data = MSGB_ALLOC (sizeof (arg), BPRI_LO, KM_SLEEP)) == NULL) {
        !          2509: 
        !          2510:                retval = ENOSR;
        !          2511:                goto done;
        !          2512:        }
        !          2513: 
        !          2514:        * (_VOID **) data->b_rptr = arg;
        !          2515:        data->b_wptr += sizeof (arg);
        !          2516: 
        !          2517: 
        !          2518:        for (;;) {
        !          2519:                /*
        !          2520:                 * Now we send the ioctl () and wait for the acknowledgement.
        !          2521:                 * Transparent ioctl ()'s wait forever, but M_ERROR and
        !          2522:                 * hangup events are interesting to us, so we can blow out.
        !          2523:                 */
        !          2524: 
        !          2525:                if ((msg = IOCTL_SEND (sheadp, mode, msg, & retval,
        !          2526:                                       0)) == NULL)
        !          2527:                        return retval;
        !          2528: 
        !          2529: 
        !          2530:                /*
        !          2531:                 * Transparent ioctl ()'s dont have to worry about data coming
        !          2532:                 * back in the M_IOCACK message, they just have to process the
        !          2533:                 * M_COPYIN and M_COPYOUT requests.
        !          2534:                 */
        !          2535: 
        !          2536:                switch (msg->b_datap->db_type) {
        !          2537: 
        !          2538:                case M_IOCNAK:
        !          2539:                        retval = ioc->ioc.ioc_error;
        !          2540:                        goto done;
        !          2541: 
        !          2542:                case M_IOCACK:
        !          2543:                        * rvalp = ioc->ioc.ioc_rval;
        !          2544:                        retval = ioc->ioc.ioc_error;
        !          2545: 
        !          2546:                        if (ioc->ioc.ioc_count > 0)
        !          2547:                                cmn_err (CE_WARN, "Transparent ioctl () processing forbids data in M_IOCACK");
        !          2548:                        goto done;
        !          2549: 
        !          2550:                case M_COPYIN:
        !          2551:                        if ((data = msg->b_cont) != NULL)
        !          2552:                                freemsg (data);
        !          2553: 
        !          2554:                        /*
        !          2555:                         * The STREAMS documentation is unclear as to whether
        !          2556:                         * these blocks are split up or not, but it seems
        !          2557:                         * unlikely.
        !          2558:                         */
        !          2559: 
        !          2560:                        if ((data = MSGB_ALLOC (ioc->req.cq_size, BPRI_LO,
        !          2561:                                                KM_SLEEP)) == NULL)
        !          2562:                                retval = ENOSR;
        !          2563:                        else if (copyin (ioc->req.cq_addr, data->b_rptr,
        !          2564:                                         ioc->req.cq_size) != 0) {
        !          2565:                                freemsg (data);
        !          2566:                                data = NULL;
        !          2567:                                retval = EFAULT;
        !          2568:                        } else {
        !          2569: 
        !          2570:                                data->b_wptr = data->b_rptr +
        !          2571:                                                ioc->req.cq_size;
        !          2572:                                retval = 0;
        !          2573:                        }
        !          2574: 
        !          2575:                        msg->b_cont = data;
        !          2576:                        break;
        !          2577: 
        !          2578:                case M_COPYOUT:
        !          2579:                        retval = 0;
        !          2580: 
        !          2581:                        while (ioc->req.cq_size > 0 &&
        !          2582:                               (data = msg->b_cont) != NULL) {
        !          2583:                                size_t          unit;
        !          2584: 
        !          2585:                                /*
        !          2586:                                 * Copy a single M_DATA block at a time. After
        !          2587:                                 * copying, we free the block.
        !          2588:                                 */
        !          2589: 
        !          2590:                                unit = data->b_wptr - data->b_rptr;
        !          2591:                                if (unit > ioc->req.cq_size)
        !          2592:                                        unit = ioc->req.cq_size;
        !          2593: 
        !          2594:                                if (copyout (data->b_rptr, ioc->req.cq_addr,
        !          2595:                                             unit) != 0) {
        !          2596:                                        retval = EFAULT;
        !          2597:                                        break;
        !          2598:                                }
        !          2599: 
        !          2600:                                ioc->req.cq_size -= unit;
        !          2601:                                ioc->req.cq_addr += unit;
        !          2602: 
        !          2603:                                msg->b_cont = data->b_cont;
        !          2604:                                freeb (data);
        !          2605:                        }
        !          2606: 
        !          2607:                        /*
        !          2608:                         * Throw away uncopied extra data.
        !          2609:                         */
        !          2610: 
        !          2611:                        if ((data = msg->b_cont) != NULL)
        !          2612:                                freemsg (data);
        !          2613: 
        !          2614:                        msg->b_cont = NULL;
        !          2615:                        break;
        !          2616: 
        !          2617:                default:
        !          2618:                        cmn_err (CE_WARN, "Invalid message type %d received during unlink processing",
        !          2619:                                 msg->b_datap->db_type);
        !          2620:                        retval = ENXIO;
        !          2621:                        goto done;
        !          2622:                }
        !          2623: 
        !          2624:                /*
        !          2625:                 * In common code for M_COPYIN and M_COPYOUT, we turn around
        !          2626:                 * the request message. If the request succeeded, we wrap
        !          2627:                 * around to the top of the loop to serve the next request;
        !          2628:                 * it there has been an error, we just put the message and
        !          2629:                 * bail out.
        !          2630:                 */
        !          2631: 
        !          2632:                msg->b_datap->db_type = M_IOCDATA;
        !          2633:                ioc->resp.cp_rval = (caddr_t) retval;
        !          2634: 
        !          2635:                if (retval != 0) {
        !          2636: 
        !          2637:                        putq (W (sheadp->sh_head), msg);
        !          2638:                        break;
        !          2639:                }
        !          2640:        }
        !          2641: 
        !          2642: done:
        !          2643:        freemsg (msg);
        !          2644: 
        !          2645:        return retval;
        !          2646: }
        !          2647: 
        !          2648: 
        !          2649: /*
        !          2650:  * This function contains code common to the ioctl () message processing for
        !          2651:  * stream link and unlink commands. These ioctl ()s send messages downstream
        !          2652:  * which are all of a single common form.
        !          2653:  */
        !          2654: 
        !          2655: #if    __USE_PROTO__
        !          2656: __LOCAL__ int (LINK_MESSAGE) (shead_t * upper, int mode, shead_t * lower,
        !          2657:                              int cmd, int muxid, cred_t * credp,
        !          2658:                              int * retvalp)
        !          2659: #else
        !          2660: __LOCAL__ int
        !          2661: LINK_MESSAGE __ARGS ((upper, mode, lower, cmd, muxid, credp, retvalp))
        !          2662: shead_t              * upper;
        !          2663: int            mode;
        !          2664: shead_t              * lower;
        !          2665: int            cmd;
        !          2666: int            muxid;
        !          2667: cred_t       * credp;
        !          2668: int          * retvalp;
        !          2669: #endif
        !          2670: {
        !          2671:        mblk_t        * msg;
        !          2672:        struct iocblk * ioc;
        !          2673:        struct linkblk * linkblk;
        !          2674:        int             ackflag;
        !          2675:        queue_t       * q;
        !          2676: 
        !          2677:        ASSERT_SLEEP_LOCKED (upper, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          2678:        ASSERT_SLEEP_LOCKED (lower, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          2679:        ASSERT (credp != NULL);
        !          2680: 
        !          2681:        /*
        !          2682:         * Set ourselves up for a STREAMS ioctl (). Note that since we keep
        !          2683:         * transparent ioctl () processing separate from normal I_STR code, we
        !          2684:         * don't have to allocate an initial message block that can be turned
        !          2685:         * into a "copyreq" or "copyresp" structure.
        !          2686:         */
        !          2687: 
        !          2688: 
        !          2689:        if ((msg = MSGB_ALLOC (sizeof (* ioc), BPRI_LO, KM_SLEEP)) == NULL)
        !          2690:                return ENOSR;
        !          2691: 
        !          2692:        ioc = (struct iocblk *) msg->b_rptr;
        !          2693:        msg->b_wptr = (unsigned char *) (ioc + 1);
        !          2694: 
        !          2695:        msg->b_datap->db_type = M_IOCTL;
        !          2696: 
        !          2697:        ioc->ioc_cmd = cmd;
        !          2698:        ioc->ioc_cr = credp;
        !          2699:        ioc->ioc_id = ++ upper->sh_ioc_seq;
        !          2700:        ioc->ioc_count = sizeof (struct linkblk);
        !          2701:        ioc->ioc_rval = ioc->ioc_error = 0;
        !          2702: 
        !          2703: 
        !          2704:        /*
        !          2705:         * Now we allocate and fill in the data part of the I_...LINK message.
        !          2706:         */
        !          2707: 
        !          2708:        if ((msg->b_cont = MSGB_ALLOC (sizeof (struct linkblk), BPRI_LO,
        !          2709:                                       KM_SLEEP)) == NULL) {
        !          2710:                freeb (msg);
        !          2711:                return ENOSR;
        !          2712:        }
        !          2713: 
        !          2714:        linkblk = (struct linkblk *) msg->b_cont->b_rptr;
        !          2715:        msg->b_cont->b_wptr = (unsigned char *) (linkblk + 1);
        !          2716: 
        !          2717: 
        !          2718:        /*
        !          2719:         * Find the bottom-most write queue on the upper stream. To make this
        !          2720:         * walk of the queue safe with respect to I_PUSH and I_POP, we take
        !          2721:         * out a read lock on the stream head. See the PUSH_MODULE () and
        !          2722:         * POP_MODULE () routines for more details on this.
        !          2723:         *
        !          2724:         * We don't use QUEUE_NEXT () because the intermediate modules are of
        !          2725:         * no interest to us; we just want the driver at the bottom.
        !          2726:         */
        !          2727: 
        !          2728:        {
        !          2729:                queue_t       * next;
        !          2730: 
        !          2731:                (void) SHEAD_LOCK (upper);
        !          2732: 
        !          2733:                next = W (upper->sh_head);
        !          2734: 
        !          2735:                do {
        !          2736:                        q = next;
        !          2737: 
        !          2738:                        (void) QFREEZE_TRACE (q, "LINK_MESSAGE");
        !          2739: 
        !          2740:                        next = q->q_next;
        !          2741: 
        !          2742:                        QUNFREEZE_TRACE (q, plbase);
        !          2743:                } while (next != NULL);
        !          2744: 
        !          2745:                SHEAD_UNLOCK (upper, plbase);
        !          2746:        }
        !          2747: 
        !          2748:        linkblk->l_qtop = q;
        !          2749:        linkblk->l_qbot = lower->sh_head;
        !          2750:        linkblk->l_index = muxid;
        !          2751: 
        !          2752: 
        !          2753:        /*
        !          2754:         * Now we send the ioctl () and wait for the acknowledgement. Since
        !          2755:         * there is no mechanism for managing this timeout, we will use the
        !          2756:         * close timeout (which is appropriate given that this operation will
        !          2757:         * often be performed as the result of a close ()).
        !          2758:         */
        !          2759: 
        !          2760:        if ((msg = IOCTL_SEND (upper, mode, msg, retvalp,
        !          2761:                               upper->sh_cltime)) == NULL)
        !          2762:                return 0;               /* counts as a negative ack */
        !          2763: 
        !          2764:        /*
        !          2765:         * Now we see what kind of message the driver has send to us.
        !          2766:         */
        !          2767: 
        !          2768:        ioc = (struct iocblk *) msg->b_rptr;
        !          2769: 
        !          2770:        if (retvalp != NULL)
        !          2771:                * retvalp = ioc->ioc_error;
        !          2772: 
        !          2773:        switch (msg->b_datap->db_type) {
        !          2774: 
        !          2775:        case M_IOCNAK:
        !          2776:                ackflag = 0;
        !          2777:                break;
        !          2778: 
        !          2779:        case M_IOCACK:
        !          2780:                /*
        !          2781:                 * We do not copy the "ioc_rval" member out because it is not
        !          2782:                 * documented as forming the return value from such a link-
        !          2783:                 * style ioctl () request.
        !          2784:                 */
        !          2785: 
        !          2786:                /*
        !          2787:                 * Since "arg" for an I_UNLINK or I_PUNLINK is not a pointer,
        !          2788:                 * it makes no sense for a driver to attempt to return data
        !          2789:                 * for the user. Since the canonical multiplexing driver code
        !          2790:                 * clears ioc_count and simply turns around the message, it
        !          2791:                 * is not a problem for there to be M_DATA messages following
        !          2792:                 * the M_IOCACK, but it is a problem if "ioc_count" is greater
        !          2793:                 * than 0.
        !          2794:                 */
        !          2795: 
        !          2796:                ackflag = 1;
        !          2797: 
        !          2798:                if (ioc->ioc_count > 0)
        !          2799:                        cmn_err (CE_WARN, "Driver %s returned data with link/unlink ioctl ()",
        !          2800:                                 q->q_qinfo->qi_minfo->mi_idname);
        !          2801: 
        !          2802:                break;
        !          2803: 
        !          2804:        default:
        !          2805:                cmn_err (CE_WARN, "Invalid message type %d received during link/unlink processing",
        !          2806:                         msg->b_datap->db_type);
        !          2807:                * retvalp = ENXIO;
        !          2808: 
        !          2809:                ackflag = 0;            /* treat as a negative ack */
        !          2810:                break;
        !          2811:        }
        !          2812: 
        !          2813:        freemsg (msg);
        !          2814: 
        !          2815:        return ackflag;
        !          2816: }
        !          2817: 
        !          2818: 
        !          2819: /*
        !          2820:  * Helper function for the link/unlink process to restore a stream to the
        !          2821:  * unlinked state.
        !          2822:  */
        !          2823: 
        !          2824: #if    __USE_PROTO__
        !          2825: __LOCAL__ int (SHEAD_INIT_UNLINKED) (shead_t * sheadp)
        !          2826: #else
        !          2827: __LOCAL__ int
        !          2828: SHEAD_INIT_UNLINKED __ARGS ((sheadp))
        !          2829: shead_t              * sheadp;
        !          2830: #endif
        !          2831: {
        !          2832:        pl_t            prev_pl;
        !          2833:        int             final_close;
        !          2834: 
        !          2835:        ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          2836: 
        !          2837:        /*
        !          2838:         * The driver is no longer using this stream; restore it to normal
        !          2839:         * operation. Note that we have to reset "q_ptr" back to point at the
        !          2840:         * stream head!
        !          2841:         */
        !          2842: 
        !          2843:        prev_pl = SHEAD_LOCK (sheadp);
        !          2844: 
        !          2845:        sheadp->sh_linked = NULL;
        !          2846:        sheadp->sh_flags &= ~ SH_PLINK;
        !          2847: 
        !          2848:        final_close = -- sheadp->sh_open_count == 0;
        !          2849: 
        !          2850:        SHEAD_UNLOCK (sheadp, prev_pl);
        !          2851: 
        !          2852: 
        !          2853:        prev_pl = QFREEZE_TRACE (sheadp->sh_head, "SHEAD_INIT_UNLINKED");
        !          2854: 
        !          2855:        sheadp->sh_head->q_ptr = sheadp;
        !          2856:        W (sheadp->sh_head)->q_ptr = sheadp;
        !          2857: 
        !          2858:        QUEUE_INIT (sheadp->sh_head, sheadp->sh_tab, QI_NORMAL);
        !          2859: 
        !          2860:        QUNFREEZE_TRACE (sheadp->sh_head, prev_pl);
        !          2861: 
        !          2862:        return final_close;
        !          2863: }
        !          2864: 
        !          2865: 
        !          2866: /*
        !          2867:  * This function takes care of unlinking a lower stream from an upper stream.
        !          2868:  *
        !          2869:  * The caller should have both the upper and lower stream heads locked for
        !          2870:  * open/close processing.
        !          2871:  */
        !          2872: 
        !          2873: #if    __USE_PROTO__
        !          2874: __LOCAL__ int (LOCKED_UNLINK) (shead_t * upper, int mode, shead_t * lower,
        !          2875:                               int cmd, cred_t * credp, int * retvalp)
        !          2876: #else
        !          2877: __LOCAL__ int
        !          2878: LOCKED_UNLINK __ARGS ((upper, mode, lower, cmd, credp, retvalp))
        !          2879: shead_t              * upper;
        !          2880: int            mode;
        !          2881: shead_t              * lower;
        !          2882: int            cmd;
        !          2883: cred_t       * credp;
        !          2884: int          * retvalp;
        !          2885: #endif
        !          2886: {
        !          2887:        ASSERT_SLEEP_LOCKED (upper, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          2888:        ASSERT_SLEEP_LOCKED (lower, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          2889: 
        !          2890:        /*
        !          2891:         * Check that the right kind of unlink command is being issued.
        !          2892:         */
        !          2893: 
        !          2894:        if (lower->sh_linked != upper ||
        !          2895:            ((lower->sh_flags & SH_PLINK) != 0) == (cmd == I_PUNLINK))
        !          2896:                return EINVAL;
        !          2897: 
        !          2898:        /*
        !          2899:         * Send the message downstream and get the return result.
        !          2900:         */
        !          2901: 
        !          2902:        if (LINK_MESSAGE (upper, mode, lower, cmd, lower->sh_muxid, credp,
        !          2903:                          retvalp)) {
        !          2904:                /*
        !          2905:                 * The unlink was properly acknowledged. Note that this may
        !          2906:                 * cause the lower stream to close.
        !          2907:                 */
        !          2908: 
        !          2909:                if (SHEAD_INIT_UNLINKED (lower) != 0)
        !          2910:                        SHEAD_DO_CLOSE (lower, mode, credp);
        !          2911: 
        !          2912:                return 1;
        !          2913:        }
        !          2914: 
        !          2915:        return 0;
        !          2916: }
        !          2917: 
        !          2918: 
        !          2919: /*
        !          2920:  * This function wraps up part of the required client functionality for
        !          2921:  * callers of SHEAD_UNLINK () by dealing with locking the lower stream head
        !          2922:  * and making appropriate calls to see if it needs closing.
        !          2923:  */
        !          2924: 
        !          2925: #if    __USE_PROTO__
        !          2926: __LOCAL__ int (SHEAD_UNLINK) (shead_t * upper, shead_t * lower, int cmd,
        !          2927:                              int mode, cred_t * credp, int * retvalp)
        !          2928: #else
        !          2929: __LOCAL__ int
        !          2930: SHEAD_UNLINK __ARGS ((upper, lower, cmd, mode, credp, retvalp))
        !          2931: shead_t              * upper;
        !          2932: shead_t              * lower;
        !          2933: int            cmd;
        !          2934: int            mode;
        !          2935: cred_t       * credp;
        !          2936: int          * retvalp;
        !          2937: #endif
        !          2938: {
        !          2939:        int             success;
        !          2940: 
        !          2941:        /*
        !          2942:         * In order to unlink this lower stream we first have to lock it. This
        !          2943:         * is necessary not only to ensure that we don't trip up other
        !          2944:         * operations affecting this stream (since there may be open file
        !          2945:         * descriptors referring to it, and/or it may be a stream pipe) but
        !          2946:         * since stream deallocations are checked for in the unlock code this
        !          2947:         * is necessary to ensure that an unlink of an otherwise unreferenced
        !          2948:         * stream does the right thing.
        !          2949:         */
        !          2950: 
        !          2951:        if ((* retvalp = SHEAD_SLEEP_LOCK (lower,
        !          2952:                                           SH_OPENCLOSE | SH_IOCTL_LOCK, 0,
        !          2953:                                           DONT_SIGNAL)) != 0) {
        !          2954: 
        !          2955:                cmn_err (CE_WARN, "Unable to lock stream in SHEAD_UNLINK (), error %d",
        !          2956:                         * retvalp);
        !          2957:                return 1;
        !          2958:        }
        !          2959: 
        !          2960: 
        !          2961:        /*
        !          2962:         * OK, we unlink this lower stream, and do all the stuff we
        !          2963:         * need to do to ensure that the lower stream gets closed if
        !          2964:         * its time has come.
        !          2965:         */
        !          2966: 
        !          2967:        success = LOCKED_UNLINK (upper, mode, lower, cmd, credp, retvalp);
        !          2968: 
        !          2969:        SHEAD_SLEEP_UNLOCK (lower, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          2970: 
        !          2971:        return success;
        !          2972: }
        !          2973: 
        !          2974: 
        !          2975: /*
        !          2976:  * Loop-detection algorithm for use in SHEAD_LINK ().
        !          2977:  *
        !          2978:  * The STREAMS documentation is very vague about what constitutes a cycle in
        !          2979:  * the link graph, probably deliberately.
        !          2980:  *
        !          2981:  * For our purposes we consider a cycle to be caused by any path of links
        !          2982:  * which lead upwards (to user level) from the *device* indicated by "upper"
        !          2983:  * to the *device* indicated by "lower".
        !          2984:  *
        !          2985:  * Frankly, given the nature of multiplexing drivers in terms of routing
        !          2986:  * information, I really don't see much advantage in this; it is perfectly
        !          2987:  * easy for messages cycles to form other ways, and given the typical nature
        !          2988:  * of multiplexor services interfaces a cycle in the hierarchy need not cause
        !          2989:  * a loop. Still, that's the way it's specified.
        !          2990:  *
        !          2991:  * THIS IS A RECURSIVE ALGORITHM FOR DEPTH-FIRST SEARCH. This fact does not
        !          2992:  * really worry me in the slightest, because the depth of the recursion here
        !          2993:  * is no worse than the possible recursive depth of the multiplexor put ()
        !          2994:  * calls themselves.
        !          2995:  */
        !          2996: 
        !          2997: #if    __USE_PROTO__
        !          2998: __LOCAL__ int (DETECT_LOOP) (shead_t * upper, shead_t * lower)
        !          2999: #else
        !          3000: __LOCAL__ int
        !          3001: DETECT_LOOP __ARGS ((upper, lower))
        !          3002: shead_t              * upper;
        !          3003: shead_t              * lower;
        !          3004: #endif
        !          3005: {
        !          3006:        shead_t       * scan;
        !          3007: 
        !          3008:        /*
        !          3009:         * We base our comparisons on the "sh_tab" member of the stream head
        !          3010:         * structure, since that is equivalent to the major part of the
        !          3011:         * (internal) device number.
        !          3012:         */
        !          3013: 
        !          3014:        if (upper->sh_tab == lower->sh_tab)
        !          3015:                return 1;
        !          3016: 
        !          3017:        /*
        !          3018:         * Now recursively work upward through the multiplexing configuration
        !          3019:         * calling DETECT_LOOP () for all the linked streams with the "sh_tab"
        !          3020:         * entry of the stream which "upper" is linked to (if "upper" is in
        !          3021:         * fact linked below another multiplexor).
        !          3022:         *
        !          3023:         * Since only device streams can be multiplexors, we only scan the
        !          3024:         * device stream list.
        !          3025:         */
        !          3026: 
        !          3027:        if ((upper = upper->sh_linked) == NULL)
        !          3028:                return 0;
        !          3029: 
        !          3030:        for (scan = str_mem->sm_streams [DEV_SLIST] ; scan != NULL ;
        !          3031:             scan = scan->sh_next) {
        !          3032: 
        !          3033:                if (scan->sh_tab == upper->sh_tab &&
        !          3034:                    DETECT_LOOP (scan, lower))
        !          3035:                        return 1;
        !          3036:        }
        !          3037: 
        !          3038:        return 0;
        !          3039: }
        !          3040: 
        !          3041: 
        !          3042: /*
        !          3043:  * This function deals with linking one stream below another. There are
        !          3044:  * numerous conditions which might prevent this from happening, including a
        !          3045:  * refusal from the multiplexing driver.
        !          3046:  *
        !          3047:  * The upper stream must be locked for open/close operations. The lower stream
        !          3048:  * will also be locked by this routine.
        !          3049:  */
        !          3050: 
        !          3051: #if    __USE_PROTO__
        !          3052: int (SHEAD_LINK) (shead_t * upper, int mode, shead_t * lower, int cmd,
        !          3053:                  cred_t * credp)
        !          3054: #else
        !          3055: int
        !          3056: SHEAD_LINK __ARGS ((upper, mode, lower, cmd, credp))
        !          3057: shead_t              * upper;
        !          3058: int            mode;
        !          3059: shead_t              * lower;
        !          3060: int            cmd;
        !          3061: cred_t       * credp;
        !          3062: #endif
        !          3063: {
        !          3064:        int             retval;
        !          3065:        muxid_t         muxid;
        !          3066: 
        !          3067:        ASSERT (lower != NULL);
        !          3068: 
        !          3069:        ASSERT_SLEEP_LOCKED (upper, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          3070: 
        !          3071:        if (SHEAD_IS_PIPE (upper) ||
        !          3072:            upper->sh_tab->st_muxrinit == NULL ||
        !          3073:            upper->sh_tab->st_muxwinit == NULL)
        !          3074:                return EINVAL;
        !          3075: 
        !          3076:        /*
        !          3077:         * Perform some of the non-recursive setup (mainly locking) for the
        !          3078:         * cycle-detection algorithm. We use the read/write lock on the stream
        !          3079:         * head since the detection algorithm walks over the global stream
        !          3080:         * list many times. Note that this single-threads checking operations,
        !          3081:         * which we would also have to do if were were pushing marker bits
        !          3082:         * around in a non-recursive implementation.
        !          3083:         */
        !          3084: 
        !          3085:        (void) RW_WRLOCK (str_mem->sm_head_lock, plstr);
        !          3086: 
        !          3087:        retval = DETECT_LOOP (upper, lower);
        !          3088: 
        !          3089:        RW_UNLOCK (str_mem->sm_head_lock, plbase);
        !          3090: 
        !          3091:        if (retval != 0)
        !          3092:                return EINVAL;
        !          3093: 
        !          3094:        /*
        !          3095:         * Generate a suitable multiplexor ID for the link. We use the device
        !          3096:         * number of the lower stream as a suitable seed point.
        !          3097:         */
        !          3098: 
        !          3099:        for (muxid = (muxid_t) lower->sh_dev ;
        !          3100:             SHEAD_FIND_MUXID (upper, cmd, muxid) != NULL ; muxid ++)
        !          3101:                ; /* DO NOTHING */
        !          3102: 
        !          3103:        /*
        !          3104:         * We set up the lower now, before we send the I_LINK, so that by the
        !          3105:         * time the driver sees the I_LINK the stream is ready for use. We
        !          3106:         * NULL out the "q_ptr" member of the lower queue so that messages
        !          3107:         * arriving early can be correctly handled.
        !          3108:         *
        !          3109:         * We take a sleep lock on the lower stream. If we can't lock it,
        !          3110:         * return EINVAL since whatever error caused the failure isn't really
        !          3111:         * relevant to the stream the caller is dealing with.
        !          3112:         */
        !          3113: 
        !          3114:        if ((retval = SHEAD_SLEEP_LOCK (lower, SH_OPENCLOSE | SH_IOCTL_LOCK,
        !          3115:                                        0, DONT_SIGNAL)) != 0)
        !          3116:                return EINVAL;
        !          3117: 
        !          3118:        /*
        !          3119:         * Note that the "q_ptr" field of the queue gets zeroed to avoid
        !          3120:         * communicating our state to the driver. In addition, we have to
        !          3121:         * count the link as an extra open now.
        !          3122:         *
        !          3123:         * Paranoia time; we check for errors, hangups and whether the lower
        !          3124:         * stream is linked at this late stage so the cutover is atomic. This
        !          3125:         * requires some cooperation from the stream head read side service
        !          3126:         * routine; look to see that it tests for "sh_linked" in the service
        !          3127:         * routine somewhere...
        !          3128:         */
        !          3129: 
        !          3130:        (void) SHEAD_LOCK (lower);
        !          3131: 
        !          3132:        if (SHEAD_HANGUP (lower) || _shead_error (lower, FREAD | FWRITE)) {
        !          3133: 
        !          3134:                SHEAD_UNLOCK (lower, plbase);
        !          3135:                SHEAD_SLEEP_UNLOCK (lower, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          3136:                return EINVAL;
        !          3137:        }
        !          3138: 
        !          3139:        lower->sh_open_count ++;        /* duplicate reference */
        !          3140: 
        !          3141:        lower->sh_linked = upper;
        !          3142:        lower->sh_muxid = muxid;
        !          3143: 
        !          3144:        if (cmd == I_PLINK)
        !          3145:                lower->sh_flags |= SH_PLINK;
        !          3146: 
        !          3147:        SHEAD_UNLOCK (lower, plbase);
        !          3148: 
        !          3149: 
        !          3150:        (void) QFREEZE_TRACE (lower->sh_head, "LINK_STREAMS");
        !          3151: 
        !          3152:        lower->sh_head->q_ptr = NULL;
        !          3153:        W (lower->sh_head)->q_ptr = NULL;
        !          3154: 
        !          3155:        QUEUE_INIT (lower->sh_head, lower->sh_tab, QI_MUX);
        !          3156: 
        !          3157:        QUNFREEZE_TRACE (lower->sh_head, plbase);
        !          3158: 
        !          3159: 
        !          3160:        /*
        !          3161:         * Send the message downstream and get the return result.
        !          3162:         */
        !          3163: 
        !          3164:        if (LINK_MESSAGE (upper, mode, lower, cmd, muxid, credp,
        !          3165:                          & retval) == 0) {
        !          3166:                int             final;
        !          3167: 
        !          3168:                /*
        !          3169:                 * The driver failed the link; restore the lower stream. This
        !          3170:                 * won't cause the stream to close (because of our open
        !          3171:                 * reference) but we take care to ensure that the counts are
        !          3172:                 * properly maintained.
        !          3173:                 */
        !          3174: 
        !          3175:                final = SHEAD_INIT_UNLINKED (lower);
        !          3176: 
        !          3177:                if (final != 0)
        !          3178:                        cmn_err (CE_WARN, "Final close in SHEAD_LINK () ????");
        !          3179:        }
        !          3180: 
        !          3181: 
        !          3182:        /*
        !          3183:         * Unlock the lower stream for proper symmetry.
        !          3184:         */
        !          3185: 
        !          3186:        SHEAD_SLEEP_UNLOCK (lower, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          3187:        return retval;
        !          3188: }
        !          3189: 
        !          3190: 
        !          3191: /*
        !          3192:  * This function deals with a special case in SHEAD_DO_CLOSE () below where
        !          3193:  * the last close of a stream pipe end causes the other end to be detached
        !          3194:  * from all the filesystem entries it has been mounted over.
        !          3195:  */
        !          3196: 
        !          3197: #if    __USE_PROTO__
        !          3198: __LOCAL__ void (SHEAD_PIPE_DETACH) (shead_t * __NOTUSED (other))
        !          3199: #else
        !          3200: __LOCAL__ void
        !          3201: SHEAD_PIPE_DETACH __ARGS ((other))
        !          3202: shead_t              * other;
        !          3203: #endif
        !          3204: {
        !          3205:        /*
        !          3206:         * Until we know how attachments are going to be performed and what
        !          3207:         * kind of structure exists, we cannot implement this function.
        !          3208:         */
        !          3209: 
        !          3210:        cmn_err (CE_PANIC, "UNIMPLEMENTED : SHEAD_PIPE_DETACH ()");
        !          3211: }
        !          3212: 
        !          3213: 
        !          3214: /*
        !          3215:  * This module factors out some code from SHEAD_DO_CLOSE (). The final
        !          3216:  * close processing for a stream head is complicated a little because when a
        !          3217:  * stream pipe end is closed that side of the pipe is not actually closed
        !          3218:  * until the other end also closes.
        !          3219:  */
        !          3220: 
        !          3221: #if    __USE_PROTO__
        !          3222: __LOCAL__ void (SHEAD_FINAL_CLOSE) (shead_t * sheadp, int mode,
        !          3223:                                    cred_t * credp)
        !          3224: #else
        !          3225: __LOCAL__ void
        !          3226: SHEAD_FINAL_CLOSE __ARGS ((sheadp, mode, credp))
        !          3227: shead_t              * sheadp;
        !          3228: int            mode;
        !          3229: cred_t       * credp;
        !          3230: #endif
        !          3231: {
        !          3232:        shead_t       * scan;
        !          3233:        queue_t       * q;
        !          3234:        int             retval;
        !          3235: 
        !          3236:        /*
        !          3237:         * Final close of a stream; the close steps are to be performed in
        !          3238:         * this order, as given in the DDI/DDK entry for close(D2DK).
        !          3239:         *      Non-persistent multiplexor links are unlinked.
        !          3240:         *      For each module and driver from the head to the driver:
        !          3241:         *              Wait for the write queue to drain.
        !          3242:         *              Call close () routine.
        !          3243:         *              Remove module/driver from stream.
        !          3244:         *              Free remaining messages.
        !          3245:         *              Deallocate queue pair.
        !          3246:         *
        !          3247:         * Here we can behave as if we have an ioctl () lock on the stream
        !          3248:         * because during final close no other process can legitimately hold
        !          3249:         * another lock on the stream head (no other legal references to the
        !          3250:         * stream exist).
        !          3251:         */
        !          3252: 
        !          3253:        while ((scan = SHEAD_FIND_MUXID (sheadp, I_UNLINK, -1)) != NULL) {
        !          3254: 
        !          3255:                if (SHEAD_UNLINK (sheadp, scan, I_UNLINK, mode, credp,
        !          3256:                                  & retval) == 0) {
        !          3257:                        /*
        !          3258:                         * There is no good reason for a driver to fail an
        !          3259:                         * I_UNLINK request.
        !          3260:                         */
        !          3261: 
        !          3262:                        cmn_err (CE_WARN, "Driver failed unlink () during final close (%d)",
        !          3263:                                 retval);
        !          3264:                        scan->sh_linked = NULL;
        !          3265:                }
        !          3266:        }
        !          3267: 
        !          3268: 
        !          3269:        /*
        !          3270:         * Before draining the write side modules, drain the stream head.
        !          3271:         */
        !          3272: 
        !          3273:        DRAIN_QUEUE (sheadp, W (sheadp->sh_head));
        !          3274: 
        !          3275: 
        !          3276:        /*
        !          3277:         * Now pop all the modules from the stream.
        !          3278:         */
        !          3279: 
        !          3280:        while ((q = TOP_MODULE (sheadp)) != NULL) {
        !          3281: 
        !          3282:                DRAIN_QUEUE (sheadp, W (q));
        !          3283: 
        !          3284:                (void) POP_MODULE (sheadp, q, mode, credp);
        !          3285:        }
        !          3286: 
        !          3287: 
        !          3288:        /*
        !          3289:         * Now close the driver, unless this is a pipe. Once this has been
        !          3290:         * done there is no reason for any context to reference this object
        !          3291:         * except to unlock it.
        !          3292:         */
        !          3293: 
        !          3294:        if (! SHEAD_IS_PIPE (sheadp)) {
        !          3295:                q = TOP_QUEUE (sheadp);
        !          3296: 
        !          3297:                DRAIN_QUEUE (sheadp, q);
        !          3298: 
        !          3299:                q = R (q);
        !          3300: 
        !          3301:                retval = (* q->q_qinfo->qi_qclose) (q, mode, credp);
        !          3302: 
        !          3303:                if (retval != 0)
        !          3304:                        cmn_err (CE_WARN, "Driver close returned %d", retval);
        !          3305: 
        !          3306:                if ((q->q_flag & QPROCSOFF) == 0) {
        !          3307: 
        !          3308:                        cmn_err (CE_WARN, "Driver %s did not call qprocsoff ()",
        !          3309:                                 q->q_qinfo->qi_minfo->mi_idname);
        !          3310:                        qprocsoff (q);
        !          3311:                }
        !          3312:        }
        !          3313: }
        !          3314: 
        !          3315: 
        !          3316: /*
        !          3317:  * This function does most of the close processing for a stream head. It is
        !          3318:  * used by regular stream close, and by stream open code if certain
        !          3319:  * irregularities are detected.
        !          3320:  *
        !          3321:  * The caller must have the stream head locked for close operations. If the
        !          3322:  * stream head being operated on is a pipe, that means both ends must be
        !          3323:  * locked (so that the caller can sequence the lock order on the basis of the
        !          3324:  * master/slave bits).
        !          3325:  */
        !          3326: 
        !          3327: #if    __USE_PROTO__
        !          3328: __LOCAL__ int (SHEAD_DO_CLOSE) (shead_t * sheadp, int mode, cred_t * credp)
        !          3329: #else
        !          3330: __LOCAL__ int
        !          3331: SHEAD_DO_CLOSE __ARGS ((sheadp, mode, credp))
        !          3332: shead_t              * sheadp;
        !          3333: int            mode;
        !          3334: cred_t       * credp;
        !          3335: #endif
        !          3336: {
        !          3337:        ASSERT (credp != NULL);
        !          3338:        ASSERT_SLEEP_LOCKED (sheadp, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          3339: 
        !          3340:        /*
        !          3341:         * If other processes have references to this stream head, then we can
        !          3342:         * just return doing no more work. Note that we keep the notion of
        !          3343:         * number of open references, number of filesystem attachments, and
        !          3344:         * multiplexor links completely separate, but any one qualifies as
        !          3345:         * a reason for keeping the stream around.
        !          3346:         *
        !          3347:         * Therefore, it follows that any code which manipulates any of these
        !          3348:         * quantities such that the next expression might become false needs
        !          3349:         * to call this function to ensure that the stream memory will be
        !          3350:         * properly reclaimed.
        !          3351:         */
        !          3352: 
        !          3353:        ASSERT (sheadp->sh_open_count == 0);
        !          3354: 
        !          3355:        if (SHEAD_IS_PIPE (sheadp)) {
        !          3356:                shead_t       * other = SHEAD_OTHER (sheadp);
        !          3357: 
        !          3358:                /*
        !          3359:                 * If this is a pipe, there are some extra things we should
        !          3360:                 * worry about. First, the first end of a stream pipe to close
        !          3361:                 * should send an M_HANGUP message to the other end rather
        !          3362:                 * than actually closing. The other end then gets to destroy
        !          3363:                 * both sides of the pipe when it finally closes.
        !          3364:                 *
        !          3365:                 * The second exception is that when an unattached end of a
        !          3366:                 * streams pipe is closed, the other end is automatically
        !          3367:                 * detached.
        !          3368:                 *
        !          3369:                 * Note that if the other end of the pipe is linked below a
        !          3370:                 * multiplexor, we do not attempt to automatically unlink it.
        !          3371:                 * This might seem entirely reasonable, but we cannot attempt
        !          3372:                 * this without introducing a possibility of deadlock.
        !          3373:                 */
        !          3374: 
        !          3375:                if (other->sh_attach_count > 0)
        !          3376:                        SHEAD_PIPE_DETACH (other);
        !          3377: 
        !          3378:                if (other->sh_open_count > 0) {
        !          3379:                        /*
        !          3380:                         * The last close/detach/unlink of the other end will
        !          3381:                         * clean everything up.
        !          3382:                         */
        !          3383: 
        !          3384:                        putctl (W (other->sh_head), M_HANGUP);
        !          3385:                        return 0;
        !          3386:                }
        !          3387: 
        !          3388:                /*
        !          3389:                 * Now we clean up the "other" end.
        !          3390:                 */
        !          3391: 
        !          3392:                SHEAD_FINAL_CLOSE (other, mode, credp);
        !          3393:        }
        !          3394: 
        !          3395:        SHEAD_FINAL_CLOSE (sheadp, mode, credp);
        !          3396: 
        !          3397:        /*
        !          3398:         * We leave the last part of the cleanup (dallocating the queue pair
        !          3399:         * and any remaining messages) to the unlock call which the caller
        !          3400:         * will perform.
        !          3401:         */
        !          3402: 
        !          3403:        return 0;
        !          3404: }
        !          3405: 
        !          3406: 
        !          3407: /*
        !          3408:  * This function builds and send an M_FLUSH message down the stream.
        !          3409:  */
        !          3410: 
        !          3411: #if    __USE_PROTO__
        !          3412: __LOCAL__ int (SHEAD_FLUSH) (shead_t * sheadp, int flag, uchar_t band)
        !          3413: #else
        !          3414: __LOCAL__ int
        !          3415: SHEAD_FLUSH __ARGS ((sheadp, flag, band))
        !          3416: shead_t              * sheadp;
        !          3417: int            flag;
        !          3418: uchar_t                band;
        !          3419: #endif
        !          3420: {
        !          3421:        mblk_t        * msg;
        !          3422: 
        !          3423:        if ((flag & FLUSHRW) == 0 || (flag & ~ FLUSHRW) != 0)
        !          3424:                return EINVAL;
        !          3425:        else if ((msg = MSGB_ALLOC (2, BPRI_LO, KM_SLEEP)) == NULL)
        !          3426:                return ENOSR;
        !          3427:        else {
        !          3428:                /*
        !          3429:                 * Send the message downstream...
        !          3430:                 */
        !          3431: 
        !          3432:                if (band > 0)
        !          3433:                        flag |= FLUSHBAND;
        !          3434: 
        !          3435:                msg->b_datap->db_type = M_FLUSH;
        !          3436:                * msg->b_wptr ++ = (unsigned char) flag;
        !          3437: 
        !          3438:                if (band > 0)
        !          3439:                        * msg->b_wptr ++ = band;
        !          3440: 
        !          3441:                put (W (sheadp->sh_head), msg);
        !          3442:        }
        !          3443: 
        !          3444:        return 0;
        !          3445: }
        !          3446: 
        !          3447: 
        !          3448: /*
        !          3449:  * This function locates a module's streamtab entry given the name. Only the
        !          3450:  * first FMNAMESZ characters are considered significant.
        !          3451:  */
        !          3452: 
        !          3453: #if    __USE_PROTO__
        !          3454: modsw_t * (FIND_MODULE) (__CONST__ char * modname)
        !          3455: #else
        !          3456: modsw_t *
        !          3457: FIND_MODULE __ARGS ((modname))
        !          3458: __CONST__ char * modname;
        !          3459: #endif
        !          3460: {
        !          3461:        modsw_t       * scan;
        !          3462:        modsw_t       * end;
        !          3463: 
        !          3464:        for (scan = modsw, end = scan + nmodsw ; scan != end ; scan ++) {
        !          3465:                __CONST__ char * name;
        !          3466: 
        !          3467:                name = scan->mod_stream->st_rdinit->qi_minfo->mi_idname;
        !          3468: 
        !          3469:                if (name != NULL && strncmp (modname, name, FMNAMESZ) == 0)
        !          3470:                        return scan;
        !          3471:        }
        !          3472: 
        !          3473:        return NULL;
        !          3474: }
        !          3475: 
        !          3476: 
        !          3477: /*
        !          3478:  * This function holds code to process an I_STR ioctl ().
        !          3479:  */
        !          3480: 
        !          3481: #if    __USE_PROTO__
        !          3482: __LOCAL__ int (ISTR_IOCTL) (shead_t * sheadp, int mode,
        !          3483:                            struct strioctl * strioc, cred_t * credp,
        !          3484:                            int * rvalp)
        !          3485: #else
        !          3486: __LOCAL__ int
        !          3487: ISTR_IOCTL __ARGS ((sheadp, mode, strioc, credp, rvalp))
        !          3488: shead_t              * sheadp;
        !          3489: int            mode;
        !          3490: struct strioctl
        !          3491:              * strioc;
        !          3492: cred_t       * credp;
        !          3493: int          * rvalp;
        !          3494: #endif
        !          3495: {
        !          3496:        __clock_t       ticks;
        !          3497:        mblk_t        * msg;
        !          3498:        mblk_t        * data;
        !          3499:        struct iocblk * ioc;
        !          3500:         int            retval;
        !          3501: 
        !          3502:        ASSERT_SLEEP_LOCKED (sheadp, SH_IOCTL_LOCK);
        !          3503: 
        !          3504:        /*
        !          3505:         * Set up timeout; "ic_timeout" == -1 means infinite
        !          3506:         * timeout, while "ic_timeout" == 0 means default
        !          3507:         * (which is infinite).
        !          3508:         */
        !          3509: 
        !          3510:        if (strioc->ic_timeout != -1 && strioc->ic_timeout != 0) {
        !          3511:                /*
        !          3512:                 * We take care to deal with overflow here.
        !          3513:                 */
        !          3514: 
        !          3515:                if ((ticks = strioc->ic_timeout) > (__clock_t) -1 / 1000000L)
        !          3516:                        ticks = (__clock_t) -1;
        !          3517: 
        !          3518:                ticks = drv_usectohz (ticks * 1000000L);
        !          3519:        } else
        !          3520:                ticks = 0;
        !          3521: 
        !          3522:        if ((msg = MSGB_ALLOC (sizeof (* ioc), BPRI_LO, KM_SLEEP)) == NULL)
        !          3523:                return ENOSR;
        !          3524: 
        !          3525:        ioc = (struct iocblk *) msg->b_rptr;
        !          3526:        msg->b_wptr = (unsigned char *) (ioc + 1);
        !          3527: 
        !          3528:        msg->b_datap->db_type = M_IOCTL;
        !          3529: 
        !          3530:        ioc->ioc_cmd = strioc->ic_cmd;
        !          3531:        ioc->ioc_cr = credp;
        !          3532:        ioc->ioc_id = ++ sheadp->sh_ioc_seq;
        !          3533:        ioc->ioc_count = strioc->ic_len;
        !          3534:        ioc->ioc_rval = ioc->ioc_error = 0;
        !          3535: 
        !          3536: 
        !          3537:        /*
        !          3538:         * If there is data to be sent downstream, we allocate a buffer to
        !          3539:         * hold it and copy the data into that buffer.
        !          3540:         */
        !          3541: 
        !          3542:        if (ioc->ioc_count > 0) {
        !          3543: 
        !          3544:                if ((data = MSGB_ALLOC (strioc->ic_len, BPRI_LO,
        !          3545:                                        KM_SLEEP)) == NULL) {
        !          3546: 
        !          3547:                        retval = ENOSR;
        !          3548:                        goto done;
        !          3549:                }
        !          3550: 
        !          3551:                msg->b_cont = data;
        !          3552:                data->b_wptr += strioc->ic_len;
        !          3553: 
        !          3554:                if (copyin (strioc->ic_dp, data->b_rptr,
        !          3555:                            strioc->ic_len) != 0) {
        !          3556: 
        !          3557:                        retval = EFAULT;
        !          3558:                        goto done;
        !          3559:                }
        !          3560:        }
        !          3561: 
        !          3562:        /*
        !          3563:         * Now we send the ioctl () and wait for the acknowledgement.
        !          3564:         */
        !          3565: 
        !          3566:        if ((msg = IOCTL_SEND (sheadp, mode, msg, & retval, ticks)) == NULL)
        !          3567:                return retval;
        !          3568: 
        !          3569: 
        !          3570:        /*
        !          3571:         * What do we do with the results? We copy at most "ioc_count" bytes
        !          3572:         * of data back into the user's address space if this is M_IOCACK.
        !          3573:         */
        !          3574: 
        !          3575:        ioc = (struct iocblk *) msg->b_rptr;
        !          3576: 
        !          3577:        switch (msg->b_datap->db_type) {
        !          3578: 
        !          3579:        case M_IOCNAK:
        !          3580:                retval = ioc->ioc_error;
        !          3581:                break;
        !          3582: 
        !          3583:        case M_IOCACK:
        !          3584:                * rvalp = ioc->ioc_rval;
        !          3585:                retval = ioc->ioc_error;
        !          3586: 
        !          3587:                data = msg->b_cont;
        !          3588: 
        !          3589:                while (ioc->ioc_count > 0) {
        !          3590:                        size_t          len;
        !          3591: 
        !          3592:                        if (data == NULL) {
        !          3593: 
        !          3594:                                cmn_err (CE_WARN, "ISTR_IOCTL : Insufficient M_DATA blocks for ioc_count");
        !          3595:                                break;
        !          3596:                        }
        !          3597: 
        !          3598:                        len = data->b_wptr - data->b_rptr;
        !          3599: 
        !          3600:                        if (len > ioc->ioc_count)
        !          3601:                                len = ioc->ioc_count;
        !          3602: 
        !          3603:                        if (len > 0 &&
        !          3604:                            copyout (data->b_rptr, strioc->ic_dp,
        !          3605:                                     len) != 0) {
        !          3606: 
        !          3607:                                retval = EFAULT;
        !          3608:                                goto done;
        !          3609:                        }
        !          3610: 
        !          3611:                        ioc->ioc_count -= len;
        !          3612:                        data = data->b_cont;
        !          3613:                        strioc->ic_dp += len;
        !          3614:                }
        !          3615:                break;
        !          3616: 
        !          3617:        default:
        !          3618:                cmn_err (CE_WARN, "Invalid message type %d received during unlink processing",
        !          3619:                         msg->b_datap->db_type);
        !          3620:                retval = ENXIO;
        !          3621:                break;
        !          3622:        }
        !          3623: 
        !          3624: done:
        !          3625:        freemsg (msg);
        !          3626: 
        !          3627:        return retval;
        !          3628: }
        !          3629: 
        !          3630: 
        !          3631: /*
        !          3632:  * Here are the details of the implementation of sigpoll_t.
        !          3633:  */
        !          3634: 
        !          3635: struct sigpoll {
        !          3636:        sigpoll_t     * sp_next;        /* single-threaded */
        !          3637:        _VOID         * sp_proc;        /* from proc_ref () */
        !          3638:        short           sp_events;      /* events to signal per <stropts.h> */
        !          3639: };
        !          3640: 
        !          3641: 
        !          3642: /*
        !          3643:  * This function is used when an M_SIG or M_PCSIG message is processed at the
        !          3644:  * stream head.
        !          3645:  */
        !          3646: 
        !          3647: #if    __USE_PROTO__
        !          3648: void (SHEAD_SIGNAL) (shead_t * sheadp, uchar_t signal)
        !          3649: #else
        !          3650: void
        !          3651: SHEAD_SIGNAL __ARGS ((sheadp, signal))
        !          3652: shead_t              * sheadp;
        !          3653: uchar_t                signal;
        !          3654: #endif
        !          3655: {
        !          3656:        pl_t            prev_pl;
        !          3657: 
        !          3658:        prev_pl = SHEAD_LOCK (sheadp);
        !          3659: 
        !          3660:        if (signal == SIGPOLL) {
        !          3661:                sigpoll_t     * sigs;
        !          3662: 
        !          3663:                /*
        !          3664:                 * SIGPOLL is only sent to those processes that have
        !          3665:                 * registered to receive it with I_SETSIG.
        !          3666:                 */
        !          3667: 
        !          3668: 
        !          3669:                for (sigs = sheadp->sh_sigs ; sigs != NULL ;
        !          3670:                     sigs = sigs->sp_next) {
        !          3671: 
        !          3672:                        if ((sigs->sp_events & S_MSG) != 0)
        !          3673:                                proc_signal (sigs->sp_proc, signal);
        !          3674:                }
        !          3675:        } else {
        !          3676:                /*
        !          3677:                 * Send a signal to the controlling process group for this
        !          3678:                 * stream; if this stream is not a controlling tty, then no
        !          3679:                 * signal is sent.
        !          3680:                 */
        !          3681: 
        !          3682:                if (sheadp->sh_pgrp != 0)
        !          3683:                        proc_kill_group (sheadp->sh_pgrp, signal);
        !          3684:        }
        !          3685: 
        !          3686:        SHEAD_UNLOCK (sheadp, prev_pl);
        !          3687: }
        !          3688: 
        !          3689: 
        !          3690: /*
        !          3691:  * This function encapsulates all user-level access to the front of the stream
        !          3692:  * head message queue. It deals with ensuring that the STREAMS scheduling
        !          3693:  * policy works (by managing QWANTR) and some other details such as dealing
        !          3694:  * with in-band processing of M_SIG messages.
        !          3695:  *
        !          3696:  * The stream head read queue should be frozen by the caller.
        !          3697:  */
        !          3698: 
        !          3699: #if    __USE_PROTO__
        !          3700: __LOCAL__ mblk_t * (SHEAD_FIRSTMSG) (shead_t * sheadp)
        !          3701: #else
        !          3702: __LOCAL__ mblk_t *
        !          3703: SHEAD_FIRSTMSG __ARGS ((sheadp))
        !          3704: shead_t              * sheadp;
        !          3705: #endif
        !          3706: {
        !          3707:        mblk_t        * msg;
        !          3708: 
        !          3709:        QFROZEN_TRACE (sheadp->sh_head, "SHEAD_FIRSTMSG");
        !          3710: 
        !          3711:        while ((msg = sheadp->sh_head->q_first) != NULL) {
        !          3712: 
        !          3713:                if (msg->b_datap->db_type != M_SIG)
        !          3714:                        return msg;
        !          3715: 
        !          3716:                rmvq (sheadp->sh_head, msg);
        !          3717:                SHEAD_SIGNAL (sheadp, * msg->b_rptr);
        !          3718:                freemsg (msg);
        !          3719:        }
        !          3720: 
        !          3721:        sheadp->sh_head->q_flag |= QWANTR;
        !          3722: 
        !          3723:        return NULL;
        !          3724: }
        !          3725: 
        !          3726: 
        !          3727: /*
        !          3728:  * This function does the necessary work to implement POLLWRBAND, which tests
        !          3729:  * to see if any of the previously written-to bands of flow in the next
        !          3730:  * downstream queue with a service procedure are not flow controlled.
        !          3731:  */
        !          3732: 
        !          3733: #if    __USE_PROTO__
        !          3734: __LOCAL__ int (POLL_WRBAND) (queue_t * q)
        !          3735: #else
        !          3736: __LOCAL__ int
        !          3737: POLL_WRBAND __ARGS ((q))
        !          3738: queue_t              * q;
        !          3739: #endif
        !          3740: {
        !          3741:        pl_t            prev_pl;
        !          3742:        qband_t       * qbandp;
        !          3743: 
        !          3744:        prev_pl = QFREEZE_TRACE (q, "POLL_WRBAND");
        !          3745: 
        !          3746:        do {
        !          3747:                q = QUEUE_NEXT (q);
        !          3748: 
        !          3749:                if (q == NULL)
        !          3750:                        return 1;
        !          3751: 
        !          3752:        } while (q->q_qinfo->qi_srvp == NULL);
        !          3753: 
        !          3754: 
        !          3755:        /*
        !          3756:         * We have found a queue with a service procedure, and have it frozen.
        !          3757:         * If there are no bands, then we can write a band...
        !          3758:         */
        !          3759: 
        !          3760:        if (q->q_nband == 0) {
        !          3761: 
        !          3762:                QUNFREEZE_TRACE (q, prev_pl);
        !          3763:                return 1;
        !          3764:        }
        !          3765: 
        !          3766:        qbandp = QUEUE_BAND (q, q->q_nband);
        !          3767: 
        !          3768:        ASSERT (qbandp != NULL);
        !          3769: 
        !          3770:        /*
        !          3771:         * Since if a band is blocked implies lower bands are blocked, we can
        !          3772:         * simply test the highest-numbered band.
        !          3773:         */
        !          3774: 
        !          3775:        if ((qbandp->qb_flag & QB_FULL) != 0) {
        !          3776: 
        !          3777:                QUNFREEZE_TRACE (q, prev_pl);
        !          3778:                return 1;
        !          3779:        }
        !          3780: 
        !          3781: 
        !          3782:        /*
        !          3783:         * If all are full, request notification via back-enabling when the
        !          3784:         * highest band becomes writeable.
        !          3785:         */
        !          3786: 
        !          3787:        qbandp->qb_flag |= QB_WANTW;
        !          3788: 
        !          3789:        QUNFREEZE_TRACE (q, prev_pl);
        !          3790:        return 0;
        !          3791: }
        !          3792: 
        !          3793: 
        !          3794: /*
        !          3795:  * This function has responsibility for checking to see whether the event mask
        !          3796:  * for this SIGPOLL request is immediately satisfied.
        !          3797:  */
        !          3798: 
        !          3799: #if    __USE_PROTO__
        !          3800: __LOCAL__ short (SHEAD_POLL_CHECK) (shead_t * sheadp, short events)
        !          3801: #else
        !          3802: __LOCAL__ short
        !          3803: SHEAD_POLL_CHECK __ARGS ((sheadp, events))
        !          3804: shead_t              * sheadp;
        !          3805: short          events;
        !          3806: #endif
        !          3807: {
        !          3808:        short           revents = 0;
        !          3809:        pl_t            prev_pl;
        !          3810:        mblk_t        * msg;
        !          3811: 
        !          3812: 
        !          3813:        /*
        !          3814:         * Check the conditions that do not depend on the status of the first
        !          3815:         * queued message (if any).
        !          3816:         *
        !          3817:         * For S_OUTPUT, using canputnext () is important because it sets the
        !          3818:         * back-enable flag so that we will be properly notified when the
        !          3819:         * condition becomes true.
        !          3820:         *
        !          3821:         * For S_WRBAND, things are a little more complex; this tests whether
        !          3822:         * *any* downstream priority band is writeable, which involves walking
        !          3823:         * over all the 'qband' structures allocated to the next stream with
        !          3824:         * a service procedure.
        !          3825:         */
        !          3826: 
        !          3827:        if ((events & __POLL_OUTPUT) != 0 && canputnext (W (sheadp->sh_head)))
        !          3828:                revents |= __POLL_OUTPUT;
        !          3829: 
        !          3830:        if ((events & __POLL_WRBAND) != 0 &&
        !          3831:            POLL_WRBAND (W (sheadp->sh_head)))
        !          3832:                revents |= __POLL_WRBAND;
        !          3833: 
        !          3834: 
        !          3835:        prev_pl = SHEAD_LOCK (sheadp);
        !          3836: 
        !          3837:        if ((events & S_ERROR) != 0 &&
        !          3838:            (sheadp->sh_rerrcode != 0 || sheadp->sh_werrcode != 0))
        !          3839:                revents |= POLLERR;
        !          3840: 
        !          3841:        if ((events & S_HANGUP) != 0 && (sheadp->sh_flags & SH_HANGUP) != 0)
        !          3842:                revents = (revents | POLLHUP) &
        !          3843:                                ~ (__POLL_OUTPUT | __POLL_WRBAND);
        !          3844: 
        !          3845:        SHEAD_UNLOCK (sheadp, prev_pl);
        !          3846: 
        !          3847: 
        !          3848:        prev_pl = QFREEZE_TRACE (sheadp->sh_head, "SHEAD_POLL_CHECK");
        !          3849: 
        !          3850:        if ((msg = SHEAD_FIRSTMSG (sheadp)) != NULL &&
        !          3851:            datamsg (msg->b_datap->db_type)) {
        !          3852: 
        !          3853:                if (! pcmsg (msg->b_datap->db_type)) {
        !          3854: 
        !          3855:                        if ((events & __POLL_INPUT) != 0)
        !          3856:                                revents |= __POLL_INPUT;
        !          3857: 
        !          3858:                        if ((events & __POLL_RDNORM) != 0 && msg->b_band == 0)
        !          3859:                                revents |= __POLL_RDNORM;
        !          3860: 
        !          3861:                        if ((events & __POLL_RDBAND) != 0 && msg->b_band > 0)
        !          3862:                                revents |= __POLL_RDBAND;
        !          3863:                } else if ((events & __POLL_HIPRI) != 0)
        !          3864:                        revents |= __POLL_HIPRI;
        !          3865:        }
        !          3866: 
        !          3867:        QUNFREEZE_TRACE (sheadp->sh_head, prev_pl);
        !          3868: 
        !          3869:        return revents;
        !          3870: }
        !          3871: 
        !          3872: 
        !          3873: /*
        !          3874:  * This function attempts to locate any sigpoll record for the current
        !          3875:  * process. The stream head needs to be locked out against modification of
        !          3876:  * the signal list, which means an IOCTL lock is sufficient.
        !          3877:  */
        !          3878: 
        !          3879: #if    __USE_PROTO__
        !          3880: __LOCAL__ sigpoll_t * (FIND_SIGPOLL) (shead_t * sheadp)
        !          3881: #else
        !          3882: __LOCAL__ sigpoll_t *
        !          3883: FIND_SIGPOLL __ARGS ((sheadp))
        !          3884: shead_t              * sheadp;
        !          3885: #endif
        !          3886: {
        !          3887:        _VOID         * proc;
        !          3888:        sigpoll_t     * scan;
        !          3889: 
        !          3890:        ASSERT_SLEEP_LOCKED (sheadp, SH_IOCTL_LOCK);
        !          3891: 
        !          3892:        /*
        !          3893:         * See if the process is already registered (so that we can modify or
        !          3894:         * free an existing record).
        !          3895:         */
        !          3896: 
        !          3897:        proc = proc_ref ();
        !          3898: 
        !          3899:        for (scan = sheadp->sh_sigs ; scan != NULL ; scan ++)
        !          3900:                if (scan->sp_proc == proc)
        !          3901:                        break;
        !          3902: 
        !          3903:        proc_unref (proc);
        !          3904: 
        !          3905:        return scan;
        !          3906: }
        !          3907: 
        !          3908: 
        !          3909: /*
        !          3910:  * This function deals with (de)registering a process for SIGPOLL. The caller
        !          3911:  * should have an IOCTL lock on the stream head so that there are no other
        !          3912:  * contexts which could modify the list of registered signals.
        !          3913:  */
        !          3914: 
        !          3915: #if    __USE_PROTO__
        !          3916: __LOCAL__ int (REGISTER_SIGPOLL) (shead_t * sheadp, short events)
        !          3917: #else
        !          3918: __LOCAL__ int
        !          3919: REGISTER_SIGPOLL __ARGS ((sheadp, events))
        !          3920: shead_t              * sheadp;
        !          3921: short          events;
        !          3922: #endif
        !          3923: {
        !          3924:        _VOID         * proc;
        !          3925:        sigpoll_t     * scan;
        !          3926:        sigpoll_t     * prev;
        !          3927: 
        !          3928:        ASSERT_SLEEP_LOCKED (sheadp, SH_IOCTL_LOCK);
        !          3929: 
        !          3930:        /*
        !          3931:         * See if the process is already registered (so that we can modify or
        !          3932:         * free an existing record). We don't use the FIND_SIGPOLL () routine
        !          3933:         * because we want to locate the previous record also.
        !          3934:         */
        !          3935: 
        !          3936:        proc = proc_ref ();
        !          3937: 
        !          3938:        for (prev = NULL, scan = sheadp->sh_sigs ; scan != NULL ;
        !          3939:             prev = scan, scan ++) {
        !          3940: 
        !          3941:                if (scan->sp_proc == proc) {
        !          3942:                        /*
        !          3943:                         * We have found a preexisting record... now modify
        !          3944:                         * or free it.
        !          3945:                         */
        !          3946: 
        !          3947:                        proc_unref (proc);
        !          3948: 
        !          3949:                        (void) SHEAD_LOCK (sheadp);
        !          3950: 
        !          3951:                        if ((scan->sp_events = events) == 0) {
        !          3952:                                /*
        !          3953:                                 * Free the cell after unlinking it from the
        !          3954:                                 * list of registered processes. We take out
        !          3955:                                 * a lock on the stream head to protect
        !          3956:                                 * against streams-level contexts walking the
        !          3957:                                 * list.
        !          3958:                                 */
        !          3959: 
        !          3960:                                if (prev == NULL)
        !          3961:                                        sheadp->sh_sigs = scan->sp_next;
        !          3962:                                else
        !          3963:                                        prev->sp_next = scan->sp_next;
        !          3964: 
        !          3965:                                SHEAD_UNLOCK (sheadp, plbase);
        !          3966: 
        !          3967:                                /*
        !          3968:                                 * We unlock the stream head before calling
        !          3969:                                 * the heap manager as a matter of courtesy.
        !          3970:                                 */
        !          3971: 
        !          3972:                                kmem_free (scan, sizeof (* scan));
        !          3973:                                proc_unref (proc);
        !          3974:                                return 0;
        !          3975:                        }
        !          3976: 
        !          3977:                        SHEAD_UNLOCK (sheadp, plbase);
        !          3978:                        goto sigcheck;
        !          3979:                }
        !          3980:        }
        !          3981: 
        !          3982: 
        !          3983:        if (events == 0) {
        !          3984:                /*
        !          3985:                 * Not found, nothing to do. That is an error according to the
        !          3986:                 * streamio (7) man pages.
        !          3987:                 */
        !          3988: 
        !          3989:                return EINVAL;
        !          3990:        }
        !          3991: 
        !          3992: 
        !          3993:        /*
        !          3994:         * We need to make a new event.
        !          3995:         */
        !          3996: 
        !          3997:        if ((scan = (sigpoll_t *) kmem_alloc (sizeof (* scan),
        !          3998:                                              KM_SLEEP)) == NULL) {
        !          3999: 
        !          4000:                proc_unref (proc);
        !          4001:                return EAGAIN;
        !          4002:        }
        !          4003: 
        !          4004:        scan->sp_proc = proc;
        !          4005:        scan->sp_events = events;
        !          4006:        scan->sp_next = sheadp->sh_sigs;
        !          4007: 
        !          4008:        /*
        !          4009:         * Since we are the only process context modifying the list, we only
        !          4010:         * need to lock the last stage of the insert against interrupt-level
        !          4011:         * contexts walking the list.
        !          4012:         */
        !          4013: 
        !          4014:        (void) SHEAD_LOCK (sheadp);
        !          4015: 
        !          4016:        sheadp->sh_sigs = scan;
        !          4017: 
        !          4018:        SHEAD_UNLOCK (sheadp, plbase);
        !          4019: 
        !          4020: sigcheck:
        !          4021:        if ((events = SHEAD_POLL_CHECK (sheadp, scan->sp_events)) != 0) {
        !          4022:                /*
        !          4023:                 * We have a winner! Check for the SIGURG special case, and
        !          4024:                 * otherwise/also send SIGPOLL via proc_signal ().
        !          4025:                 */
        !          4026: 
        !          4027:                if ((events & __POLL_RDBAND) != 0 &&
        !          4028:                    (scan->sp_events & S_BANDURG) != 0) {
        !          4029: 
        !          4030:                        proc_signal (scan->sp_proc, SIGURG);
        !          4031:                        events &= ~ __POLL_RDBAND;
        !          4032:                }
        !          4033: 
        !          4034:                if (events != 0)
        !          4035:                        proc_signal (scan->sp_proc, SIGPOLL);
        !          4036:        }
        !          4037: 
        !          4038:        return 0;
        !          4039: }
        !          4040: 
        !          4041: 
        !          4042: /*
        !          4043:  * This function maps a file descriptor into a stream head by calling upon the
        !          4044:  * abstract file-description functions declared in <sys/fhsys.h>. The caller
        !          4045:  * must lock the stream somehow.
        !          4046:  */
        !          4047: 
        !          4048: #if    ! _NO_INSTALLABLE_FILESYSTEMS
        !          4049: 
        !          4050: extern fprocs_t                streams_fsys;
        !          4051: 
        !          4052: #endif
        !          4053: 
        !          4054: 
        !          4055: #if    __USE_PROTO__
        !          4056: __LOCAL__ shead_t * (FH_TO_STREAM) (int fd, int * retvalp)
        !          4057: #else
        !          4058: __LOCAL__ shead_t *
        !          4059: FH_TO_STREAM __ARGS ((fd, retvalp))
        !          4060: int            fd;
        !          4061: int          * retvalp;
        !          4062: #endif
        !          4063: {
        !          4064:        fhandle_t     * handle;
        !          4065:        scookie_t     * cookie;
        !          4066: 
        !          4067:        ASSERT (retvalp != NULL);
        !          4068: 
        !          4069:        if ((handle = fd_get_handle (fd)) == NULL) {
        !          4070: 
        !          4071:                * retvalp = EBADF;
        !          4072:                return NULL;
        !          4073: #if    ! _NO_INSTALLABLE_FILESYSTEMS
        !          4074:        } else if (fh_procs (handle) == & streams_fsys) {
        !          4075: 
        !          4076:                * retvalp = EINVAL;
        !          4077:                return NULL;
        !          4078: #endif
        !          4079:        }
        !          4080: 
        !          4081:        cookie = (scookie_t *) fh_get_cookie (handle);
        !          4082: 
        !          4083:        ASSERT (cookie != NULL);
        !          4084: 
        !          4085:        if (cookie->sheadp == NULL)
        !          4086:                cmn_err (CE_WARN, "Bad cookie in streams");
        !          4087: 
        !          4088:        return cookie->sheadp;
        !          4089: }
        !          4090: 
        !          4091: 
        !          4092: /*
        !          4093:  * The following structure is used by the routines below to deal with the
        !          4094:  * M_PASSFP message type. The structure of the data contained in that message
        !          4095:  * is completely opaque to STREAMS routines, so we keep the definition local.
        !          4096:  */
        !          4097: 
        !          4098: struct passfp {
        !          4099:        sftab_t       * sftab;  /* system file table entry address */
        !          4100:        n_uid_t         uid;
        !          4101:        n_gid_t         gid;
        !          4102: };
        !          4103: 
        !          4104: 
        !          4105: /*
        !          4106:  * This function attempts to retrieve a file descriptor sent by an I_SENDFD
        !          4107:  * ioctl () and create a local file descriptor referring to the same file.
        !          4108:  */
        !          4109: 
        !          4110: #if    __USE_PROTO__
        !          4111: __LOCAL__ int (FH_RECV) (shead_t * sheadp, int mode, struct strrecvfd * recvp)
        !          4112: #else
        !          4113: __LOCAL__ int
        !          4114: FH_RECV __ARGS ((sheadp, mode, recvp))
        !          4115: shead_t              * sheadp;
        !          4116: int            mode;
        !          4117: struct strrecvfd
        !          4118:              * recvp;
        !          4119: #endif
        !          4120: {
        !          4121:        mblk_t        * msg;
        !          4122:        struct passfp * fp;
        !          4123:        int             retval;
        !          4124: 
        !          4125:        ASSERT (sheadp != NULL);
        !          4126:        ASSERT (recvp != NULL);
        !          4127: 
        !          4128:        if (! SHEAD_IS_PIPE (sheadp))
        !          4129:                return EINVAL;
        !          4130: 
        !          4131:        if ((mode & FREAD) == 0)
        !          4132:                return EBADF;
        !          4133: 
        !          4134:        mode &= ~ FWRITE;
        !          4135: 
        !          4136: 
        !          4137:        /*
        !          4138:         * Look at the stream head to see if a message is present.
        !          4139:         */
        !          4140: 
        !          4141:        for (;;) {
        !          4142:                int             retval;
        !          4143: 
        !          4144:                (void) QFREEZE_TRACE (sheadp->sh_head, "FH_RECV");
        !          4145: 
        !          4146:                if ((msg = SHEAD_FIRSTMSG (sheadp)) != NULL)
        !          4147:                        break;
        !          4148: 
        !          4149:                /*
        !          4150:                 * Use the STREAMS flag to indicate that we have found the
        !          4151:                 * queue empty.
        !          4152:                 */
        !          4153: 
        !          4154:                (void) SHEAD_LOCK (sheadp);
        !          4155: 
        !          4156:                QUNFREEZE_TRACE (sheadp->sh_head, plstr);
        !          4157: 
        !          4158:                /*
        !          4159:                 * We need to wait (unless O_NDELAY or O_NONBLOCK has been
        !          4160:                 * specified), or the stream has been hung up.
        !          4161:                 */
        !          4162: 
        !          4163:                if ((retval = SHEAD_WAIT_NONBLOCK (sheadp, mode, SH_READ_WAIT,
        !          4164:                                                   CHECK_SIGNALS)) != 0)
        !          4165:                        return retval;
        !          4166: 
        !          4167:                /*
        !          4168:                 * Check again...
        !          4169:                 */
        !          4170:        }
        !          4171: 
        !          4172:        if (msg->b_datap->db_type != M_PASSFP)
        !          4173:                retval = EBADMSG;
        !          4174:        else if (! fd_can_add ())
        !          4175:                retval = EMFILE;
        !          4176:        else {
        !          4177: 
        !          4178:                retval = 0;
        !          4179:                rmvq (sheadp->sh_head, msg);
        !          4180:        }
        !          4181: 
        !          4182:        QUNFREEZE_TRACE (sheadp->sh_head, plbase);
        !          4183: 
        !          4184:        if (retval != 0)
        !          4185:                return retval;
        !          4186: 
        !          4187:        /*
        !          4188:         * After this point, "msg" is our responsibility and we either have to
        !          4189:         * free it or put it back if there is an error.
        !          4190:         */
        !          4191: 
        !          4192:        fp = (struct passfp *) msg->b_rptr;
        !          4193: 
        !          4194:        if ((retval = fd_add_sftab (fp->sftab, & recvp->fd)) == 0 &&
        !          4195:            ((recvp->uid = (o_uid_t) fp->uid) != fp->uid ||
        !          4196:             (recvp->gid = (o_gid_t) fp->gid) != fp->gid))
        !          4197:                retval = EOVERFLOW;
        !          4198: 
        !          4199:        freemsg (msg);
        !          4200:        return retval;
        !          4201: }
        !          4202: 
        !          4203: 
        !          4204: /*
        !          4205:  * This function attempts to send a file descriptor to another process at the
        !          4206:  * other end of a stream pipe.
        !          4207:  */
        !          4208: 
        !          4209: #if    __USE_PROTO__
        !          4210: __LOCAL__ int (FH_SEND) (shead_t * sheadp, int fd, cred_t * credp)
        !          4211: #else
        !          4212: __LOCAL__ int
        !          4213: FH_SEND __ARGS ((sheadp, fd, credp))
        !          4214: shead_t              * sheadp;
        !          4215: int            fd;
        !          4216: cred_t       * credp;
        !          4217: #endif
        !          4218: {
        !          4219:        mblk_t        * msg;
        !          4220:        struct passfp * fp;
        !          4221:        sftab_t       * sftab;
        !          4222:        shead_t       * other;
        !          4223:        int             retval;
        !          4224: 
        !          4225:        ASSERT (sheadp != NULL);
        !          4226:        ASSERT (credp != NULL);
        !          4227: 
        !          4228:        if (! SHEAD_IS_PIPE (sheadp))
        !          4229:                return EINVAL;
        !          4230: 
        !          4231:        /*
        !          4232:         * We are passed a file descriptor (a user-level abstract entity);
        !          4233:         * here we turn that into a kernel-level abstract entity.
        !          4234:         */
        !          4235: 
        !          4236:        if ((sftab = fd_get_sftab (fd)) == NULL)
        !          4237:                return EBADF;
        !          4238: 
        !          4239:        other = SHEAD_OTHER (sheadp);
        !          4240: 
        !          4241:        if (! canput (W (other->sh_head)) ||
        !          4242:            (msg = MSGB_ALLOC (sizeof (* fp), BPRI_LO, KM_SLEEP)) == NULL)
        !          4243:                return EAGAIN;
        !          4244: 
        !          4245:        /*
        !          4246:         * Fill in the new message block and put the message to the other
        !          4247:         * side. After this point we have to free the message block if there
        !          4248:         * is a problem.
        !          4249:         */
        !          4250: 
        !          4251:        fp = (struct passfp *) msg->b_rptr;
        !          4252:        msg->b_wptr = (unsigned char *) (fp + 1);
        !          4253: 
        !          4254:        msg->b_datap->db_type = M_PASSFP;
        !          4255: 
        !          4256:        fp->sftab = sftab;
        !          4257:        fp->uid = credp->cr_uid;
        !          4258:        fp->gid = credp->cr_gid;
        !          4259: 
        !          4260:        (void) SHEAD_LOCK (sheadp);
        !          4261: 
        !          4262:        if ((retval = SHEAD_ERRHUP_LOCKED (sheadp, FWRITE)) == 0) {
        !          4263: 
        !          4264:                putq (W (other->sh_head), msg);
        !          4265: 
        !          4266:                SHEAD_UNLOCK (sheadp, plbase);
        !          4267:        } else
        !          4268:                freemsg (msg);
        !          4269: 
        !          4270:        return retval;
        !          4271: }
        !          4272: 
        !          4273: 
        !          4274: /*
        !          4275:  * This function factors out the details of copying data out from kernel space
        !          4276:  * into a "strbuf" stream buffer structure in user space.
        !          4277:  *
        !          4278:  * The return value of this function is 0 on success or -1 on error.
        !          4279:  */
        !          4280: 
        !          4281: enum {
        !          4282:        CONTROL_PART,
        !          4283:        DATA_PART
        !          4284: };
        !          4285: 
        !          4286: #if    __USE_PROTO__
        !          4287: __LOCAL__ int (COPYOUT_BUF) (struct strbuf * bufp, mblk_t ** mpp, int data)
        !          4288: #else
        !          4289: __LOCAL__ int
        !          4290: COPYOUT_BUF __ARGS ((bufp, mpp, data))
        !          4291: struct strbuf *        bufp;
        !          4292: mblk_t      ** mpp;
        !          4293: int            data;
        !          4294: #endif
        !          4295: {
        !          4296:        mblk_t        * prev;
        !          4297:        mblk_t        * scan;
        !          4298:        int             remaining;
        !          4299:        caddr_t         outaddr;
        !          4300: 
        !          4301:        ASSERT (mpp != NULL);
        !          4302: 
        !          4303:        /*
        !          4304:         * The first thing we do is check some special values; if a "strbuf"
        !          4305:         * entry is NULL or has its "maxlen" member set to "-1", we do nothing
        !          4306:         * with the message.
        !          4307:         */
        !          4308: 
        !          4309:        if (bufp == NULL || bufp->maxlen == -1)
        !          4310:                return 0;
        !          4311: 
        !          4312:        /*
        !          4313:         * Next, if this is a data-part copy, skip any intial M_PROTO or
        !          4314:         * M_PCPROTO message blocks. There *should* only ever be one of these
        !          4315:         * at the front of a message, but we are required to effectively
        !          4316:         * coalesce multiple control blocks.
        !          4317:         */
        !          4318: 
        !          4319:        prev = NULL;
        !          4320:        scan = * mpp;
        !          4321: 
        !          4322:        if (data == DATA_PART) {
        !          4323:                /*
        !          4324:                 * Find the data portion of the message, if any.
        !          4325:                 */
        !          4326: 
        !          4327:                while (scan != NULL) {
        !          4328: 
        !          4329:                        if (scan->b_datap->db_type == M_DATA)
        !          4330:                                break;
        !          4331:                        scan = (prev = scan)->b_cont;
        !          4332:                }
        !          4333:        } else
        !          4334:                if (scan->b_datap->db_type == M_DATA)
        !          4335:                        scan = NULL;
        !          4336: 
        !          4337:        /*
        !          4338:         * If there is no control (or data, as appropriate) part to the
        !          4339:         * message, then we set the "len" member of the "strbuf" to -1.
        !          4340:         */
        !          4341: 
        !          4342:        if (scan == NULL) {
        !          4343: 
        !          4344:                bufp->len = -1;
        !          4345:                return 0;
        !          4346:        }
        !          4347: 
        !          4348: 
        !          4349:        /*
        !          4350:         * Now be do the actual copy; the form of this loop is organized so
        !          4351:         * that zero-length message blocks will be consumed if "maxlen" is
        !          4352:         * set to 0. This is important not only to comply with the manual page
        !          4353:         * for getmsg ()/getpmsg (), but also ensures that trailing zero-
        !          4354:         * length blocks at the end of a message get cleaned up properly.
        !          4355:         */
        !          4356: 
        !          4357:        bufp->len = 0;
        !          4358:        remaining = bufp->maxlen;
        !          4359:        outaddr = (caddr_t) bufp->buf;
        !          4360: 
        !          4361:        for (;;) {
        !          4362:                size_t          copylen = scan->b_wptr - scan->b_rptr;
        !          4363:                mblk_t        * next;
        !          4364: 
        !          4365:                if (copylen > remaining)
        !          4366:                        copylen = remaining;
        !          4367: 
        !          4368:                if (copylen > 0) {
        !          4369:                        /*
        !          4370:                         * Copy the data to the user. Don't forget that
        !          4371:                         * copyout () is like bcopy () in that the arguments
        !          4372:                         * are src, dest, len !
        !          4373:                         */
        !          4374: 
        !          4375:                        if (copyout (scan->b_rptr, outaddr, copylen) != 0)
        !          4376:                                return EFAULT;
        !          4377: 
        !          4378:                        bufp->len += copylen;
        !          4379:                        scan->b_rptr += copylen;
        !          4380:                        remaining -= copylen;
        !          4381:                }
        !          4382: 
        !          4383:                if (scan->b_rptr != scan->b_wptr) {
        !          4384:                        /*
        !          4385:                         * Since this message block was not fully consumed, we
        !          4386:                         * can infer that we have copied all the data we can.
        !          4387:                         */
        !          4388: 
        !          4389:                        ASSERT (remaining == 0);
        !          4390:                        break;
        !          4391:                }
        !          4392: 
        !          4393: 
        !          4394:                /*
        !          4395:                 * This message block has been consumed; unlink and free it.
        !          4396:                 */
        !          4397: 
        !          4398:                next = scan->b_cont;
        !          4399:                if (prev == NULL)
        !          4400:                        * mpp = next;
        !          4401:                else
        !          4402:                        prev->b_cont = next;
        !          4403:                freeb (scan);
        !          4404: 
        !          4405: 
        !          4406:                /*
        !          4407:                 * Get ready to go around the loop again; if we are copying
        !          4408:                 * the control part of a message, we have to test for the end
        !          4409:                 * of the control part here.
        !          4410:                 */
        !          4411: 
        !          4412:                if ((scan = next) == NULL)
        !          4413:                        break;
        !          4414: 
        !          4415:                if (data == CONTROL_PART && scan->b_datap->db_type == M_DATA)
        !          4416:                        break;
        !          4417:        }
        !          4418: 
        !          4419:        return 0;
        !          4420: }
        !          4421: 
        !          4422: 
        !          4423: /*
        !          4424:  * This is a buffer callback function used by SHEAD_PEEK () to deal with
        !          4425:  * dupmsg () failures via bufcall ().
        !          4426:  */
        !          4427: 
        !          4428: #if    __USE_PROTO__
        !          4429: __LOCAL__ void peek_bufcall_func (_VOID * arg)
        !          4430: #else
        !          4431: __LOCAL__ void
        !          4432: peek_bufcall_func (arg)
        !          4433: _VOID        * arg;
        !          4434: #endif
        !          4435: {
        !          4436:        pl_t            prev_pl;
        !          4437:        shead_t       * sheadp = (shead_t *) arg;
        !          4438: 
        !          4439:        /*
        !          4440:         * We freeze the stream head read queue to synchronize ourselves with
        !          4441:         * the SHEAD_PEEK () and avoid race conditions where we try and wake
        !          4442:         * up the process that scheduled us before they have slept.
        !          4443:         */
        !          4444: 
        !          4445:        prev_pl = QFREEZE_TRACE (sheadp->sh_head, "peek_bufcall_func");
        !          4446: 
        !          4447:        sheadp->sh_read_bufcall = 0;
        !          4448: 
        !          4449:        SHEAD_WAKE (sheadp, SH_PEEK_WAIT);
        !          4450: 
        !          4451:        QUNFREEZE_TRACE (sheadp->sh_head, prev_pl);
        !          4452: }
        !          4453: 
        !          4454: 
        !          4455: /*
        !          4456:  * This is a helper function for I_PEEK and read ()-like functions who want
        !          4457:  * to recover from an out-of-memory situation by performing a short sleep.
        !          4458:  *
        !          4459:  * This function takes care of scheduling and cancelling the bufcall. The
        !          4460:  * caller must have the stream head locked when calling this function.
        !          4461:  *
        !          4462:  * This function returns with the stream head read queue unlocked, and with
        !          4463:  * the value 0 on success and an error number on error.
        !          4464:  */
        !          4465: 
        !          4466: #if    __USE_PROTO__
        !          4467: __LOCAL__ int (SHEAD_READ_BUFCALL) (shead_t * sheadp, int __NOTUSED (mode))
        !          4468: #else
        !          4469: __LOCAL__ int
        !          4470: SHEAD_READ_BUFCALL __ARGS ((sheadp, mode))
        !          4471: shead_t              * sheadp;
        !          4472: int            mode;
        !          4473: #endif
        !          4474: {
        !          4475:        SHEAD_ASSERT_LOCKED (sheadp);
        !          4476: 
        !          4477:        if (sheadp->sh_read_bufcall == 0 &&
        !          4478:            (sheadp->sh_read_bufcall = bufcall (1024, BPRI_LO,
        !          4479:                                                peek_bufcall_func,
        !          4480:                                                sheadp)) == 0) {
        !          4481:                SHEAD_UNLOCK (sheadp, plbase);
        !          4482:                return ENOSR;
        !          4483:        }
        !          4484: 
        !          4485:        return SHEAD_WAIT_NONBLOCK (sheadp, FREAD, SH_PEEK_WAIT,
        !          4486:                                    CHECK_SIGNALS);
        !          4487: }
        !          4488: 
        !          4489: 
        !          4490: /*
        !          4491:  * This function implements I_PEEK read-ahead for streams. The caller should
        !          4492:  * have the stream head locked for read/write access.
        !          4493:  */
        !          4494: 
        !          4495: #if    __USE_PROTO__
        !          4496: __LOCAL__ int (SHEAD_PEEK) (shead_t * sheadp, struct strpeek * peek,
        !          4497:                            int * rvalp)
        !          4498: #else
        !          4499: __LOCAL__ int
        !          4500: SHEAD_PEEK __ARGS ((sheadp, peek, rvalp))
        !          4501: shead_t              * sheadp;
        !          4502: struct strpeek * peek;
        !          4503: int          * rvalp;
        !          4504: #endif
        !          4505: {
        !          4506:        mblk_t        * msg;
        !          4507:        int             retval;
        !          4508: 
        !          4509:        ASSERT (sheadp != NULL);
        !          4510:        ASSERT (peek != NULL);
        !          4511:        ASSERT (rvalp != NULL);
        !          4512: 
        !          4513:        if (peek->flags != 0 && peek->flags != RS_HIPRI)
        !          4514:                return EINVAL;
        !          4515: 
        !          4516:        /*
        !          4517:         * Look at the stream head to see if there are any queued messages.
        !          4518:         *
        !          4519:         * Some notes about this are in order; as mentioned in the discussion
        !          4520:         * on locking elsewhere, the possibility of page fault resolution
        !          4521:         * during copies to user space complicates life, because copy routines
        !          4522:         * may sleep while a page is made resident.
        !          4523:         *
        !          4524:         * This affects routines which read from the stream head in various
        !          4525:         * ways, some of which are outlined in the general section on locking.
        !          4526:         * Other than data consistency, it also affects the way message are
        !          4527:         * deallocated; this routine wants to take a copy of the data in a
        !          4528:         * message, but we need to ensure that the message will not be
        !          4529:         * deallocated not just by other processes but also by actions at the
        !          4530:         * stream level such as M_FLUSH.
        !          4531:         *
        !          4532:         * Other than getting into a web of locking flags and reference counts
        !          4533:         * (there are already too many of those), the simplest ways of dealing
        !          4534:         * with this are a) create a duplicate reference to the message data
        !          4535:         * with dupmsg (), and b) simply dequeue the message and put it back
        !          4536:         * when we're done.
        !          4537:         *
        !          4538:         * Neither alternative is without unpleasant consequences; a) has to
        !          4539:         * deal with a lack of available storage to duplicate the message
        !          4540:         * blocks, and b) has to deal with such things as reads blocking while
        !          4541:         * the message is dequeued.
        !          4542:         *
        !          4543:         * a) and b) seem to have more-or-less equal implementation costs, but
        !          4544:         * while a) is guaranteed to maintain the semantics of all stream
        !          4545:         * operations, b) is not. Unless we can predict all the consequences
        !          4546:         * of b) and either work around them or determine that they are benign
        !          4547:         * then a) seems preferable.
        !          4548:         */
        !          4549: 
        !          4550:        for (;;) {
        !          4551:                (void) QFREEZE_TRACE (sheadp->sh_head, "SHEAD_PEEK");
        !          4552: 
        !          4553:                if ((msg = SHEAD_FIRSTMSG (sheadp)) == NULL) {
        !          4554: no_message:
        !          4555:                        /*
        !          4556:                         * No go; arrange for the value 0 to be returned to
        !          4557:                         * the caller of the ioctl ().
        !          4558:                         */
        !          4559: 
        !          4560:                        QUNFREEZE_TRACE (sheadp->sh_head, plbase);
        !          4561:                        * rvalp = 0;
        !          4562: 
        !          4563:                        return 0;
        !          4564:                }
        !          4565: 
        !          4566:                switch (msg->b_datap->db_type) {
        !          4567: 
        !          4568:                case M_DATA:
        !          4569:                case M_PROTO:
        !          4570:                        /*
        !          4571:                         * If the caller has asked for high-priority messages
        !          4572:                         * only, then we arrange to return 0.
        !          4573:                         */
        !          4574: 
        !          4575:                        if ((peek->flags & RS_HIPRI) != 0)
        !          4576:                                goto no_message;
        !          4577:                        break;
        !          4578: 
        !          4579:                case M_PCPROTO:
        !          4580:                        break;
        !          4581: 
        !          4582:                default:
        !          4583:                        QUNFREEZE_TRACE (sheadp->sh_head, plbase);
        !          4584:                        return EBADMSG;
        !          4585:                }
        !          4586: 
        !          4587: 
        !          4588:                /*
        !          4589:                 * Attempt to obtain a duplicate reference to this message.
        !          4590:                 */
        !          4591: 
        !          4592:                if ((msg = dupmsg (msg)) != NULL) {
        !          4593: 
        !          4594:                        QUNFREEZE_TRACE (sheadp->sh_head, plbase);
        !          4595:                        break;
        !          4596:                }
        !          4597: 
        !          4598: 
        !          4599:                /*
        !          4600:                 * Wait a short time for buffers to be available. To do this,
        !          4601:                 * we transfer our locking attention from the queue to the
        !          4602:                 * stream head.
        !          4603:                 */
        !          4604: 
        !          4605:                (void) SHEAD_LOCK (sheadp);
        !          4606: 
        !          4607:                QUNFREEZE_TRACE (sheadp->sh_head, plstr);
        !          4608: 
        !          4609:                if ((retval = SHEAD_READ_BUFCALL (sheadp, FREAD)) != 0)
        !          4610:                        return retval;
        !          4611:        }
        !          4612: 
        !          4613: 
        !          4614:        /*
        !          4615:         * Now we have a duplicate copy of a message to transfer to user
        !          4616:         * space. From this point on, any attempt to exit from this routine
        !          4617:         * must take care of freeing this message. However, we don't have to
        !          4618:         * touch the queue again.
        !          4619:         */
        !          4620: 
        !          4621:        peek->flags = msg->b_datap->db_type == M_PCPROTO ? RS_HIPRI : 0;
        !          4622: 
        !          4623:        retval = (COPYOUT_BUF (& peek->ctlbuf, & msg, CONTROL_PART) != 0 ||
        !          4624:                  COPYOUT_BUF (& peek->databuf, & msg,
        !          4625:                               DATA_PART) != 0) ? EFAULT : 0;
        !          4626: 
        !          4627:        if (msg != NULL)
        !          4628:                freemsg (msg);
        !          4629: 
        !          4630:        * rvalp = 1;
        !          4631: 
        !          4632:        return retval;
        !          4633: }
        !          4634: 
        !          4635: 
        !          4636: /*
        !          4637:  * Helper function to atomically read the stream head write offset.
        !          4638:  */
        !          4639: 
        !          4640: #if    __USE_PROTO__
        !          4641: __LOCAL__ short (SHEAD_WRITEOFFSET) (shead_t * sheadp)
        !          4642: #else
        !          4643: __LOCAL__ short
        !          4644: SHEAD_WRITEOFFSET __ARGS ((sheadp))
        !          4645: shead_t              * sheadp;
        !          4646: #endif
        !          4647: {
        !          4648:        pl_t            prev_pl;
        !          4649:        short           opt;
        !          4650: 
        !          4651:        prev_pl = SHEAD_LOCK (sheadp);
        !          4652: 
        !          4653:        opt = sheadp->sh_readopt;
        !          4654: 
        !          4655:        SHEAD_UNLOCK (sheadp, prev_pl);
        !          4656: 
        !          4657:        return opt;
        !          4658: }
        !          4659: 
        !          4660: 
        !          4661: /*
        !          4662:  * This function tests for errors on a stream and optionally also waits for
        !          4663:  * flow control to be relieved.
        !          4664:  */
        !          4665: 
        !          4666: #if    __USE_PROTO__
        !          4667: __LOCAL__ int (SHEAD_WRITE_TEST) (shead_t * sheadp, int mode, int band,
        !          4668:                                   int hipri)
        !          4669: #else
        !          4670: __LOCAL__ int
        !          4671: SHEAD_WRITE_TEST __ARGS ((sheadp, mode, band, hipri))
        !          4672: shead_t              * sheadp;
        !          4673: int            mode;
        !          4674: int            band;
        !          4675: int            hipri;
        !          4676: #endif
        !          4677: {
        !          4678:        int             retval;
        !          4679: 
        !          4680:        do {
        !          4681:                (void) SHEAD_LOCK (sheadp);
        !          4682: 
        !          4683:                if ((retval = SHEAD_ERRHUP_LOCKED (sheadp, mode)) != 0)
        !          4684:                        break;
        !          4685: 
        !          4686:                if (hipri != 0 || bcanputnext (W (sheadp->sh_head), band)) {
        !          4687: 
        !          4688:                        SHEAD_UNLOCK (sheadp, plbase);
        !          4689:                        break;
        !          4690:                }
        !          4691:        } while ((retval = SHEAD_WAIT_NONBLOCK (sheadp, mode, SH_WRITE_WAIT,
        !          4692:                                                CHECK_SIGNALS)) == 0);
        !          4693: 
        !          4694:        return retval;
        !          4695: }
        !          4696: 
        !          4697: 
        !          4698: /*
        !          4699:  * This function deals with all the grunge of creating a message for sending
        !          4700:  * down a stream. There are many conditions that need to be checked, including
        !          4701:  * whether the message fits within the size limits given by the downstream
        !          4702:  * queue.
        !          4703:  *
        !          4704:  * Since the message is going to be written to the stream, we also deal with
        !          4705:  * waiting for flow control here. We only allocate memory for the user's data
        !          4706:  * when we have an indication that it will be valid to write it... this may
        !          4707:  * not be an optimal choice for a high-performance system with vast amounts
        !          4708:  * of STREAMS buffer space.
        !          4709:  */
        !          4710: 
        !          4711: #if    __USE_PROTO__
        !          4712: __LOCAL__ mblk_t * (SHEAD_MAKEMSG) (shead_t * sheadp, int mode,
        !          4713:                                    struct strbuf * ctlbuf,
        !          4714:                                    struct strbuf * databuf,
        !          4715:                                    int flags, int band, int * retvalp)
        !          4716: #else
        !          4717: __LOCAL__ mblk_t *
        !          4718: SHEAD_MAKEMSG __ARGS ((sheadp, mode, ctlbuf, databuf, flags, band, retvalp))
        !          4719: shead_t              * sheadp;
        !          4720: int            mode;
        !          4721: struct strbuf *        ctlbuf;
        !          4722: struct strbuf *        databuf;
        !          4723: int            flags;
        !          4724: int            band;
        !          4725: int          * retvalp;
        !          4726: #endif
        !          4727: {
        !          4728:        queue_t       * q;
        !          4729:        int             ctlsize;
        !          4730:        int             datasize;
        !          4731:        int             wroff;
        !          4732:        mblk_t        * ctlmsg;
        !          4733:        mblk_t        * datamsg;
        !          4734: 
        !          4735:        ASSERT (sheadp != NULL);
        !          4736:        ASSERT (retvalp != NULL);
        !          4737: 
        !          4738:        /*
        !          4739:         * The "flags" value specifies one of the constants MSG_BAND or
        !          4740:         * MSG_HIPRI. Despite being arranged as flags, only one is allowed to
        !          4741:         * be given.
        !          4742:         */
        !          4743: 
        !          4744:        if (flags != MSG_BAND && flags != MSG_HIPRI) {
        !          4745: 
        !          4746:                * retvalp = EINVAL;
        !          4747:                return NULL;
        !          4748:        }
        !          4749: 
        !          4750:        if ((mode & FWRITE) == 0) {
        !          4751: 
        !          4752:                * retvalp = EBADF;
        !          4753:                return NULL;
        !          4754:        }
        !          4755: 
        !          4756:        mode &= ~ FREAD;
        !          4757: 
        !          4758: 
        !          4759:        /*
        !          4760:         * The absolute maximum possible size for the control or data parts of
        !          4761:         * a STREAMS message are configured system-wide.
        !          4762:         */
        !          4763: 
        !          4764:        ctlsize = ctlbuf == NULL ? -1 : ctlbuf->len;
        !          4765:        datasize = databuf == NULL ? -1 : databuf->len;
        !          4766:        wroff = SHEAD_WRITEOFFSET (sheadp);
        !          4767: 
        !          4768:        q = TOP_QUEUE (sheadp);
        !          4769: 
        !          4770:        if (ctlsize > str_mem->sm_maxctlsize ||
        !          4771:            (datasize + wroff) > str_mem->sm_maxdatasize ||
        !          4772:            (datasize + wroff) < q->q_minpsz ||
        !          4773:            (datasize + wroff) > q->q_maxpsz) {
        !          4774: 
        !          4775:                * retvalp = ERANGE;
        !          4776:                return NULL;
        !          4777:        }
        !          4778: 
        !          4779: 
        !          4780:        /*
        !          4781:         * You can't send a high-priority message without a control part, or a
        !          4782:         * high-priority message with a non-zero band number.
        !          4783:         *
        !          4784:         * Otherwise, if no data at all is specified, then no message will be
        !          4785:         * sent.
        !          4786:         */
        !          4787: 
        !          4788:        if (flags == MSG_HIPRI) {
        !          4789: 
        !          4790:                if (ctlsize < 0 || band != 0) {
        !          4791: 
        !          4792:                        * retvalp = EINVAL;
        !          4793:                        return NULL;
        !          4794:                }
        !          4795:        } else if (datasize < 0 && ctlsize < 0) {
        !          4796: 
        !          4797:                * retvalp = 0;
        !          4798:                return NULL;
        !          4799:        }
        !          4800: 
        !          4801: 
        !          4802:        /*
        !          4803:         * Let's see if the stream is flow controlled; if it is, we either
        !          4804:         * block or return EAGAIN depending on the FNDELAY/FNONBLOCK setting.
        !          4805:         */
        !          4806: 
        !          4807:        if ((* retvalp = SHEAD_WRITE_TEST (sheadp, mode, band, flags)) != 0)
        !          4808:                return NULL;
        !          4809: 
        !          4810:        /*
        !          4811:         * Now we allocate data space for the messages. If the size of a
        !          4812:         * component is -1, then we don't allocate any space for that part,
        !          4813:         * otherwise we allocate a component of length 0.
        !          4814:         *
        !          4815:         * Don't forget that copyin () has arguments in the bcopy () order,
        !          4816:         * ie. src, dest, len
        !          4817:         */
        !          4818: 
        !          4819:        if (ctlsize >= 0) {
        !          4820:                /*
        !          4821:                 * Special case; the stream head is required to ensure that
        !          4822:                 * the control part of any message has at least 64 bytes of
        !          4823:                 * space. This is specified in the putmsg (2) manual page!
        !          4824:                 */
        !          4825: 
        !          4826:                if ((ctlmsg = MSGB_ALLOC (ctlsize < 64 ? 64 : ctlsize,
        !          4827:                                          BPRI_LO, KM_SLEEP)) == NULL) {
        !          4828:                        * retvalp = ENOSR;
        !          4829:                        return NULL;
        !          4830:                }
        !          4831: 
        !          4832:                ctlmsg->b_datap->db_type = flags == MSG_HIPRI ? M_PCPROTO :
        !          4833:                                                                M_PROTO;
        !          4834:                ctlmsg->b_band = band;
        !          4835: 
        !          4836:                if (ctlsize > 0 &&
        !          4837:                    copyin (ctlbuf->buf, ctlmsg->b_rptr, ctlsize) != 0) {
        !          4838: 
        !          4839:                        freeb (ctlmsg);
        !          4840:                        * retvalp = EFAULT;
        !          4841:                        return NULL;
        !          4842:                }
        !          4843: 
        !          4844:                ctlmsg->b_wptr += ctlsize;
        !          4845:        } else
        !          4846:                ctlmsg = NULL;          /* paranoia */
        !          4847: 
        !          4848:        if (datasize >= 0) {
        !          4849: 
        !          4850:                if ((datamsg = MSGB_ALLOC (datasize + wroff, BPRI_LO,
        !          4851:                                           KM_SLEEP)) == NULL) {
        !          4852:                        if (ctlsize >= 0)
        !          4853:                                freeb (ctlmsg);
        !          4854: 
        !          4855:                        * retvalp = ENOSR;
        !          4856:                        return NULL;
        !          4857:                }
        !          4858: 
        !          4859:                if (ctlsize < 0)
        !          4860:                        ctlmsg = datamsg;
        !          4861:                else
        !          4862:                        ctlmsg->b_cont = datamsg;
        !          4863: 
        !          4864:                datamsg->b_band = band;
        !          4865:                datamsg->b_wptr = datamsg->b_wptr = datamsg->b_rptr + wroff;
        !          4866: 
        !          4867:                if (datasize > 0 &&
        !          4868:                    copyin (databuf->buf, datamsg->b_rptr, datasize) != 0) {
        !          4869: 
        !          4870:                        freemsg (ctlmsg);
        !          4871: 
        !          4872:                        * retvalp = EFAULT;
        !          4873:                        return NULL;
        !          4874:                }
        !          4875: 
        !          4876:                datamsg->b_wptr += datasize;
        !          4877:        }
        !          4878: 
        !          4879: 
        !          4880:        /*
        !          4881:         * Since the allocation requests could have blocked for memory to
        !          4882:         * become available, and the copy requests could have blocked to
        !          4883:         * resolve page faults, we could actually be a fair way down the track
        !          4884:         * by now.
        !          4885:         *
        !          4886:         * If we were paranoid, we would recheck the flow control parameters
        !          4887:         * and a bunch of other stuff, but there doesn't seem to be a whole
        !          4888:         * lot of point to that. As long as we don't use data that could have
        !          4889:         * changed while we waited, we're fine.
        !          4890:         */
        !          4891: 
        !          4892:        * retvalp = 0;
        !          4893:        return ctlmsg;
        !          4894: }
        !          4895: 
        !          4896: 
        !          4897: /*
        !          4898:  * This function implements the I_FDINSERT ioctl ().
        !          4899:  */
        !          4900: 
        !          4901: #if    __USE_PROTO__
        !          4902: __LOCAL__ int (SHEAD_FDINSERT) (shead_t * sheadp, int mode,
        !          4903:                                struct strfdinsert * fdinsp)
        !          4904: #else
        !          4905: __LOCAL__ int
        !          4906: SHEAD_FDINSERT __ARGS ((sheadp, mode, fdinsp))
        !          4907: shead_t              * sheadp;
        !          4908: int            mode;
        !          4909: struct strfdinsert
        !          4910:              * fdinsp;
        !          4911: #endif
        !          4912: {
        !          4913:        int             retval;
        !          4914:        shead_t       * other;
        !          4915:        mblk_t        * msg;
        !          4916: 
        !          4917:        ASSERT (sheadp != NULL);
        !          4918:        ASSERT (fdinsp != NULL);
        !          4919: 
        !          4920:        /*
        !          4921:         * There are a large number of error conditions to check for this
        !          4922:         * function. Don't lose sight of the fact that the big set of chained
        !          4923:         * conditions below computes "other" for us.
        !          4924:         */
        !          4925:        /*
        !          4926:         * ALIGNMENT-DEPENDENT CODE.
        !          4927:         */
        !          4928: 
        !          4929:        if ((fdinsp->flags != 0 && fdinsp->flags != RS_HIPRI) ||
        !          4930:            ((unsigned) fdinsp->offset & ~ sizeof (int)) != 0 ||
        !          4931:            fdinsp->offset + sizeof (queue_t *) > fdinsp->ctlbuf.len ||
        !          4932:            (other = FH_TO_STREAM (fdinsp->fildes, & retval)) != 0) {
        !          4933:                /*
        !          4934:                 * A failure of any of the above returns EINVAL; according to
        !          4935:                 * streamio (7) EINVAL rather than EBADF results from a bad
        !          4936:                 * file descriptor.
        !          4937:                 */
        !          4938: 
        !          4939:                return EINVAL;
        !          4940:        }
        !          4941: 
        !          4942:        /*
        !          4943:         * Make a band 0 message (possibly high-priority). This can fail if
        !          4944:         * the requested message is too large for the advertised limits set
        !          4945:         * by the next thing downstream.
        !          4946:         *
        !          4947:         * IMPORANT: we *rely* on this function making a message with a single
        !          4948:         * large control block at least as big as the advertised size. If we
        !          4949:         * cannot rely on this function we have to do lots of extra checking
        !          4950:         * which I'd rather avoid.
        !          4951:         */
        !          4952: 
        !          4953:        msg = SHEAD_MAKEMSG (sheadp, mode, & fdinsp->ctlbuf,
        !          4954:                             & fdinsp->databuf,
        !          4955:                             fdinsp->flags ? MSG_HIPRI : MSG_BAND, 0,
        !          4956:                             & retval);
        !          4957:        if (msg == NULL)
        !          4958:                return retval;
        !          4959: 
        !          4960:        /*
        !          4961:         * Note that we don't recheck for hangups even though we could have
        !          4962:         * waited a poentially long time in SHEAD_MAKEMSG (). The hangup
        !          4963:         * condition has plenty of slop in it with the time it takes write
        !          4964:         * messages to move down the queue anyway; drivers and modules have to
        !          4965:         * be able to cope.
        !          4966:         */
        !          4967: 
        !          4968:        * (queue_t **) (msg->b_rptr + fdinsp->offset) = other->sh_head;
        !          4969: 
        !          4970:        putq (W (sheadp->sh_head), msg);
        !          4971: 
        !          4972:        return 0;
        !          4973: }
        !          4974: 
        !          4975: 
        !          4976: /*
        !          4977:  * This function implements the I_FIND ioctl ().
        !          4978:  */
        !          4979: 
        !          4980: #if    __USE_PROTO__
        !          4981: __LOCAL__ int (SHEAD_FIND_MODINFO) (shead_t * sheadp, char * modname,
        !          4982:                                    int * rvalp)
        !          4983: #else
        !          4984: __LOCAL__ int
        !          4985: SHEAD_FIND_MODINFO __ARGS ((sheadp, modname, rvalp))
        !          4986: shead_t              * sheadp;
        !          4987: char         * modname;
        !          4988: int          * rvalp;
        !          4989: #endif
        !          4990: {
        !          4991:        modsw_t       * module;
        !          4992: 
        !          4993:        /*
        !          4994:         * First try to find the module in the global list of modules, then
        !          4995:         * attempt to find that module's info on the stream.
        !          4996:         */
        !          4997: 
        !          4998:        if ((module = FIND_MODULE (modname)) == NULL)
        !          4999:                return EINVAL;
        !          5000:        else {
        !          5001:                queue_t       * scan;
        !          5002:                pl_t            prev_pl;
        !          5003: 
        !          5004:                /*
        !          5005:                 * Walk down the write side of the stream until either the
        !          5006:                 * write side module info matches -or- a cross-point is found.
        !          5007:                 */
        !          5008: 
        !          5009:                scan = W (sheadp->sh_head);
        !          5010: 
        !          5011:                prev_pl = SHEAD_LOCK (sheadp);
        !          5012: 
        !          5013:                while (scan->q_next != NULL) {
        !          5014:                        if ((scan->q_flag & QREADR) !=
        !          5015:                            (scan->q_next->q_flag & QREADR)) {
        !          5016:                                /*
        !          5017:                                 * Set scan to NULL to flag an unsuccessful
        !          5018:                                 * search.
        !          5019:                                 */
        !          5020: 
        !          5021:                                scan = NULL;
        !          5022:                                break;
        !          5023:                        }
        !          5024: 
        !          5025:                        scan = scan->q_next;
        !          5026: 
        !          5027:                        if ((scan->q_flag & QPROCSOFF) != 0)
        !          5028:                                continue;
        !          5029: 
        !          5030:                        if (scan->q_qinfo == module->mod_stream->st_wrinit)
        !          5031:                                break;
        !          5032:                }
        !          5033: 
        !          5034:                SHEAD_UNLOCK (sheadp, prev_pl);
        !          5035: 
        !          5036:                * rvalp = scan != NULL;
        !          5037:        }
        !          5038: 
        !          5039:        return 0;
        !          5040: }
        !          5041: 
        !          5042: 
        !          5043: /*
        !          5044:  * This function implements the I_LIST ioctl () for the case where the user
        !          5045:  * supplies a buffer to copy the module/driver names into.
        !          5046:  */
        !          5047: 
        !          5048: #if    __USE_PROTO__
        !          5049: __LOCAL__ int (SHEAD_LIST) (shead_t * sheadp, struct str_list * slistp,
        !          5050:                            int * rvalp)
        !          5051: #else
        !          5052: __LOCAL__ int
        !          5053: SHEAD_LIST __ARGS ((sheadp, slistp, rvalp))
        !          5054: shead_t              * sheadp;
        !          5055: struct str_list
        !          5056:              * slistp;
        !          5057: int          * rvalp;
        !          5058: #endif
        !          5059: {
        !          5060:        queue_t       * scan;
        !          5061:        int             modcount;
        !          5062:        int             i;
        !          5063:        struct str_mlist
        !          5064:                      * buf;
        !          5065:        struct str_mlist
        !          5066:                      * temp;
        !          5067: 
        !          5068:        if (slistp->sl_nmods < 1)
        !          5069:                return EINVAL;
        !          5070: 
        !          5071:        /*
        !          5072:         * The EAGAIN error documented for I_LIST in streamio (7) is
        !          5073:         * suggestive of how it is implemented; rather than get involved in
        !          5074:         * tricky synchronization issues, copy the module names into a kernel
        !          5075:         * buffer and then copy that to user level.
        !          5076:         */
        !          5077: 
        !          5078:        modcount = SHEAD_MODCOUNT (sheadp);
        !          5079: 
        !          5080:        if (modcount > slistp->sl_nmods)
        !          5081:                modcount = slistp->sl_nmods;
        !          5082: 
        !          5083: 
        !          5084:        /*
        !          5085:         * If we were paranoid, we'd user kmem_zalloc () to ensure that the
        !          5086:         * data we copy to user space contains no sensitive information. As it
        !          5087:         * happens, because of the fact we user strncpy () to fill the buffer
        !          5088:         * with data, we are guaranteed that we have overwritten all of the
        !          5089:         * contents.
        !          5090:         */
        !          5091: 
        !          5092:        if ((buf = (struct str_mlist *) kmem_alloc (modcount * sizeof (* buf),
        !          5093:                                                    KM_SLEEP)) == NULL)
        !          5094:                return EAGAIN;
        !          5095: 
        !          5096:        /*
        !          5097:         * Now fill the buffer in by moving down the stream. We don't worry
        !          5098:         * about the race between the calculation of the buffer size and the
        !          5099:         * time we fill it in, because the problem also exists for the user;
        !          5100:         * in order to know how much space to allocate at user level, some
        !          5101:         * arrangement must have been made to ensure things are stable.
        !          5102:         */
        !          5103: 
        !          5104:        i = 0;
        !          5105:        scan = W (sheadp->sh_head);
        !          5106:        temp = buf;
        !          5107: 
        !          5108:        (void) SHEAD_LOCK (sheadp);
        !          5109: 
        !          5110:        while (scan->q_next != NULL &&
        !          5111:               ((scan->q_flag & QREADR) == (scan->q_next->q_flag & QREADR))) {
        !          5112: 
        !          5113:                scan = scan->q_next;
        !          5114: 
        !          5115:                if ((scan->q_flag & QPROCSOFF) != 0)
        !          5116:                        continue;
        !          5117: 
        !          5118:                if (i ++ > modcount)
        !          5119:                        break;
        !          5120: 
        !          5121:                /*
        !          5122:                 * Now actually copy the module name. Note that we count on
        !          5123:                 * strncpy () null-padding the target for security.
        !          5124:                 */
        !          5125: 
        !          5126:                strncpy (temp->l_name, scan->q_qinfo->qi_minfo->mi_idname,
        !          5127:                         sizeof (temp->l_name) - 1);
        !          5128:                temp->l_name [sizeof (temp->l_name) - 1] = 0;
        !          5129:        }
        !          5130: 
        !          5131:        SHEAD_UNLOCK (sheadp, plbase);
        !          5132: 
        !          5133:        /*
        !          5134:         * After unlocking we can safely call copyout (), which we could not
        !          5135:         * use inside the loop because it may sleep resolving a page fault.
        !          5136:         * Don't forget that copyout () is like bcopy (), not memcpy ()!
        !          5137:         */
        !          5138: 
        !          5139:        * rvalp = i;
        !          5140: 
        !          5141:        i = copyout (buf, slistp->sl_modlist, i * sizeof (* buf));
        !          5142: 
        !          5143:        kmem_free (buf, modcount * sizeof (* buf));
        !          5144: 
        !          5145:        return i == 0 ? 0 : EFAULT;
        !          5146: }
        !          5147: 
        !          5148: 
        !          5149: /*
        !          5150:  * This function deals with setting the stream head read mode flag bits in
        !          5151:  * M_SETOPT messages or from an I_SRDOPT ioctl ().
        !          5152:  */
        !          5153: 
        !          5154: #if    __USE_PROTO__
        !          5155: int (SHEAD_SRDOPT) (shead_t * sheadp, int flag)
        !          5156: #else
        !          5157: int
        !          5158: SHEAD_SRDOPT __ARGS ((sheadp, flag))
        !          5159: shead_t              * sheadp;
        !          5160: int            flag;
        !          5161: #endif
        !          5162: {
        !          5163:        int             newflag;
        !          5164: 
        !          5165:        SHEAD_ASSERT_LOCKED (sheadp);
        !          5166: 
        !          5167:        if ((newflag = flag & RMODEMASK) == __RINVAL)
        !          5168:                return EINVAL;
        !          5169: 
        !          5170:        /*
        !          5171:         * The streamio (7) man pages seem ambiguous about whether an
        !          5172:         * application is permitted to, has to, or cannot diagnose a request
        !          5173:         * to set multiple read options.
        !          5174:         *
        !          5175:         * Arbitrarily, we choose not to.
        !          5176:         */
        !          5177: 
        !          5178:        newflag |= (flag & RPROTNORM) != 0 ? RPROTNORM :
        !          5179:                   (flag & RPROTDAT) != 0 ? RPROTDAT :
        !          5180:                   (flag & RPROTDIS) != 0 ? RPROTDIS :
        !          5181:                        (sheadp->sh_readopt & ~ RMODEMASK);
        !          5182: 
        !          5183:        sheadp->sh_readopt = newflag;
        !          5184: 
        !          5185:        return 0;
        !          5186: }
        !          5187: 
        !          5188: 
        !          5189: /*
        !          5190:  * This table determines how many bytes to copy from user space at the start
        !          5191:  * of ioctl () processing and how many bytes to copy to user space at the end
        !          5192:  * of processing (presuming no other errors have occurred yet).
        !          5193:  */
        !          5194: 
        !          5195: #define        BADLEN          ((unsigned short) -1)
        !          5196: 
        !          5197: typedef enum {
        !          5198:        IO_NOLOCK = 0,
        !          5199:        IO_BASIC_LOCK,
        !          5200:        IO_READFREEZE,
        !          5201:        IO_SLEEP_LOCK
        !          5202: } iolock_t;
        !          5203: 
        !          5204: enum { NOHUP,
        !          5205:        HUP
        !          5206: };
        !          5207: 
        !          5208: static struct ioinfo {
        !          5209:        iolock_t        lock;           /* lock type */
        !          5210:        cat_t           cat;            /* category flag */
        !          5211:        unsigned short  in_len;         /* bytes to copy in */
        !          5212:        unsigned short  out_len;        /* bytes to copy out */
        !          5213:        unsigned char   hup_chk;        /* check for hangup */
        !          5214: } _ioctl_table [] = {
        !          5215:        { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP },
        !          5216:                                        /* illegal */
        !          5217:        { IO_READFREEZE, SH_NONE, sizeof (size_t), NOHUP },
        !          5218:                                                /* I_NREAD */
        !          5219:        { IO_SLEEP_LOCK, SH_OPENCLOSE | SH_IOCTL_LOCK,
        !          5220:                FMNAMESZ + 1, 0, HUP },         /* I_PUSH */
        !          5221:        { IO_SLEEP_LOCK, SH_OPENCLOSE | SH_IOCTL_LOCK, 0, 0, HUP },
        !          5222:                                                /* I_POP */
        !          5223:        { IO_NOLOCK, SH_NONE, FMNAMESZ + 1, FMNAMESZ + 1, NOHUP },
        !          5224:                                                /* I_LOOK */
        !          5225:        { IO_NOLOCK, SH_NONE, 0, 0, HUP },      /* I_FLUSH */
        !          5226:        { IO_BASIC_LOCK, SH_NONE, 0, 0, NOHUP },/* I_SRDOPT */
        !          5227:        { IO_BASIC_LOCK, SH_NONE, 0, sizeof (int), NOHUP },
        !          5228:                                                /* I_GRDOPT */
        !          5229:        { IO_SLEEP_LOCK, SH_IOCTL_LOCK, sizeof (struct strioctl),
        !          5230:                sizeof (struct strioctl), HUP },/* I_STR */
        !          5231:        { IO_SLEEP_LOCK, SH_IOCTL_LOCK, 0, 0, NOHUP },
        !          5232:                                                /* I_SETSIG */
        !          5233:        { IO_SLEEP_LOCK, SH_IOCTL_LOCK, 0, sizeof (int), NOHUP },
        !          5234:                                                /* I_GETSIG */
        !          5235:        { IO_NOLOCK, SH_NONE, FMNAMESZ + 1, 0, NOHUP },
        !          5236:                                                /* I_FIND */
        !          5237:        { IO_SLEEP_LOCK, SH_IOCTL_LOCK, 0, 0, HUP },
        !          5238:                                                /* I_LINK */
        !          5239:        { IO_SLEEP_LOCK, SH_IOCTL_LOCK, 0, 0, HUP },
        !          5240:                                                /* I_UNLINK */
        !          5241:        { IO_SLEEP_LOCK, SH_READ_LOCK, 0, sizeof (struct strrecvfd), HUP },
        !          5242:                                                /* I_RECVFD */
        !          5243:        { IO_SLEEP_LOCK, SH_READ_LOCK, sizeof (struct strpeek),
        !          5244:                sizeof (struct strpeek), NOHUP },/* I_PEEK */
        !          5245:        { IO_NOLOCK, SH_NONE, sizeof (struct strfdinsert), 0, NOHUP },
        !          5246:                                                /* I_FDINSERT */
        !          5247:        { IO_NOLOCK, SH_NONE, 0, 0, HUP },      /* I_SENDFD */
        !          5248:        { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP },
        !          5249:                                        /* --- */
        !          5250:        { IO_BASIC_LOCK, SH_NONE, 0, 0, NOHUP },/* I_SWROPT */
        !          5251:        { IO_BASIC_LOCK, SH_NONE, 0, sizeof (int), NOHUP },
        !          5252:                                                /* I_GWROPT */
        !          5253:        { IO_NOLOCK, SH_NONE, 0, 0, NOHUP },    /* I_LIST */ /* special */
        !          5254:        { IO_BASIC_LOCK, SH_OPENCLOSE | SH_IOCTL_LOCK, 0, 0, HUP },
        !          5255:                                                /* I_PLINK */
        !          5256:        { IO_BASIC_LOCK, SH_OPENCLOSE | SH_IOCTL_LOCK, 0, 0, HUP },
        !          5257:                                                /* I_PUNLINK */
        !          5258:        { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP },
        !          5259:                                        /* I_SETEV */
        !          5260:        { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP },
        !          5261:                                        /* I_GETEV */
        !          5262:        { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP },
        !          5263:                                        /* I_STREV */
        !          5264:        { IO_NOLOCK, SH_NONE, BADLEN, BADLEN, NOHUP },
        !          5265:                                        /* I_UNSTREV */
        !          5266:        { IO_NOLOCK, SH_NONE, sizeof (struct bandinfo), 0, HUP },
        !          5267:                                                /* I_FLUSHBAND */
        !          5268:        { IO_READFREEZE, SH_NONE, 0, 0, NOHUP },/* I_CKBAND */
        !          5269:        { IO_READFREEZE, SH_NONE, 0, sizeof (int), NOHUP },
        !          5270:                                                /* I_GETBAND */
        !          5271:        { IO_READFREEZE, SH_NONE, 0, 0, NOHUP },/* I_ATMARK */
        !          5272:        { IO_BASIC_LOCK, SH_NONE, sizeof (__clock_t), 0, NOHUP },
        !          5273:                                                /* I_SETCLTIME */
        !          5274:        { IO_BASIC_LOCK, SH_NONE, 0, sizeof (__clock_t), NOHUP },
        !          5275:                                                /* I_GETCLTIME */
        !          5276:        { IO_NOLOCK, SH_NONE, 0, 0, HUP }       /* I_CANPUT */
        !          5277: };
        !          5278: 
        !          5279: struct ioinfo  _transparent = {
        !          5280:        IO_SLEEP_LOCK, SH_IOCTL_LOCK, 0, 0, HUP
        !          5281: };
        !          5282: 
        !          5283: 
        !          5284: /*
        !          5285:  * Symbol for accessing the default ioctl () and close timeouts. Consider
        !          5286:  * making this a static variable and initializing it at boot time.
        !          5287:  */
        !          5288: 
        !          5289: #define        IOCTL_TIMEOUT   drv_usectohz ((__clock_t) 15000000L)
        !          5290: 
        !          5291: 
        !          5292: /*
        !          5293:  * Main ioctl () processing for STREAMS files and pipes.
        !          5294:  *
        !          5295:  * This switch+table is an abomination, but trying to emulate C++ style in C
        !          5296:  * to subsume the switch and the above table would probably kill me. This
        !          5297:  * probably is about as short as it can really be.
        !          5298:  */
        !          5299: 
        !          5300: #if    __USE_PROTO__
        !          5301: int (STREAMS_IOCTL) (shead_t * sheadp, int cmd, _VOID * arg, int mode,
        !          5302:                     cred_t * credp, int * rvalp)
        !          5303: #else
        !          5304: int
        !          5305: STREAMS_IOCTL (sheadp, cmd, arg, mode, credp, rvalp)
        !          5306: shead_t              * sheadp;
        !          5307: int            cmd;
        !          5308: _VOID        * arg;
        !          5309: int            mode;
        !          5310: cred_t       * credp;
        !          5311: int          * rvalp;
        !          5312: #endif
        !          5313: {
        !          5314:        union {
        !          5315:                int             i_int;
        !          5316:                __clock_t       i_clock;
        !          5317:                size_t          i_size;
        !          5318:                char            i_modname [FMNAMESZ + 1];
        !          5319:                struct strioctl i_strioc;
        !          5320:                struct strrecvfd i_recvfd;
        !          5321:                struct strbuf   i_strbuf;
        !          5322:                struct strfdinsert
        !          5323:                                i_fdinsert;
        !          5324:                struct str_list i_list;
        !          5325:                struct bandinfo i_band;
        !          5326:                struct strpeek  i_peek;
        !          5327:        } iocbuf;
        !          5328:        int             retval;
        !          5329:        struct ioinfo * info;
        !          5330: 
        !          5331:        ASSERT (sheadp != NULL);
        !          5332: 
        !          5333:        /*
        !          5334:         * We start out by copying in the data specified by the table, which
        !          5335:         * means we also get to range-check the ioctl entry if it has the
        !          5336:         * magic STREAMS id.
        !          5337:         */
        !          5338: 
        !          5339:        if ((cmd & ~ 0xFF) == STREAM_I) {
        !          5340:                int             index = cmd & 0xFF;
        !          5341: 
        !          5342:                if (index >= sizeof (_ioctl_table) / sizeof (* info))
        !          5343:                        return EINVAL;
        !          5344: 
        !          5345:                info = & _ioctl_table [index];
        !          5346:        } else
        !          5347:                info = & _transparent;
        !          5348: 
        !          5349:        if (info->in_len == BADLEN)
        !          5350:                return EINVAL;
        !          5351: 
        !          5352:        /*
        !          5353:         * We *must* do the copy before the lock! Never forget that
        !          5354:         * copyin ()/copyout () can block in page fault resolution.
        !          5355:         */
        !          5356: 
        !          5357:        if (info->in_len > 0 && copyin (arg, & iocbuf, info->in_len) != 0)
        !          5358:                return EFAULT;
        !          5359: 
        !          5360:        /*
        !          5361:         * We may wish to check for a hangup or error before proceeding.
        !          5362:         */
        !          5363: 
        !          5364:        (void) SHEAD_LOCK (sheadp);
        !          5365: 
        !          5366:        if (info->hup_chk == HUP &&
        !          5367:            (retval = SHEAD_ERRHUP_LOCKED (sheadp, mode)) != 0)
        !          5368:                return ENXIO;
        !          5369: 
        !          5370:        if (info->lock != IO_BASIC_LOCK)
        !          5371:                SHEAD_UNLOCK (sheadp, plbase);
        !          5372: 
        !          5373:        switch (info->lock) {
        !          5374: 
        !          5375:        case IO_BASIC_LOCK:
        !          5376:                /* stay holding on to the basic lock */
        !          5377:                break;
        !          5378: 
        !          5379:        case IO_READFREEZE:
        !          5380:                (void) QFREEZE_TRACE (sheadp->sh_head, "STREAMS_IOCTL");
        !          5381:                break;
        !          5382: 
        !          5383:        case IO_SLEEP_LOCK:
        !          5384:                if ((retval = SHEAD_SLEEP_LOCK (sheadp, info->cat,
        !          5385:                                                IOCTL_TIMEOUT,
        !          5386:                                                CHECK_SIGNALS)) != 0)
        !          5387:                        return retval;
        !          5388:                break;
        !          5389: 
        !          5390:        default:
        !          5391:                break;
        !          5392:        }
        !          5393: 
        !          5394:        retval = 0;
        !          5395: 
        !          5396:        switch (cmd) {
        !          5397: 
        !          5398:        case I_NREAD:           /* Get message length, count */
        !          5399:                {
        !          5400:                        mblk_t        * scan;
        !          5401:                        mblk_t        * first = NULL;
        !          5402: 
        !          5403:                        * rvalp = 0;
        !          5404: 
        !          5405:                        for (scan = SHEAD_FIRSTMSG (sheadp) ; scan != NULL ;
        !          5406:                             scan = scan->b_next) {
        !          5407: 
        !          5408:                                if (datamsg (scan->b_datap->db_type)) {
        !          5409: 
        !          5410:                                        if (first == NULL)
        !          5411:                                                first = scan;
        !          5412:                                        (* rvalp) ++;
        !          5413:                                }
        !          5414:                        }
        !          5415: 
        !          5416:                        if (first != NULL)
        !          5417:                                iocbuf.i_int = msgdsize (first);
        !          5418:                        else
        !          5419:                                iocbuf.i_int = 0;
        !          5420:                }
        !          5421:                break;
        !          5422: 
        !          5423:        case I_PUSH:            /* push named module */
        !          5424:                {
        !          5425:                        modsw_t       * module;
        !          5426: 
        !          5427:                        if ((module = FIND_MODULE (iocbuf.i_modname)) == NULL)
        !          5428:                                retval = EINVAL;
        !          5429:                        else
        !          5430:                                retval = PUSH_MODULE (sheadp, mode, credp,
        !          5431:                                                      module);
        !          5432:                }
        !          5433:                break;
        !          5434: 
        !          5435:        case I_POP:             /* pop topmost module */
        !          5436:                {
        !          5437:                        queue_t       * q;
        !          5438: 
        !          5439:                        if ((q = TOP_MODULE (sheadp)) == NULL)
        !          5440:                                retval = EINVAL;
        !          5441:                        else
        !          5442:                                retval = POP_MODULE (sheadp, q, mode, credp);
        !          5443:                }
        !          5444:                break;
        !          5445: 
        !          5446:        case I_LOOK:            /* get topmost module name */
        !          5447:                {
        !          5448:                        queue_t       * q;
        !          5449: 
        !          5450:                        if ((q = TOP_MODULE (sheadp)) == NULL)
        !          5451:                                retval = EINVAL;
        !          5452:                        else {
        !          5453:                                /*
        !          5454:                                 * Copy the module name, taking care to
        !          5455:                                 * 0-terminate it at FMNAMESZ bytes long.
        !          5456:                                 */
        !          5457: 
        !          5458:                                strncpy (iocbuf.i_modname,
        !          5459:                                         q->q_qinfo->qi_minfo->mi_idname,
        !          5460:                                         FMNAMESZ);
        !          5461:                                iocbuf.i_modname [FMNAMESZ] = 0;
        !          5462:                        }
        !          5463:                }
        !          5464:                break;
        !          5465: 
        !          5466:        case I_FLUSH:           /* flush read and/or write side */
        !          5467:                retval = SHEAD_FLUSH (sheadp, (int) arg, 0);
        !          5468:                break;
        !          5469: 
        !          5470:        case I_SRDOPT:          /* set read options */
        !          5471:                retval = SHEAD_SRDOPT (sheadp, (int) arg);
        !          5472:                break;
        !          5473: 
        !          5474:        case I_GRDOPT:          /* retrieve read options */
        !          5475:                iocbuf.i_int = sheadp->sh_readopt;
        !          5476:                break;
        !          5477: 
        !          5478:        case I_STR:             /* send ioctl () data down a stream */
        !          5479:                if ((iocbuf.i_strioc.ic_cmd & ~ 0xFF) == STREAM_I ||
        !          5480:                    (unsigned) iocbuf.i_strioc.ic_len == TRANSPARENT) {
        !          5481:                        /*
        !          5482:                         * We do not permit I_STR to send STREAMS ioctl ()
        !          5483:                         * codes downstream; in certain cases such as I_LINK
        !          5484:                         * this could produce disastrous results.
        !          5485:                         *
        !          5486:                         * We also do not permit TRANSPARENT length I_STR
        !          5487:                         * messages. While the STREAMS documentation neither
        !          5488:                         * explicitly permits or forbids this, we keep the
        !          5489:                         * transparent ioctl () behaviour separate.
        !          5490:                         */
        !          5491: 
        !          5492:                        retval = EINVAL;
        !          5493:                        break;
        !          5494: 
        !          5495:                }
        !          5496: 
        !          5497:                retval = ISTR_IOCTL (sheadp, mode, & iocbuf.i_strioc, credp,
        !          5498:                                     rvalp);
        !          5499:                break;
        !          5500: 
        !          5501:        case I_SETSIG:          /* register events for SIGPOLL signal */
        !          5502:                {
        !          5503:                        int             events = (short) (ulong_t) arg;
        !          5504: 
        !          5505:                        if ((events & ~ __POLL_MASK) != 0)
        !          5506:                                retval = EINVAL;
        !          5507:                        else
        !          5508:                                retval = REGISTER_SIGPOLL (sheadp, events);
        !          5509:                }
        !          5510:                break;
        !          5511: 
        !          5512:        case I_GETSIG:          /* return registered event mask */
        !          5513:                {
        !          5514:                        sigpoll_t     * sigs;
        !          5515: 
        !          5516:                        if ((sigs = FIND_SIGPOLL (sheadp)) == NULL)
        !          5517:                                retval = EINVAL;
        !          5518:                        else
        !          5519:                                * rvalp = sigs->sp_events;
        !          5520:                }
        !          5521:                break;
        !          5522: 
        !          5523:        case I_FIND:            /* determine if module exists on stream */
        !          5524:                retval = SHEAD_FIND_MODINFO (sheadp, iocbuf.i_modname, rvalp);
        !          5525:                break;
        !          5526: 
        !          5527:        case I_LINK:            /* link stream below another */
        !          5528:        case I_PLINK:           /* create a persistent link */
        !          5529:                {
        !          5530:                        shead_t       * lower;
        !          5531: 
        !          5532:                        if ((lower = FH_TO_STREAM ((int) arg,
        !          5533:                                                   & retval)) != NULL) {
        !          5534:                                retval = SHEAD_LINK (sheadp, mode, lower, cmd,
        !          5535:                                                     credp);
        !          5536: 
        !          5537:                                if (retval == 0)
        !          5538:                                        * rvalp = lower->sh_muxid;
        !          5539:                        }
        !          5540:                }
        !          5541:                break;
        !          5542: 
        !          5543:        case I_UNLINK:          /* remove a (or all) link(s) below a stream */
        !          5544:        case I_PUNLINK:         /* undo a single or all persistent link(s) */
        !          5545:                do {
        !          5546:                        shead_t       * lower;
        !          5547: 
        !          5548:                        if ((lower = SHEAD_FIND_MUXID (sheadp, cmd,
        !          5549:                                                       (int) arg)) == NULL) {
        !          5550:                                /*
        !          5551:                                 * We return EINVAL if a specific mux ID was
        !          5552:                                 * given, 0 otherwise.
        !          5553:                                 */
        !          5554: 
        !          5555:                                retval = (int) arg == -1 ? 0 : EINVAL;
        !          5556:                                break;
        !          5557: 
        !          5558:                        }
        !          5559: 
        !          5560:                        (void) SHEAD_UNLINK (sheadp, lower, cmd, mode, credp,
        !          5561:                                             & retval);
        !          5562:                } while ((int) arg == -1);
        !          5563:                break;
        !          5564: 
        !          5565:        case I_RECVFD:          /* receive a file descriptor from stream */
        !          5566:                retval = FH_RECV (sheadp, mode, & iocbuf.i_recvfd);
        !          5567:                break;
        !          5568: 
        !          5569:        case I_PEEK:            /* examine data at stream head */
        !          5570:                retval = SHEAD_PEEK (sheadp, & iocbuf.i_peek, rvalp);
        !          5571:                break;
        !          5572: 
        !          5573:        case I_FDINSERT:        /* send read queue pointer down stream */
        !          5574:                retval = SHEAD_FDINSERT (sheadp, mode, & iocbuf.i_fdinsert);
        !          5575:                break;
        !          5576: 
        !          5577:        case I_SENDFD:          /* send a file descriptor down a pipe */
        !          5578:                retval = FH_SEND (sheadp, (int) arg, credp);
        !          5579:                break;
        !          5580: 
        !          5581:        case I_SWROPT:          /* set write options for stream */
        !          5582:                {
        !          5583:                        int             flag = (int) arg;
        !          5584: 
        !          5585:                        if ((flag & ~ SNDZERO) != 0)
        !          5586:                                retval = EINVAL;
        !          5587:                        else
        !          5588:                                sheadp->sh_wropt = flag;
        !          5589:                }
        !          5590:                break;
        !          5591: 
        !          5592:        case I_GWROPT:          /* retrieve write options for stream */
        !          5593:                iocbuf.i_int = sheadp->sh_wropt;
        !          5594:                break;
        !          5595: 
        !          5596:        case I_LIST:            /* get names of all modules/drivers */
        !          5597:                /*
        !          5598:                 * The value of "arg" is a pointer to a structure for this
        !          5599:                 * entry, but since a NULL value is legal we don't copy the
        !          5600:                 * data in automatically.
        !          5601:                 *
        !          5602:                 * Here we select the call type and copy in the structure for
        !          5603:                 * the non-NULL case.
        !          5604:                 */
        !          5605: 
        !          5606:                if (arg == NULL)
        !          5607:                        * rvalp = SHEAD_MODCOUNT (sheadp);
        !          5608:                else if (copyin (arg, & iocbuf, sizeof (iocbuf.i_list)) != 0)
        !          5609:                        retval = EFAULT;
        !          5610:                else
        !          5611:                        retval = SHEAD_LIST (sheadp, & iocbuf.i_list, rvalp);
        !          5612:                break;
        !          5613: 
        !          5614:        case I_SETEV:           /* The meaning of these ioctl ()'s is not */
        !          5615:        case I_GETEV:           /* documented, although their names and */
        !          5616:        case I_STREV:           /* numeric values are given in the System */
        !          5617:        case I_UNSTREV:         /* V ABI. */
        !          5618:                retval = EINVAL;
        !          5619:                break;
        !          5620: 
        !          5621:        case I_FLUSHBAND:       /* flush messages in a priority band */
        !          5622:                retval = SHEAD_FLUSH (sheadp, iocbuf.i_band.bi_flag,
        !          5623:                                      iocbuf.i_band.bi_pri);
        !          5624:                break;
        !          5625: 
        !          5626:        case I_CKBAND:          /* check for existence of band on stream */
        !          5627:                if ((uchar_t) (ulong_t) arg != (ulong_t) arg)
        !          5628:                        retval = EINVAL;
        !          5629:                else {
        !          5630:                        mblk_t        * scan;
        !          5631: 
        !          5632:                        for (scan = SHEAD_FIRSTMSG (sheadp) ; scan != NULL ;
        !          5633:                             scan = scan->b_next)
        !          5634:                                if (datamsg (scan->b_datap->db_type) &&
        !          5635:                                    scan->b_band == (uchar_t) (ulong_t) arg)
        !          5636:                                        break;
        !          5637: 
        !          5638:                        * rvalp = scan != NULL;
        !          5639:                }
        !          5640:                break;
        !          5641: 
        !          5642:        case I_GETBAND:         /* get the band number of the first message */
        !          5643:                {
        !          5644:                        mblk_t       *  scan;
        !          5645: 
        !          5646:                        for (scan = SHEAD_FIRSTMSG (sheadp) ; scan != NULL ;
        !          5647:                             scan = scan->b_next) {
        !          5648: 
        !          5649:                                if (datamsg (scan->b_datap->db_type))
        !          5650:                                        break;
        !          5651:                        }
        !          5652: 
        !          5653:                        if (scan == NULL)
        !          5654:                                retval = ENODATA;
        !          5655:                        else
        !          5656:                                iocbuf.i_int = scan->b_band;
        !          5657:                }
        !          5658:                break;
        !          5659: 
        !          5660:        case I_ATMARK:          /* test for (last) mark on messages */
        !          5661:                {
        !          5662:                        mblk_t        * scan = SHEAD_FIRSTMSG (sheadp);
        !          5663: 
        !          5664:                        if ((ulong_t) arg != ANYMARK &&
        !          5665:                            (ulong_t) arg != LASTMARK) {
        !          5666: 
        !          5667:                                retval = EINVAL;
        !          5668:                                break;
        !          5669:                        }
        !          5670: 
        !          5671:                        if (scan == NULL || (scan->b_flag & MSGMARK) == 0) {
        !          5672: 
        !          5673:                                * rvalp = 0;
        !          5674:                                break;
        !          5675:                        }
        !          5676: 
        !          5677:                        * rvalp = 1;
        !          5678: 
        !          5679:                        if ((ulong_t) arg == LASTMARK)
        !          5680:                                while ((scan = scan->b_next) != NULL)
        !          5681:                                        if ((scan->b_flag & MSGMARK) != 0) {
        !          5682:                                                * rvalp = 0;
        !          5683:                                                break;
        !          5684:                                        }
        !          5685:                }
        !          5686:                break;
        !          5687: 
        !          5688:        case I_SETCLTIME:       /* set close timeout for stream */
        !          5689:                if (iocbuf.i_clock != 0)
        !          5690:                        sheadp->sh_cltime = iocbuf.i_clock;
        !          5691:                else
        !          5692:                        retval = EINVAL;
        !          5693:                break;
        !          5694: 
        !          5695:        case I_GETCLTIME:       /* retrieve current close timeout */
        !          5696:                iocbuf.i_clock = sheadp->sh_cltime;
        !          5697:                break;
        !          5698: 
        !          5699:        case I_CANPUT:          /* test if band is writeable */
        !          5700:                if ((uchar_t) (ulong_t) arg != (ulong_t) arg)
        !          5701:                        retval = EINVAL;
        !          5702:                else
        !          5703:                        * rvalp = bcanputnext (W (sheadp->sh_head),
        !          5704:                                               (uchar_t) (ulong_t) arg);
        !          5705:                break;
        !          5706: 
        !          5707:        default:
        !          5708:                ASSERT (info == & _transparent);
        !          5709: 
        !          5710:                retval = TRANSPARENT_IOCTL (sheadp, mode, cmd, arg, credp,
        !          5711:                                            rvalp);
        !          5712:                break;
        !          5713:        }
        !          5714: 
        !          5715: 
        !          5716:        /*
        !          5717:         * Perform any necessary unlocking operations and copy back any
        !          5718:         * results into the data area pointed to by "arg" (if this is a
        !          5719:         * STREAMS-specific ioctl ()).
        !          5720:         */
        !          5721: 
        !          5722:        switch (info->lock) {
        !          5723: 
        !          5724:        case IO_BASIC_LOCK:
        !          5725:                SHEAD_UNLOCK (sheadp, plbase);
        !          5726:                break;
        !          5727: 
        !          5728:        case IO_READFREEZE:
        !          5729:                (void) QUNFREEZE_TRACE (sheadp->sh_head, plbase);
        !          5730:                break;
        !          5731: 
        !          5732:        case IO_SLEEP_LOCK:
        !          5733:                SHEAD_SLEEP_UNLOCK (sheadp, info->cat);
        !          5734:                break;
        !          5735: 
        !          5736:        default:
        !          5737:                break;
        !          5738:        }
        !          5739: 
        !          5740: 
        !          5741:        /*
        !          5742:         * We only copy out results if there is no error. We have to
        !          5743:         * do this *after* unlocking, above; copyout () can block in
        !          5744:         * page fault resolution!
        !          5745:         */
        !          5746: 
        !          5747:        if (retval == 0 && info->out_len > 0 &&
        !          5748:            copyout (& iocbuf, arg, info->out_len) != 0)
        !          5749:                retval = EFAULT;
        !          5750: 
        !          5751:        return retval;
        !          5752: }
        !          5753: 
        !          5754: 
        !          5755: /*
        !          5756:  * Helper function to atomically read the stream head read options.
        !          5757:  */
        !          5758: 
        !          5759: #if    __USE_PROTO__
        !          5760: __LOCAL__ short (SHEAD_READOPT) (shead_t * sheadp)
        !          5761: #else
        !          5762: __LOCAL__ short
        !          5763: SHEAD_READOPT __ARGS ((sheadp))
        !          5764: shead_t              * sheadp;
        !          5765: #endif
        !          5766: {
        !          5767:        pl_t            prev_pl;
        !          5768:        short           opt;
        !          5769: 
        !          5770:        prev_pl = SHEAD_LOCK (sheadp);
        !          5771: 
        !          5772:        opt = sheadp->sh_readopt;
        !          5773: 
        !          5774:        SHEAD_UNLOCK (sheadp, prev_pl);
        !          5775: 
        !          5776:        return opt;
        !          5777: }
        !          5778: 
        !          5779: 
        !          5780: /*
        !          5781:  * Stream head user-level getmsg () processing.
        !          5782:  *
        !          5783:  * This is way too many parameters; this should be bundled into a block like
        !          5784:  * the "uio" structure is.
        !          5785:  */
        !          5786: 
        !          5787: #if    __USE_PROTO__
        !          5788: int (STREAMS_GETPMSG) (shead_t * sheadp, struct strbuf * ctlbuf,
        !          5789:                       struct strbuf * databuf, int * bandp, int * flagsp,
        !          5790:                       int mode, int * rvalp)
        !          5791: #else
        !          5792: int
        !          5793: STREAMS_GETPMSG __ARGS ((sheadp, ctlbuf, databuf, bandp, flagsp, mode, rvalp))
        !          5794: shead_t              * sheadp;
        !          5795: int            mode;
        !          5796: struct strbuf *        ctlbuf;
        !          5797: struct strbuf *        databuf;
        !          5798: int          * bandp;
        !          5799: int          * flagsp;
        !          5800: int          * rvalp;
        !          5801: #endif
        !          5802: {
        !          5803:        mblk_t        * msg;
        !          5804:        mblk_t        * scan;
        !          5805:        int             retval;
        !          5806: 
        !          5807:        if ((mode & FREAD) == 0)
        !          5808:                return EBADF;
        !          5809: 
        !          5810:        mode &= ~ FWRITE;
        !          5811: 
        !          5812: 
        !          5813:        /*
        !          5814:         * As discussed in the general comment on read synchronization and in
        !          5815:         * the I_PEEK documentation, there are some warts when it comes to
        !          5816:         * read locking. Here we can solve things by dequeueing a message,
        !          5817:         * modifying at, and writing it back without worrying about any nasty
        !          5818:         * unintended effects.
        !          5819:         *
        !          5820:         * Because getmsg ()/getpmsg () always honours message boundaries,
        !          5821:         * there is no real value in single-threading this.
        !          5822:         */
        !          5823: 
        !          5824:        /*
        !          5825:         * Look at the stream head to see if a message is present. Note that
        !          5826:         * we freeze the read queue before acquiring the stream head basic
        !          5827:         * lock because that's our canonical ordering.
        !          5828:         */
        !          5829: 
        !          5830:        for (;;) {
        !          5831:                (void) QFREEZE_TRACE (sheadp->sh_head, "SHEAD_GETPMSG");
        !          5832: 
        !          5833:                (void) SHEAD_LOCK (sheadp);
        !          5834: 
        !          5835:                if ((retval = SHEAD_ERRHUP_LOCKED (sheadp, FREAD)) != 0) {
        !          5836: 
        !          5837:                        QUNFREEZE_TRACE (sheadp->sh_head, plbase);
        !          5838:                        return retval;
        !          5839:                }
        !          5840: 
        !          5841: 
        !          5842:                if ((msg = SHEAD_FIRSTMSG (sheadp)) != NULL) {
        !          5843: 
        !          5844:                        switch (msg->b_datap->db_type) {
        !          5845: 
        !          5846:                        case M_DATA:
        !          5847:                        case M_PROTO:
        !          5848: 
        !          5849:                                if (* flagsp == MSG_HIPRI ||
        !          5850:                                    (* flagsp == MSG_BAND &&
        !          5851:                                     msg->b_band < * bandp)) {
        !          5852: 
        !          5853:                                        sheadp->sh_head->q_lastband =
        !          5854:                                                msg->b_band;
        !          5855:                                        msg = NULL;
        !          5856:                                        break;
        !          5857:                                }
        !          5858: 
        !          5859:                                /* FALL THROUGH */
        !          5860: 
        !          5861:                        case M_PCPROTO:
        !          5862:                                rmvq (sheadp->sh_head, msg);
        !          5863:                                break;
        !          5864: 
        !          5865:                        default:
        !          5866:                                retval = EBADMSG;
        !          5867:                                break;
        !          5868:                        }
        !          5869:                }
        !          5870: 
        !          5871:                QUNFREEZE_TRACE (sheadp->sh_head, plbase);
        !          5872: 
        !          5873:                if (retval != 0)
        !          5874:                        return retval;
        !          5875: 
        !          5876:                if (msg != NULL)
        !          5877:                        break;
        !          5878: 
        !          5879:                /*
        !          5880:                 * We need to wait (unless O_NDELAY or O_NONBLOCK has been
        !          5881:                 * specified). We don't wait any more if the stream has been
        !          5882:                 * hung up.
        !          5883:                 */
        !          5884: 
        !          5885:                if (SHEAD_HANGUP (sheadp)) {
        !          5886:                        /*
        !          5887:                         * Hangups are not an error for getpmsg ().
        !          5888:                         */
        !          5889: 
        !          5890:                        if (ctlbuf != NULL)
        !          5891:                                ctlbuf->len = 0;
        !          5892:                        if (databuf != NULL)
        !          5893:                                databuf->len = 0;
        !          5894: 
        !          5895:                        * rvalp = 0;
        !          5896:                        return 0;
        !          5897:                }
        !          5898: 
        !          5899:                if ((retval = SHEAD_WAIT_NONBLOCK (sheadp, FREAD,
        !          5900:                                                   SH_READ_WAIT,
        !          5901:                                                   CHECK_SIGNALS)) != 0)
        !          5902:                        return retval;
        !          5903:        }
        !          5904: 
        !          5905: 
        !          5906:        /*
        !          5907:         * After this point, "msg" is our responsibility and we either have to
        !          5908:         * free it or put it back if there is an error.
        !          5909:         */
        !          5910: 
        !          5911:        * bandp = msg->b_band;
        !          5912:        * flagsp = msg->b_datap->db_type == M_PCPROTO ? MSG_HIPRI : MSG_BAND;
        !          5913: 
        !          5914:        retval = (COPYOUT_BUF (ctlbuf, & msg, CONTROL_PART) != 0 ||
        !          5915:                  COPYOUT_BUF (databuf, & msg,
        !          5916:                               DATA_PART) != 0) ? EFAULT : 0;
        !          5917: 
        !          5918:        /*
        !          5919:         * Formulate a return mask indicating what components of the message
        !          5920:         * being transferred have not been fully consumed.
        !          5921:         */
        !          5922: 
        !          5923:        * rvalp = 0;
        !          5924: 
        !          5925:        for (scan = msg ; scan != NULL ; scan = scan->b_cont)
        !          5926:                * rvalp |= scan->b_datap->db_type == M_DATA ? MOREDATA
        !          5927:                                                            : MORECTL;
        !          5928: 
        !          5929:        if (msg != NULL)
        !          5930:                putbq (sheadp->sh_head, msg);
        !          5931: 
        !          5932:        return retval;
        !          5933: }
        !          5934: 
        !          5935: 
        !          5936: /*
        !          5937:  * In order to keep the logic of SHEAD_READ () manageable, this section of
        !          5938:  * code has been factored into a separate function. Here we wait for data to
        !          5939:  * become available at the stream head for reading.
        !          5940:  *
        !          5941:  * We return 0 on success, or an error number on failure. The value of "mpp"
        !          5942:  * is only valid if 0 is returned.
        !          5943:  */
        !          5944: 
        !          5945: #if    __USE_PROTO__
        !          5946: __LOCAL__ int (SHEAD_READ_DATA) (shead_t * sheadp, int mode, mblk_t ** mpp,
        !          5947:                                 int resid)
        !          5948: #else
        !          5949: __LOCAL__ int
        !          5950: SHEAD_READ_DATA __ARGS ((sheadp, mode, mpp, resid))
        !          5951: shead_t              * sheadp;
        !          5952: int            mode;
        !          5953: mblk_t      ** mpp;
        !          5954: int            resid;
        !          5955: #endif
        !          5956: {
        !          5957:        int             retval;
        !          5958: 
        !          5959:        for (;;) {
        !          5960:                (void) QFREEZE_TRACE (sheadp->sh_head, "SHEAD_READ");
        !          5961: 
        !          5962:                (void) SHEAD_LOCK (sheadp);
        !          5963: 
        !          5964:                if ((retval = SHEAD_ERRHUP_LOCKED (sheadp, FREAD)) != 0) {
        !          5965: 
        !          5966:                        QUNFREEZE_TRACE (sheadp->sh_head, plbase);
        !          5967:                        return retval;
        !          5968:                }
        !          5969: 
        !          5970: 
        !          5971:                if ((* mpp = SHEAD_FIRSTMSG (sheadp)) != NULL) {
        !          5972: 
        !          5973:                        switch ((* mpp)->b_datap->db_type) {
        !          5974: 
        !          5975:                        case M_PROTO:
        !          5976:                        case M_PCPROTO:
        !          5977:                                /*
        !          5978:                                 * These are valid depending on the read mode
        !          5979:                                 * of the stream.
        !          5980:                                 */
        !          5981: 
        !          5982:                                if ((sheadp->sh_readopt & RPROTNORM) != 0) {
        !          5983: 
        !          5984:                                        retval = EBADMSG;
        !          5985:                                        break;
        !          5986:                                }
        !          5987: 
        !          5988:                                /* FALL THROUGH */
        !          5989: 
        !          5990:                        case M_DATA:
        !          5991:                                rmvq (sheadp->sh_head, * mpp);
        !          5992:                                break;
        !          5993: 
        !          5994:                        default:
        !          5995:                                retval = EBADMSG;
        !          5996:                                break;
        !          5997:                        }
        !          5998:                }
        !          5999: 
        !          6000:                QUNFREEZE_TRACE (sheadp->sh_head, plbase);
        !          6001: 
        !          6002:                if (retval != 0 || * mpp != NULL) {
        !          6003: 
        !          6004:                        SHEAD_UNLOCK (sheadp, plbase);
        !          6005:                        return retval;
        !          6006:                }
        !          6007: 
        !          6008: 
        !          6009:                /*
        !          6010:                 * Since we are going to sleep on a read (), this is the place
        !          6011:                 * to generate M_READ messages if that is how this stream has
        !          6012:                 * been configured.
        !          6013:                 *
        !          6014:                 * If we can't generate an M_READ message, schedule a bufcall.
        !          6015:                 * If we can't do that, return EAGAIN???
        !          6016:                 */
        !          6017: 
        !          6018:                if (SHEAD_READMSG (sheadp)) {
        !          6019:                        mblk_t        * msg;
        !          6020: 
        !          6021:                        if ((msg = MSGB_ALLOC (sizeof (int), BPRI_LO,
        !          6022:                                               KM_NOSLEEP)) == NULL) {
        !          6023:                                /*
        !          6024:                                 * Execute a short wait for buffer memory for
        !          6025:                                 * the M_READ, then retry the loop. Note that
        !          6026:                                 * SHEAD_READ_BUFCALL () unlocks the stream
        !          6027:                                 * head for us.
        !          6028:                                 */
        !          6029: 
        !          6030:                                if ((retval = SHEAD_READ_BUFCALL (sheadp,
        !          6031:                                                                  mode)) != 0)
        !          6032:                                        return retval;
        !          6033: 
        !          6034:                                continue;
        !          6035:                        }
        !          6036: 
        !          6037:                        msg->b_datap->db_type = M_READ;
        !          6038:                        * (int *) msg->b_rptr = resid;
        !          6039:                        msg->b_wptr += sizeof (int);
        !          6040: 
        !          6041:                        putq (W (sheadp->sh_head), msg);
        !          6042:                }
        !          6043: 
        !          6044:                if ((retval = SHEAD_WAIT_NONBLOCK (sheadp, mode, SH_READ_WAIT,
        !          6045:                                                   CHECK_SIGNALS)) != 0)
        !          6046:                        return retval;
        !          6047:        }
        !          6048: 
        !          6049: }
        !          6050: 
        !          6051: 
        !          6052: /*
        !          6053:  * In order to keep the logic of SHEAD_READ () manageable, this section of
        !          6054:  * code has been factored into this routine, which manages the transfer of
        !          6055:  * message data to the user.
        !          6056:  *
        !          6057:  * We return EAGAIN to the user if more data needs to be read, 0 if the read
        !          6058:  * has successfully completed, or some other error number on failure.
        !          6059:  */
        !          6060: 
        !          6061: #if    __USE_PROTO__
        !          6062: __LOCAL__ int (SHEAD_READ_MOVE) (shead_t * sheadp, uio_t * uiop,
        !          6063:                                 mblk_t * msg)
        !          6064: #else
        !          6065: __LOCAL__ int
        !          6066: SHEAD_READ_MOVE __ARGS ((sheadp, uiop, msg))
        !          6067: shead_t              * sheadp;
        !          6068: uio_t        * uiop;
        !          6069: mblk_t       * msg;
        !          6070: #endif
        !          6071: {
        !          6072:        int             readopt = SHEAD_READOPT (sheadp);
        !          6073:        mblk_t        * scan;
        !          6074: 
        !          6075:        if ((readopt & RMODEMASK) == RNORM &&
        !          6076:            (msg->b_cont == NULL && msg->b_rptr == msg->b_wptr)) {
        !          6077:                /*
        !          6078:                 * We have run into a zero-length message. Put it
        !          6079:                 * back and terminate the read.
        !          6080:                 */
        !          6081: 
        !          6082:                putbq (sheadp->sh_head, msg);
        !          6083:                return 0;
        !          6084:        }
        !          6085: 
        !          6086:        if ((readopt & RPROTDIS) != 0) {
        !          6087: 
        !          6088:                while (msg != NULL && msg->b_datap->db_type != M_DATA) {
        !          6089:                        /*
        !          6090:                         * Consume the control part of the message.
        !          6091:                         */
        !          6092: 
        !          6093:                        scan = msg->b_cont;
        !          6094:                        freeb (msg);
        !          6095:                        msg = scan;
        !          6096:                }
        !          6097: 
        !          6098:                if (msg == NULL)
        !          6099:                        return EAGAIN;
        !          6100:        }
        !          6101: 
        !          6102: 
        !          6103:        /*
        !          6104:         * Actual data transfer time; copy each message segment to the user
        !          6105:         * with uiomove ().
        !          6106:         */
        !          6107: 
        !          6108:        do {
        !          6109:                size_t          unit = msg->b_wptr - msg->b_rptr;
        !          6110: 
        !          6111:                if (unit > uiop->uio_resid)
        !          6112:                        unit = uiop->uio_resid;
        !          6113: 
        !          6114:                if (unit > 0 &&
        !          6115:                    uiomove (msg->b_rptr, unit, UIO_READ, uiop) != 0) {
        !          6116:                        /*
        !          6117:                         * Address fault time. But first, put back the data.
        !          6118:                         */
        !          6119: 
        !          6120:                        putbq (sheadp->sh_head, msg);
        !          6121: 
        !          6122:                        return EFAULT;
        !          6123:                }
        !          6124: 
        !          6125:                msg->b_rptr += unit;
        !          6126: 
        !          6127:                if (msg->b_wptr != msg->b_rptr) {
        !          6128:                        /*
        !          6129:                         * Since we didn't finish this message block, we must
        !          6130:                         * be finished with the read (). If we are in message-
        !          6131:                         * discard mode we throw away the remaining data.
        !          6132:                         */
        !          6133: 
        !          6134:                        ASSERT (uiop->uio_resid == 0);
        !          6135: 
        !          6136:                        if ((readopt & RMODEMASK) == RMSGD)
        !          6137:                                freemsg (msg);
        !          6138:                        else
        !          6139:                                putbq (sheadp->sh_head, msg);
        !          6140: 
        !          6141:                        return 0;
        !          6142:                }
        !          6143: 
        !          6144:                scan = msg->b_cont;
        !          6145:                freeb (msg);
        !          6146:        } while ((msg = scan) != NULL);
        !          6147: 
        !          6148: 
        !          6149:        /*
        !          6150:         * We have run out of message; what now? If in byte-stream mode, look
        !          6151:         * for more data, otherwise exit.
        !          6152:         */
        !          6153: 
        !          6154:        return (readopt & RMODEMASK) == RNORM ? EAGAIN : 0;
        !          6155: }
        !          6156: 
        !          6157: 
        !          6158: /*
        !          6159:  * Stream head user-level read processing.
        !          6160:  *
        !          6161:  * I apologise for the abysmal structure of this code; the gotos should be
        !          6162:  * replaced by proper loops and the major subsections factored into auxiliary
        !          6163:  * functions, but this code is the victim of time pressure and several
        !          6164:  * rewrites. By all means encourage the author to improve this in case he has
        !          6165:  * forgotten to come back and fix it.
        !          6166:  */
        !          6167: 
        !          6168: #if    __USE_PROTO__
        !          6169: int (STREAMS_READ) (shead_t * sheadp, uio_t * uiop)
        !          6170: #else
        !          6171: int
        !          6172: STREAMS_READ __ARGS ((sheadp, uiop))
        !          6173: shead_t              * sheadp;
        !          6174: uio_t        * uiop;
        !          6175: #endif
        !          6176: {
        !          6177:        mblk_t        * msg;
        !          6178:        int             retval;
        !          6179:        int             mode;
        !          6180:        int             readcount = uiop->uio_resid;
        !          6181: 
        !          6182:        if ((uiop->uio_fmode & FREAD) == 0)
        !          6183:                return EBADF;
        !          6184: 
        !          6185:        mode = uiop->uio_fmode & ~ FWRITE;
        !          6186: 
        !          6187: 
        !          6188:        /*
        !          6189:         * We (optionally) take out a lock on the stream head to single-thread
        !          6190:         * reads. This is important because in byte-stream mode we may want
        !          6191:         * to guarantee atomicity of reads. This is only relevant to byte-
        !          6192:         * stream mode because modes which honor message boundaries cannot
        !          6193:         * be protected against multiple readers anyway.
        !          6194:         */
        !          6195: 
        !          6196:        if ((retval = SHEAD_SLEEP_LOCK (sheadp, SH_READ_LOCK, 0,
        !          6197:                                        CHECK_SIGNALS)) != 0)
        !          6198:                return retval;
        !          6199: 
        !          6200:        do {
        !          6201:                if ((retval = SHEAD_READ_DATA (sheadp, mode, & msg,
        !          6202:                                               uiop->uio_resid)) != 0)
        !          6203:                        break;
        !          6204: 
        !          6205:                /*
        !          6206:                 * After this point, "msg" is our responsibility and we either
        !          6207:                 * have to free it or put it back if there is an error.
        !          6208:                 */
        !          6209: 
        !          6210:        } while ((retval = SHEAD_READ_MOVE (sheadp, uiop, msg)) == EAGAIN);
        !          6211: 
        !          6212: 
        !          6213:        /*
        !          6214:         * If a partial read has been done, we return a short read rather than
        !          6215:         * reporting an error immediately.
        !          6216:         */
        !          6217: 
        !          6218:        if (retval != 0 && readcount != uiop->uio_resid)
        !          6219:                retval = 0;
        !          6220: 
        !          6221:        SHEAD_SLEEP_UNLOCK (sheadp, SH_READ_LOCK);
        !          6222:        return retval;
        !          6223: }
        !          6224: 
        !          6225: 
        !          6226: /*
        !          6227:  * Helper function to atomically read the stream head write options.
        !          6228:  */
        !          6229: 
        !          6230: #if    __USE_PROTO__
        !          6231: __LOCAL__ short (SHEAD_WRITEOPT) (shead_t * sheadp)
        !          6232: #else
        !          6233: __LOCAL__ short
        !          6234: SHEAD_WRITEOPT __ARGS ((sheadp))
        !          6235: shead_t              * sheadp;
        !          6236: #endif
        !          6237: {
        !          6238:        pl_t            prev_pl;
        !          6239:        short           opt;
        !          6240: 
        !          6241:        prev_pl = SHEAD_LOCK (sheadp);
        !          6242: 
        !          6243:        opt = sheadp->sh_wropt;
        !          6244: 
        !          6245:        SHEAD_UNLOCK (sheadp, prev_pl);
        !          6246: 
        !          6247:        return opt;
        !          6248: }
        !          6249: 
        !          6250: 
        !          6251: /*
        !          6252:  * Stream head user level putpmsg () processing. As with getmsg (), there are
        !          6253:  * enough parameters being passed that this should be abstracted into a
        !          6254:  * structure like uio(D4DK).
        !          6255:  */
        !          6256: 
        !          6257: #if    __USE_PROTO__
        !          6258: int (STREAMS_PUTPMSG) (shead_t * sheadp, struct strbuf * ctlbuf,
        !          6259:                       struct strbuf * databuf, int band, int flags,
        !          6260:                       int mode, int * rvalp)
        !          6261: #else
        !          6262: int
        !          6263: STREAMS_PUTPMSG __ARGS ((sheadp, ctlbuf, databuf, band, flags, mode, rvalp))
        !          6264: shead_t              * sheadp;
        !          6265: int            mode;
        !          6266: struct strbuf *        ctlbuf;
        !          6267: struct strbuf *        databuf;
        !          6268: int            band;
        !          6269: int            flags;
        !          6270: int          * rvalp;
        !          6271: #endif
        !          6272: {
        !          6273:        mblk_t        * msg;
        !          6274:        int             retval;
        !          6275: 
        !          6276:        /*
        !          6277:         * Make a message (possibly high-priority). This can fail if the
        !          6278:         * requested message is too large for the advertised limits set by the
        !          6279:         * next thing downstream. SHEAD_MAKEMSG () also checks for error and
        !          6280:         * hangup conditions, FNDELAY/FNONBLOCK, and flow control.
        !          6281:         */
        !          6282: 
        !          6283:        msg = SHEAD_MAKEMSG (sheadp, mode, ctlbuf, databuf, flags, band,
        !          6284:                             & retval);
        !          6285: 
        !          6286:        if (msg == NULL)
        !          6287:                return retval;
        !          6288: 
        !          6289:        /*
        !          6290:         * Note that we don't recheck for hangups even though we could have
        !          6291:         * waited a poentially long time in SHEAD_MAKEMSG (). The hangup
        !          6292:         * condition has plenty of slop in it with the time it takes write
        !          6293:         * messages to move down the queue anyway; drivers and modules have to
        !          6294:         * be able to cope.
        !          6295:         */
        !          6296: 
        !          6297:        putq (W (sheadp->sh_head), msg);
        !          6298: 
        !          6299:        * rvalp = 0;
        !          6300:        return 0;
        !          6301: }
        !          6302: 
        !          6303: 
        !          6304: /*
        !          6305:  * Stream head user-level write processing.
        !          6306:  *
        !          6307:  * I apologise for the abysmal structure of this code; the gotos should be
        !          6308:  * replaced by proper loops and the major subsections factored into auxiliary
        !          6309:  * functions, but this code is the victim of time pressure and several
        !          6310:  * rewrites. By all means encourage the author to improve this in case he has
        !          6311:  * forgotten to come back and fix it.
        !          6312:  */
        !          6313: 
        !          6314: #if    __USE_PROTO__
        !          6315: int (STREAMS_WRITE) (shead_t * sheadp, uio_t * uiop)
        !          6316: #else
        !          6317: int
        !          6318: STREAMS_WRITE __ARGS ((sheadp, uiop))
        !          6319: shead_t              * sheadp;
        !          6320: uio_t        * uiop;
        !          6321: #endif
        !          6322: {
        !          6323:        queue_t       * q;
        !          6324:        short           wropt = SHEAD_WRITEOPT (sheadp);
        !          6325:        mblk_t        * datamsg;
        !          6326:        int             datasize;
        !          6327:        int             wroff;
        !          6328:        int             retval;
        !          6329:        int             mode;
        !          6330:        int             writecount;
        !          6331: 
        !          6332:        if ((uiop->uio_fmode & FWRITE) == 0)
        !          6333:                return EBADF;
        !          6334: 
        !          6335:        mode = uiop->uio_fmode & ~ FREAD;
        !          6336: 
        !          6337: 
        !          6338:        /*
        !          6339:         * Deal with the zero-length-message special case.
        !          6340:         */
        !          6341: 
        !          6342:        if ((writecount = uiop->uio_resid) == 0 && (wropt & SNDZERO) == 0)
        !          6343:                return 0;
        !          6344: 
        !          6345:        /*
        !          6346:         * Unlike putmsg ()/putpmsg (), write () can potentially spread the
        !          6347:         * data it writes over multiple messages and take a considerable time
        !          6348:         * to do it, we allow for the possibility of locking the stream head
        !          6349:         * so that only one write () is in progress at any time.
        !          6350:         *
        !          6351:         * The primary purpose of this is to allow PIPE_BUF to be effectively
        !          6352:         * unlimited. This is an experimental idea, though.
        !          6353:         */
        !          6354: 
        !          6355:        if ((retval = SHEAD_SLEEP_LOCK (sheadp, SH_WRITE_LOCK, 0,
        !          6356:                                        CHECK_SIGNALS)) != 0)
        !          6357:                return retval;
        !          6358: 
        !          6359:        wroff = SHEAD_WRITEOFFSET (sheadp);
        !          6360: 
        !          6361:        q = TOP_QUEUE (sheadp);
        !          6362: 
        !          6363:        do {
        !          6364: 
        !          6365:                if ((datasize = uiop->uio_resid) + wroff > q->q_maxpsz) {
        !          6366:                        /*
        !          6367:                         * Special case (documented on the write (2) manual
        !          6368:                         * page; if we can't fit within the max/min range and
        !          6369:                         * the minimum is greater than 0, return ERANGE.
        !          6370:                         */
        !          6371: 
        !          6372:                        if (q->q_minpsz > 0) {
        !          6373: 
        !          6374:                                retval = ERANGE;
        !          6375:                                break;
        !          6376:                        }
        !          6377: 
        !          6378:                        datasize = q->q_maxpsz - wroff;
        !          6379:                } else if (datasize + wroff < q->q_minpsz) {
        !          6380: 
        !          6381:                        retval = ERANGE;
        !          6382:                        break;
        !          6383:                }
        !          6384: 
        !          6385: 
        !          6386:                /*
        !          6387:                 * Let's see if the stream is flow controlled; if it is, we
        !          6388:                 * either block or return EAGAIN depending on the
        !          6389:                 * FNDELAY/FNONBLOCK setting.
        !          6390:                 */
        !          6391: 
        !          6392:                if ((retval = SHEAD_WRITE_TEST (sheadp, mode, 0, 0)) != 0)
        !          6393:                        break;
        !          6394: 
        !          6395:                if ((datamsg = MSGB_ALLOC (datasize + wroff, BPRI_LO,
        !          6396:                                           KM_SLEEP)) == NULL) {
        !          6397:                        retval = ENOSR;
        !          6398:                        break;
        !          6399:                }
        !          6400: 
        !          6401:                datamsg->b_wptr = datamsg->b_rptr = datamsg->b_rptr + wroff;
        !          6402: 
        !          6403:                if (datasize > 0 &&
        !          6404:                    uiomove (datamsg->b_rptr, datasize, UIO_WRITE,
        !          6405:                             uiop) != 0) {
        !          6406: 
        !          6407:                        freemsg (datamsg);
        !          6408: 
        !          6409:                        retval = EFAULT;
        !          6410:                        break;
        !          6411:                }
        !          6412: 
        !          6413:                datamsg->b_wptr += datasize;
        !          6414: 
        !          6415:                /*
        !          6416:                 * Now do the write, and see if there is more data.
        !          6417:                 */
        !          6418: 
        !          6419:                putq (W (sheadp->sh_head), datamsg);
        !          6420: 
        !          6421:        } while (uiop->uio_resid > 0);
        !          6422: 
        !          6423: 
        !          6424:        /*
        !          6425:         * If there has been an error after some data was actually written
        !          6426:         * we return a short read rather than report the error immediately.
        !          6427:         */
        !          6428: 
        !          6429:        if (retval != 0 && uiop->uio_resid != writecount)
        !          6430:                retval = 0;
        !          6431: 
        !          6432:        SHEAD_SLEEP_UNLOCK (sheadp, SH_WRITE_LOCK);
        !          6433:        return retval;
        !          6434: }
        !          6435: 
        !          6436: 
        !          6437: /*
        !          6438:  * Stream head user-level open processing.
        !          6439:  */
        !          6440: 
        !          6441: extern struct streamtab headinfo;
        !          6442: 
        !          6443: #if    __USE_PROTO__
        !          6444: int (STREAMS_OPEN) (n_dev_t * devp, struct streamtab * stabp, int mode,
        !          6445:                    cred_t * credp)
        !          6446: #else
        !          6447: int
        !          6448: STREAMS_OPEN (devp, stabp, mode, credp)
        !          6449: n_dev_t              * devp;
        !          6450: struct streamtab
        !          6451:              * stabp;
        !          6452: int            mode;
        !          6453: cred_t       * credp;
        !          6454: #endif
        !          6455: {
        !          6456:        shead_t       * sheadp;
        !          6457:        queue_t       * q;
        !          6458:        int             retval;
        !          6459:        n_dev_t         dev;
        !          6460: 
        !          6461:        ASSERT (devp != NULL);
        !          6462:        ASSERT (stabp != NULL);
        !          6463:        ASSERT (credp != NULL);
        !          6464: 
        !          6465: 
        !          6466:        dev = * devp;
        !          6467: 
        !          6468:        if ((sheadp = SHEAD_OPEN_LOCK (* devp, stabp, & retval)) == NULL)
        !          6469:                return retval;
        !          6470: 
        !          6471:        /*
        !          6472:         * If this is the first open of the stream, set up the stream head
        !          6473:         * entry points and the driver entry points.
        !          6474:         */
        !          6475: 
        !          6476:        q = W (sheadp->sh_head)->q_next;
        !          6477: 
        !          6478:        if (sheadp->sh_open_count == 0) {
        !          6479: 
        !          6480:                QUEUE_INIT (sheadp->sh_head, & headinfo, QI_NORMAL);
        !          6481:                qprocson (sheadp->sh_head);
        !          6482: 
        !          6483:                QUEUE_INIT (R (q), stabp, QI_NORMAL);
        !          6484:        }
        !          6485: 
        !          6486: 
        !          6487:        /*
        !          6488:         * Now we have a stream head (locked, no less), we can call the open
        !          6489:         * entry points of all the modules and the driver. In the special case
        !          6490:         * where the open count of the entry is 0, we allow the driver to
        !          6491:         * change the "dev_t" value to a previously unused number.
        !          6492:         */
        !          6493: 
        !          6494:        do {
        !          6495:                retval = (* R (q)->q_qinfo->qi_qopen)
        !          6496:                                (R (q), & dev, mode,
        !          6497:                                 q->q_next == NULL ? 0 : MODOPEN, credp);
        !          6498: 
        !          6499:                if (dev != * devp && q->q_next != NULL) {
        !          6500:                        /*
        !          6501:                         * A module has changed the device number that we
        !          6502:                         * passed a pointer to. This is not valid!
        !          6503:                         */
        !          6504: 
        !          6505:                        cmn_err (CE_WARN, "Module \"%s\" changed its device number",
        !          6506:                                 q->q_qinfo->qi_minfo->mi_idname);
        !          6507:                        retval = ENXIO;
        !          6508:                }
        !          6509: 
        !          6510:                if (retval != 0)
        !          6511:                        goto failure;
        !          6512:        } while ((q = q->q_next) != NULL);
        !          6513: 
        !          6514: 
        !          6515:        /*
        !          6516:         * The modules and driver have all OK'ed the open, so increment the
        !          6517:         * open count. Here we also check for the clone case.
        !          6518:         *
        !          6519:         * If we want to detect an error after this point, we should execute
        !          6520:         * a close.
        !          6521:         */
        !          6522: 
        !          6523:        sheadp->sh_open_count ++;
        !          6524: 
        !          6525:        if (dev != * devp) {
        !          6526:                /*
        !          6527:                 * The driver has requested that the device number of the
        !          6528:                 * queue be assigned differently than the initial device
        !          6529:                 * number. This is only really valid if this is the first open
        !          6530:                 * of the given queue.
        !          6531:                 */
        !          6532: 
        !          6533:                if (sheadp->sh_open_count > 1) {
        !          6534: 
        !          6535:                        cmn_err (CE_WARN, "Driver \"%s\" changed its device number after inital open",
        !          6536:                                 q->q_qinfo->qi_minfo->mi_idname);
        !          6537: 
        !          6538:                        sheadp->sh_open_count --;
        !          6539: 
        !          6540:                        retval = ENXIO;
        !          6541:                        goto failure;
        !          6542:                }
        !          6543: 
        !          6544: 
        !          6545:                /*
        !          6546:                 * Other open attempts may be waiting on the stream head for
        !          6547:                 * the original device number; they need a wakeup.
        !          6548:                 */
        !          6549: 
        !          6550:                if (SHEAD_RENAME (sheadp, dev) != 0) {
        !          6551: 
        !          6552:                        cmn_err (CE_WARN, "Clone device number chosen by driver \"%s\"is in use",
        !          6553:                                 q->q_qinfo->qi_minfo->mi_idname);
        !          6554: 
        !          6555:                        if (-- sheadp->sh_open_count == 0)
        !          6556:                                SHEAD_DO_CLOSE (sheadp, mode, credp);
        !          6557: 
        !          6558:                        retval = ENXIO;
        !          6559:                        goto failure;
        !          6560:                }
        !          6561: 
        !          6562:                * devp = dev;
        !          6563:        }
        !          6564: 
        !          6565: failure:
        !          6566:        /*
        !          6567:         * The module or driver has failed the open request. We unlock the
        !          6568:         * stream head, which may deallocate the stream head if the open count
        !          6569:         * is 0.
        !          6570:         */
        !          6571: 
        !          6572:        SHEAD_SLEEP_UNLOCK (sheadp, SH_OPENCLOSE);
        !          6573:        return retval;
        !          6574: }
        !          6575: 
        !          6576: 
        !          6577: /*
        !          6578:  * Stream head interface to generic polling.
        !          6579:  */
        !          6580: 
        !          6581: #if    __USE_PROTO__
        !          6582: int (STREAMS_CHPOLL) (shead_t * sheadp, short events, int anyyet,
        !          6583:                      short * reventsp, struct pollhead ** phpp)
        !          6584: #else
        !          6585: int
        !          6586: STREAMS_CHPOLL __ARGS ((sheadp, events, anyyet, reventsp, phpp))
        !          6587: shead_t              * sheadp;
        !          6588: short          events;
        !          6589: int            anyyet;
        !          6590: short        * reventsp;
        !          6591: struct pollhead
        !          6592:             ** phpp;
        !          6593: #endif
        !          6594: {
        !          6595:        short           my_events;
        !          6596: 
        !          6597:        /*
        !          6598:         * The chpoll () entry point uses the POLL... constants rather than
        !          6599:         * the S_... constants that I_SETSIG uses. We convert to the S_...
        !          6600:         * form for our internal use... see <sys/poll.h>
        !          6601:         */
        !          6602: 
        !          6603:        my_events = (events & (__POLL_INPUT | __POLL_HIPRI | __POLL_OUTPUT |
        !          6604:                               __POLL_RDNORM | __POLL_OUTPUT |
        !          6605:                               __POLL_RDBAND | __POLL_WRBAND));
        !          6606: 
        !          6607:        if ((events & POLLERR) != 0)
        !          6608:                my_events = S_ERROR;
        !          6609:        if ((events & POLLHUP) != 0)
        !          6610:                my_events = S_HANGUP;
        !          6611: 
        !          6612:        if ((my_events = SHEAD_POLL_CHECK (sheadp, my_events)) == 0) {
        !          6613: 
        !          6614:                * reventsp = 0;
        !          6615: 
        !          6616:                if (anyyet == 0)
        !          6617:                        * phpp = sheadp->sh_pollhead;
        !          6618:        } else
        !          6619:                * reventsp = my_events;
        !          6620: 
        !          6621:        return 0;
        !          6622: }
        !          6623: 
        !          6624: 
        !          6625: /*
        !          6626:  * Stream head user-level close processing.
        !          6627:  */
        !          6628: 
        !          6629: #if    __USE_PROTO__
        !          6630: int (STREAMS_CLOSE) (shead_t * sheadp, int mode, cred_t * credp)
        !          6631: #else
        !          6632: int
        !          6633: STREAMS_CLOSE __ARGS ((sheadp, mode, credp))
        !          6634: shead_t              * sheadp;
        !          6635: int            mode;
        !          6636: cred_t       * credp;
        !          6637: #endif
        !          6638: {
        !          6639:        int             retval;
        !          6640: 
        !          6641:        if ((retval = SHEAD_SLEEP_LOCK (sheadp, SH_OPENCLOSE | SH_IOCTL_LOCK,
        !          6642:                                        0, CHECK_SIGNALS)) != 0)
        !          6643:                return retval;
        !          6644: 
        !          6645:        if (-- sheadp->sh_open_count == 0)
        !          6646:                SHEAD_DO_CLOSE (sheadp, mode, credp);
        !          6647: 
        !          6648:        SHEAD_SLEEP_UNLOCK (sheadp, SH_OPENCLOSE | SH_IOCTL_LOCK);
        !          6649: 
        !          6650:        return 0;
        !          6651: }

unix.superglobalmegacorp.com

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