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

1.1       root        1: #define        _DDI_DKI        1
                      2: #define        _SYSV4          1
                      3: 
                      4: /*
                      5:  * This file contains various miscellaneous STREAMS library functions that
                      6:  * have been moved into a file on their own. Mostly, this stuff deals with
                      7:  * scheduling STREAMS service procedures, running STREAMS service procedures,
                      8:  * invoking bufcall ()/esbbcall () events, and similar stuff.
                      9:  */
                     10: 
                     11: #include <common/ccompat.h>
                     12: #include <kernel/strmlib.h>
                     13: #include <sys/debug.h>
                     14: #include <sys/types.h>
                     15: #include <sys/kmem.h>
                     16: #include <sys/stream.h>
                     17: 
                     18: 
                     19: /*
                     20:  * Allocate and initialize a schedule.
                     21:  *
                     22:  * Callable only from base level. This function may sleep.
                     23:  */
                     24: 
                     25: #if    __USE_PROTO__
                     26: ssched_t * (QSCHED_ALLOC) (void)
                     27: #else
                     28: ssched_t *
                     29: QSCHED_ALLOC __ARGS (())
                     30: #endif
                     31: {
                     32:        ssched_t      * sched;
                     33: 
                     34:        if ((sched = (ssched_t *) kmem_alloc (sizeof (* sched), KM_SLEEP))
                     35:            != NULL) {
                     36: 
                     37:                if (SCHLOCK_INIT (sched, KM_SLEEP) == 0) {
                     38: 
                     39:                        kmem_free (sched, sizeof (* sched));
                     40:                        return NULL;
                     41:                }
                     42: 
                     43:                sched->ss_head = sched->ss_tail = NULL;
                     44:        }
                     45: 
                     46:        return sched;
                     47: }
                     48: 
                     49: 
                     50: /*
                     51:  * Destroy a schedule.
                     52:  *
                     53:  * The schedule most not have any STREAMS queues threaded on it.
                     54:  */
                     55: 
                     56: #if    __USE_PROTO__
                     57: void (QSCHED_FREE) (ssched_t * sched)
                     58: #else
                     59: void
                     60: QSCHED_FREE __ARGS ((sched))
                     61: ssched_t      *        sched;
                     62: #endif
                     63: {
                     64:        ASSERT (sched != NULL);
                     65:        ASSERT (sched->ss_head == NULL && sched->ss_tail == NULL);
                     66: 
                     67:        SCHLOCK_DESTROY (sched);
                     68: 
                     69:        kmem_free (sched, sizeof (* sched));
                     70: }
                     71: 
                     72: 
                     73: /*
                     74:  * Remove a queue from a schedule. This function is available for modules and
                     75:  * drivers to call. Note that STREAMS itself will only call this function at
                     76:  * queue destruction time.
                     77:  */
                     78: 
                     79: #if    __USE_PROTO__
                     80: void (QSCHED_UNSCHEDULE) (queue_t * q, ssched_t * sched)
                     81: #else
                     82: void
                     83: QSCHED_UNSCHEDULE __ARGS ((q, sched))
                     84: queue_t              * q;
                     85: ssched_t      *        sched;
                     86: #endif
                     87: {
                     88:        pl_t            lock_pl;
                     89:        queue_t       * scan;
                     90:        queue_t       * prev;
                     91: 
                     92:        ASSERT (sched != NULL);
                     93:        QUEUE_TRACE (q, "QUEUE_UNSCHEDULE");
                     94: 
                     95:        lock_pl = SCHLOCK_LOCK (sched, "QUEUE_UNSCHEDULE");
                     96: 
                     97:        for (scan = sched->ss_head, prev = NULL ; scan != NULL ;
                     98:             scan = (prev = scan)->q_link) {
                     99: 
                    100:                if (scan == q) {
                    101: 
                    102:                        if (prev == NULL)
                    103:                                sched->ss_head = q->q_next;
                    104:                        else
                    105:                                prev->q_link = q->q_next;
                    106: 
                    107:                        if (sched->ss_tail == q)
                    108:                                sched->ss_tail = prev;
                    109:                        break;
                    110:                }
                    111:        }
                    112: 
                    113:        SCHLOCK_UNLOCK (str_mem->sm_sched, lock_pl);
                    114: }
                    115: 
                    116: 
                    117: /*
                    118:  * Dequeue and return the first stream in the schedule.
                    119:  */
                    120: 
                    121: #if    __USE_PROTO__
                    122: queue_t * (QSCHED_GETFIRST) (ssched_t * sched)
                    123: #else
                    124: queue_t *
                    125: QSCHED_GETFIRST __ARGS ((sched))
                    126: ssched_t      *        sched;
                    127: #endif
                    128: {
                    129:        pl_t            prev_pl;
                    130:        queue_t       * q;
                    131: 
                    132:        ASSERT (sched != NULL);
                    133: 
                    134:        prev_pl = SCHLOCK_LOCK (sched, "QSCHED_GETFIRST");
                    135: 
                    136:        if ((q = sched->ss_head) != NULL) {
                    137: 
                    138:                if ((sched->ss_head = q->q_link) == NULL)
                    139:                        sched->ss_tail = NULL;
                    140:        }
                    141: 
                    142:        SCHLOCK_UNLOCK (sched, prev_pl);
                    143: 
                    144:        return q;
                    145: }
                    146: 
                    147: 
                    148: /*
                    149:  * Add a queue to a schedule. This function is available for use by modules
                    150:  * and drivers. It is callable from base or interrupt level and does not
                    151:  * sleep.
                    152:  *
                    153:  * The return value is 0 for success, and -1 if it is unable to schedule the
                    154:  * queue.
                    155:  */
                    156: 
                    157: #if    __USE_PROTO__
                    158: int (QSCHED_SCHEDULE) (queue_t * q, ssched_t * sched)
                    159: #else
                    160: int
                    161: QSCHED_SCHEDULE __ARGS ((q, sched))
                    162: queue_t              * q;
                    163: ssched_t      * sched;
                    164: #endif
                    165: {
                    166:        pl_t            lock_pl;
                    167: 
                    168:        QUEUE_TRACE (q, "QSCHED_SCHEDULE");
                    169: 
                    170:        /*
                    171:         * Link this queue into the tail of the scheduling
                    172:         * list after locking the scheduling list.
                    173:         */
                    174: 
                    175:        lock_pl = SCHLOCK_LOCK (sched, "QSCHED_SCHEDULE");
                    176: 
                    177:        q->q_link = NULL;
                    178: 
                    179:        if (sched->ss_tail == NULL)
                    180:                sched->ss_head = q;
                    181:        else
                    182:                sched->ss_tail->q_link = q;
                    183: 
                    184:        sched->ss_tail = q;
                    185: 
                    186:        SCHLOCK_UNLOCK (str_mem->sm_sched, lock_pl);
                    187: 
                    188: 
                    189:        /*
                    190:         * Under this implementation, it is not really possible for a request
                    191:         * to fail, but because we are using STREAMS internal data here, we
                    192:         * allow for a portable implementation that may fail.
                    193:         */
                    194: 
                    195:        return 0;
                    196: }
                    197: 
                    198: 
                    199: /*
                    200:  * Code for checking which bufcall events to call, in a function by itself to
                    201:  * keep things clear and maintainable.
                    202:  *
                    203:  * We take a snapshot of the available memory, then loop over the bufcall ()/
                    204:  * esbbcall () lists and give away memory until our notion of what the memory
                    205:  * pool size ought to be drops to a level where there are cells we think we
                    206:  * should hold off enabling... if we make that decision, we mark things so
                    207:  * that next time through here we look again, then we exit.
                    208:  */
                    209: 
                    210: #if    __USE_PROTO__
                    211: void (RUN_BUFCALLS) (void)
                    212: #else
                    213: void
                    214: RUN_BUFCALLS __ARGS (())
                    215: #endif
                    216: {
                    217:        size_t          mem_level;
                    218:        pl_t            prev_pl;
                    219:        sevent_t      * runlist;
                    220:        sevent_t      * seventp;
                    221:        int             i;
                    222: 
                    223:        /*
                    224:         * Take a snapshot of the amount of STREAMS memory that is in use, so
                    225:         * we can parcel it out to the bufcall routines. We clear the bufcall
                    226:         * defer flag now so that if STREAMS memory is made available after
                    227:         * our snapshot we will be run again.
                    228:         */
                    229: 
                    230:        ATOMIC_STORE_UCHAR (ddi_global_data ()->dg_run_bufcalls, 0);
                    231: 
                    232:        mem_level = str_mem->sm_used;
                    233:        runlist = NULL;
                    234: 
                    235:        for (i = N_PRI_LEVELS ; i -- > 0 ; ) {
                    236:                selist_t      * elistp;
                    237:                unsigned long   max = str_mem->sm_max [i];
                    238: 
                    239:                elistp = & str_mem->sm_bcevents [i];
                    240: 
                    241:                prev_pl = SELIST_LOCK (elistp);
                    242: 
                    243:                while ((seventp = elistp->sl_head) != NULL) {
                    244:                        /*
                    245:                         * If the amount of memory requested in this cell is
                    246:                         * enough to push the memory level over the top for
                    247:                         * this allocation priority, then give up.
                    248:                         */
                    249: 
                    250:                        if ((mem_level += seventp->se_size) > max)
                    251:                                goto give_up;
                    252: 
                    253:                        /*
                    254:                         * Dequeue the event from the event list and add it to
                    255:                         * our work list.
                    256:                         */
                    257: 
                    258:                        elistp->sl_head = seventp->se_next;
                    259: 
                    260:                        seventp->se_next = runlist;
                    261:                        runlist = seventp;
                    262:                }
                    263: 
                    264: #if    _FIFO_BUFCALL
                    265:                /*
                    266:                 * If we have drained all the events in this cell...
                    267:                 */
                    268: 
                    269:                elistp->sl_tail = NULL;
                    270: #endif
                    271: 
                    272: give_up:
                    273:                SELIST_UNLOCK (elistp, prev_pl);
                    274: 
                    275:                if (seventp != NULL)
                    276:                        break;
                    277:        }
                    278: 
                    279: 
                    280:        /*
                    281:         * Now use 'i' as a boolean to remember whether we have any
                    282:         * outstanding event cells we though it better not to run.
                    283:         */
                    284: 
                    285:        i = seventp != NULL;
                    286: 
                    287: 
                    288:        /*
                    289:         * Now walk over our little work list...
                    290:         */
                    291: 
                    292:        while (runlist != NULL) {
                    293: 
                    294:                seventp = runlist;
                    295:                runlist = seventp->se_next;
                    296: 
                    297:                prev_pl = splstr ();
                    298: 
                    299:                (* seventp->se_func) (seventp->se_arg);
                    300: 
                    301:                (void) splx (prev_pl);
                    302: 
                    303:                kmem_free (seventp, sizeof (* seventp));
                    304:        }
                    305: 
                    306: 
                    307:        /*
                    308:         * If we found anything worth running, try again after we have given
                    309:         * the bufcall functions a chance to claim the memory that was free
                    310:         * first time through. We queue another defer request so that we give
                    311:         * a chance to other deferred routines.
                    312:         */
                    313: 
                    314:        if (i)
                    315:                SCHEDULE_BUFCALLS ();
                    316: }
                    317: 
                    318: 
                    319: /*
                    320:  * Streams scheduling routine, invoked before return to user level. Runs any
                    321:  * service procedures that have been enabled, calls bufcall ()/esbbcall ()
                    322:  * events if memory is sitting around, and also wakes up processes sleeping
                    323:  * in kmem_alloc ()/kmem_zalloc () for memory to become available.
                    324:  */
                    325: 
                    326: #if    __USE_PROTO__
                    327: void (RUN_STREAMS) (void)
                    328: #else
                    329: void
                    330: RUN_STREAMS __ARGS (())
                    331: #endif
                    332: {
                    333:        queue_t       * q;
                    334: 
                    335:        /*
                    336:         * Before we start running through the queues that we need to service,
                    337:         * turn off the "deferred" flag for this routine to avoid race
                    338:          * conditions.
                    339:         */
                    340: 
                    341:        ATOMIC_STORE_UCHAR (ddi_global_data ()->dg_run_strsched, 0);
                    342: 
                    343:        while ((q = QSCHED_GETFIRST (str_mem->sm_sched)) != NULL) {
                    344:                pl_t            prev_pl;
                    345: 
                    346:                /*
                    347:                 * Before we run the service procedure, we must ensure
                    348:                 * that we are not going to re-enter the service
                    349:                 * routine. After that, we can turn off the 'enabled'
                    350:                 * flag.
                    351:                 */
                    352: 
                    353:                prev_pl = QFREEZE_TRACE (q, "STREAMS_SCHEDULER");
                    354: 
                    355:                if ((q->q_flag & QSRVACTIVE) != 0) {
                    356:                        /*
                    357:                         * Put the queue back and look for something
                    358:                         * else to do.
                    359:                         */
                    360: 
                    361:                        QUNFREEZE_TRACE (q, prev_pl);
                    362:                        QSCHED_SCHEDULE (q, str_mem->sm_sched);
                    363: 
                    364:                        continue;
                    365:                }
                    366: 
                    367:                q->q_flag = (q->q_flag & ~ QENAB) | QSRVACTIVE;
                    368: 
                    369:                if ((q->q_flag & QPROCSOFF) != 0) {
                    370:                        /*
                    371:                         * The service procedure of this queue has
                    372:                         * been disabled, so we leave things alone.
                    373:                         */
                    374: 
                    375:                        goto srvdone;
                    376:                }
                    377: 
                    378:                q->q_active ++;
                    379: 
                    380:                QUNFREEZE_TRACE (q, prev_pl);
                    381: 
                    382: 
                    383:                (* q->q_qinfo->qi_srvp) (q);
                    384: 
                    385: 
                    386:                prev_pl = QFREEZE_TRACE (q, "STREAMS_SCHEDULER");
                    387: 
                    388:                q->q_flag &= ~ QSRVACTIVE;
                    389: 
                    390:                if (-- q->q_active == 0 && (q->q_flag & QPROCSOFF) != 0) {
                    391:                        /*
                    392:                         * Wake up the qprocoffs () procedure waiting
                    393:                         * for us to go exit.
                    394:                         */
                    395: 
                    396:                        (void) LOCK (str_mem->sm_proc_lock, plstr);
                    397:                        SV_BROADCAST (str_mem->sm_proc_sv, 0);
                    398:                        UNLOCK (str_mem->sm_proc_lock, plstr);
                    399:                }
                    400: srvdone:
                    401:                QUNFREEZE_TRACE (q, prev_pl);
                    402:        }
                    403: }

unix.superglobalmegacorp.com

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