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

1.1       root        1: #define        _DDI_DKI        1
                      2: #define        _DDI_DKI_IMPL   1
                      3: #define        _SYSV4          1
                      4: 
                      5: /*
                      6:  * This file contains functions relating to the implementation of DDI/DKI
                      7:  * timeout functions.
                      8:  */
                      9: /*
                     10:  *-IMPORTS:
                     11:  *     <common/ccompat.h>
                     12:  *             __USE_PROTO__
                     13:  *             __ARGS ()
                     14:  *     <kernel/ddi_glob.h>
                     15:  *             ddi_global_data ()
                     16:  *     <kernel/ddi_cpu.h>
                     17:  *             ddi_cpu_ref ()
                     18:  *             ddi_cpu_unref ()
                     19:  *             ddi_cpu_id ()
                     20:  *     <kernel/ddi_lock.h>
                     21:  *              timeout_global_hierarchy
                     22:  *             timeout_global_priority
                     23:  *     <kernel/defer.h>
                     24:  *             defer_int_cpu ()
                     25:  *             defer_int_here ()
                     26:  *     <sys/debug.h>
                     27:  *             ASSERT ()
                     28:  *     <sys/types.h>
                     29:  *             plhi
                     30:  *             pl_t
                     31:  *             toid_t
                     32:  *             __tfuncp_t
                     33:  *     <sys/inline.h>
                     34:  *             splx ()
                     35:  *     <sys/ksynch.h>
                     36:  *             LOCK_ALLOC ()
                     37:  *             LOCK_DEALLOC ()
                     38:  *             LOCK ()
                     39:  *             UNLOCK ()
                     40:  *     <sys/kmem.h>
                     41:  *             KM_NOSLEEP
                     42:  *             kmem_alloc ()
                     43:  *             kmem_free ()
                     44:  *     <sys/cmn_err.h>
                     45:  *             CE_PANIC
                     46:  *             cmn_err ()
                     47:  */
                     48: 
                     49: #include <common/ccompat.h>
                     50: #include <kernel/ddi_glob.h>
                     51: #include <kernel/ddi_cpu.h>
                     52: #include <kernel/ddi_lock.h>
                     53: #include <kernel/defer.h>
                     54: #include <sys/debug.h>
                     55: #include <sys/types.h>
                     56: #include <sys/inline.h>
                     57: #include <sys/ksynch.h>
                     58: #include <sys/kmem.h>
                     59: #include <sys/cmn_err.h>
                     60: 
                     61: /*
                     62:  * This code doesn't (yet) use the ddi_global_data () and ddi_cpu_data ()
                     63:  * mechanisms. It will need to in order to support the dtimeout () call to
                     64:  * bind a timeout to a specific CPU. However, this has been left pending
                     65:  * investigation of how we want to specify CPU ids...
                     66:  *
                     67:  * So, at some stage the TIMEOUT_GLOBAL_... (), SCHEDULE_TIMEOUT () and
                     68:  * STREAMS_TIMEOUT () functions may be parameterized.
                     69:  */
                     70: 
                     71: 
                     72: /*
                     73:  * All the global data this file uses in one handy place.
                     74:  *
                     75:  * How to do timeouts? I've always been a big fan of delta-queues.
                     76:  * How to manage untimeout ()?
                     77:  *
                     78:  * The cancellation procedure is seriously complicated by the need for cancel
                     79:  * attempts to block until completion if the timeout has begun. What we
                     80:  * implement here is similar to a ticket lock, although we use a single global
                     81:  * basic lock to guarantee write atomicity rather than a test-and-set lock.
                     82:  *     t_ticket        t_ticket_holder
                     83:  *        0                 0                  Cell pending activation.
                     84:  *        1                 0                  Cell activated.
                     85:  *        1                 1                  Cell processed.
                     86:  *        m                 n                  m != n, cancel attempts n + 1
                     87:  *                                             through m pending.
                     88:  *
                     89:  * Whoever finds "t_ticket" and "t_ticket_holder" equal (to their number, of
                     90:  * course) has responsibility for deallocating the lock structure. The timeout
                     91:  * activation code always has responsibility for dequeuing the lock once it has
                     92:  * been activated; this avoids having the pending cancels rescan the list to
                     93:  * dequeue the cell, and also ensures that untimeout () calls will simply
                     94:  * return rather than joining the queue if the timeout function has finished.
                     95:  *
                     96:  * Using a simple state code might seem simpler... but we have a special
                     97:  * problem here, in that we want to return the memory occupied by the event
                     98:  * cell (and its state code) to the heap. Using the ticket system, we get
                     99:  * acknowledgement from all the contexts that were interested in the state of
                    100:  * the cell that they are no longer interested in it.
                    101:  */
                    102: 
                    103: struct timeout {
                    104:        timeout_t     * t_next;
                    105:        __clock_t       t_delta;
                    106:        toid_t          t_id;
                    107:        processorid_t   t_cpu;
                    108: 
                    109:        atomic_uchar_t  t_ticket;               /* next ticket */
                    110:        atomic_uchar_t  t_ticket_holder;        /* who holds the ticket */
                    111: 
                    112:        __tfuncp_t      t_funcp;                /* function to call */
                    113:        _VOID         * t_arg;                  /* argument for function */
                    114:        lock_t        * t_lockp;                /* basic lock to acquire */
                    115:        pl_t            t_pl;                   /* priority level for call */
                    116: };
                    117: 
                    118: __LOCAL__ lkinfo_t _timeout_lkinfo = {
                    119:        "timeout global lock", INTERNAL_LOCK
                    120: };
                    121: 
                    122: 
                    123: #define        TIMEDATA()      (& ddi_global_data ()->dg_timeouts)
                    124: 
                    125: #define        TIMEOUT_GLOBAL_LOCK()   \
                    126:                (ASSERT (TIMEDATA ()->td_lock != NULL), \
                    127:                 LOCK (TIMEDATA ()->td_lock, timeout_global_priority))
                    128: 
                    129: #define        TIMEOUT_GLOBAL_UNLOCK(p)        UNLOCK (TIMEDATA ()->td_lock, (p))
                    130: 
                    131: 
                    132: 
                    133: /*
                    134:  * This internal function is called whenever there are timeout routines
                    135:  * waiting to be processed by a particular CPU.
                    136:  */
                    137: 
                    138: #if    __USE_PROTO__
                    139: __LOCAL__ void (RUN_TIMEOUTS) (void)
                    140: #else
                    141: __LOCAL__ void
                    142: RUN_TIMEOUTS __ARGS (())
                    143: #endif
                    144: {
                    145:        pl_t            prev_pl;
                    146:        timeout_t     * scan;
                    147:        timeout_t     * next;
                    148:        timeout_t     * free_list;
                    149:        processorid_t   my_id = ddi_cpu_id ();
                    150:        int             lock_failed = 0;
                    151: 
                    152:        prev_pl = TIMEOUT_GLOBAL_LOCK ();
                    153: 
                    154: 
                    155:        /*
                    156:         * Run all the events that belong to this CPU.
                    157:         */
                    158: 
                    159:        for (scan = TIMEDATA ()->td_run ; scan != TIMEDATA ()->td_first ;
                    160:             scan = scan->t_next) {
                    161: 
                    162:                if (scan->t_cpu != my_id)
                    163:                        continue;
                    164: 
                    165:                if (ATOMIC_FETCH_UCHAR (scan->t_ticket) > 0) {
                    166:                        /*
                    167:                         * This entry is going to be deleted. Don't run it.
                    168:                         */
                    169: 
                    170:                        continue;
                    171:                }
                    172: 
                    173: 
                    174:                /*
                    175:                 * Before we commit to running the timeout function, we need
                    176:                 * to check that the timeout function can acquire the basic
                    177:                 * lock that it needs.
                    178:                 */
                    179: 
                    180:                if (scan->t_lockp != NULL &&
                    181:                    TRYLOCK (scan->t_lockp, plhi) == invpl) {
                    182:                        /*
                    183:                         * Try the next event cell, after we remember that an
                    184:                         * event cell failed to get a lock.
                    185:                         */
                    186: 
                    187:                        lock_failed = 1;
                    188:                        continue;
                    189:                }
                    190: 
                    191: 
                    192:                /*
                    193:                 * OK, stop other CPUs from processing this entry and make
                    194:                 * cancel requests block until we are finished.
                    195:                 */
                    196: 
                    197:                ATOMIC_STORE_UCHAR (scan->t_ticket, 1);
                    198: 
                    199:                TIMEOUT_GLOBAL_UNLOCK (scan->t_pl);
                    200: 
                    201: 
                    202:                /*
                    203:                 * Now execute the user function as requested. Note that we
                    204:                 * set the interrupt priority level to "scan->t_pl" even
                    205:                 * though we passed that value to UNLOCK (), since an
                    206:                 * implementation is permitted to ignore the "pl" argument to
                    207:                 * UNLOCK ().
                    208:                 *
                    209:                 * If we acquired a lock on behalf of the timeout function, we
                    210:                 * release it after the function runs.
                    211:                 */
                    212: 
                    213:                (void) splx (scan->t_pl);
                    214: 
                    215:                (* scan->t_funcp) (scan->t_arg);
                    216: 
                    217:                if (scan->t_lockp != NULL)
                    218:                        UNLOCK (scan->t_lockp, prev_pl);
                    219: 
                    220:                (void) splx (prev_pl);
                    221: 
                    222: 
                    223:                /*
                    224:                 * Now we relock the list and mark this cell as finished. If
                    225:                 * a delete request for the cell has come in, let it proceed
                    226:                 * now that the function has been run.
                    227:                 */
                    228: 
                    229:                prev_pl = TIMEOUT_GLOBAL_LOCK ();
                    230: 
                    231:                ATOMIC_STORE_UCHAR (scan->t_ticket_holder, 1);
                    232:        }
                    233: 
                    234: 
                    235:        /*
                    236:         * Run over the list of expired events and move any that have been
                    237:         * completed to a work list for deletion.
                    238:         */
                    239: 
                    240:        free_list = NULL;
                    241: 
                    242:        for (scan = TIMEDATA ()->td_run ; scan != TIMEDATA ()->td_first ;
                    243:             scan = next) {
                    244: 
                    245:                /*
                    246:                 * If this event cell is in the throes of deletion, try again
                    247:                 * later. If there is an event which has not yet been run,
                    248:                 * don't clean up any more.
                    249:                 */
                    250: 
                    251:                if (ATOMIC_FETCH_UCHAR (scan->t_ticket_holder) !=
                    252:                    ATOMIC_FETCH_UCHAR (scan->t_ticket)) {
                    253: 
                    254:                        lock_failed = 1;
                    255:                        break;
                    256:                }
                    257: 
                    258:                if (ATOMIC_FETCH_UCHAR (scan->t_ticket) == 0)
                    259:                        break;
                    260: 
                    261:                /*
                    262:                 * Move the cell to the work list.
                    263:                 */
                    264: 
                    265:                next = scan->t_next;
                    266:                scan->t_next = free_list;
                    267:                free_list = scan;
                    268:        }
                    269: 
                    270:        TIMEDATA ()->td_run = scan;
                    271: 
                    272: 
                    273:        /*
                    274:         * If we have run (and freed) all the events that we can, clear the
                    275:         * run flag, otherwise defer this function again by way of backing off
                    276:         * from the locks we failed.
                    277:         */
                    278: 
                    279:        if (lock_failed)
                    280:                defer_int_here (RUN_TIMEOUTS);
                    281:        else
                    282:                ATOMIC_STORE_UCHAR (ddi_cpu_data ()->dc_run_timeouts, 0);
                    283: 
                    284:        TIMEOUT_GLOBAL_UNLOCK (prev_pl);
                    285: 
                    286: 
                    287:        /*
                    288:         * Free any timeout cells that we were able to reap.
                    289:         */
                    290: 
                    291:        while ((scan = free_list) != NULL) {
                    292: 
                    293:                free_list = scan->t_next;
                    294: 
                    295:                kmem_free (scan, sizeof (* scan));
                    296:        }
                    297: }
                    298: 
                    299: 
                    300: /*
                    301:  * Code from STREAMS_TIMEOUT () to schedule a single timeout event, factored
                    302:  * out here to keep STREAMS_TIMEOUT () manageable.
                    303:  */
                    304: 
                    305: #if    __USE_PROTO__
                    306: __LOCAL__ __INLINE__ void SCHEDULE_TIMEOUT (timeout_t * timep)
                    307: #else
                    308: __LOCAL__ __INLINE__ void
                    309: SCHEDULE_TIMEOUT __ARGS ((timep))
                    310: timeout_t     *        timep;
                    311: #endif
                    312: {
                    313:        dcdata_t      * dcdatap;
                    314: 
                    315:        if (timep->t_cpu == NOCPU)
                    316:                timep->t_cpu = ddi_cpu_id ();
                    317: 
                    318:        dcdatap = ddi_cpu_ref (timep->t_cpu);
                    319: 
                    320:        ASSERT (dcdatap != NULL);
                    321: 
                    322:        if (ATOMIC_FETCH_UCHAR (dcdatap->dc_run_timeouts) == 0) {
                    323:                /*
                    324:                 * Schedule the routine to actually run the timeouts.
                    325:                 */
                    326: 
                    327:                defer_int_cpu (RUN_TIMEOUTS, timep->t_cpu);
                    328:                ATOMIC_STORE_UCHAR (dcdatap->dc_run_timeouts, 1);
                    329:        }
                    330: }
                    331: 
                    332: 
                    333: /*
                    334:  * This internal function is called once for each clock tick of real time that
                    335:  * passes in the system overall. It may be that several instances get to run
                    336:  * simultaneously in different CPUs if things get bogged down, but the basic
                    337:  * idea is that the function gets called once per clock tick.
                    338:  */
                    339: 
                    340: __EXTERN_C__
                    341: #if    __USE_PROTO__
                    342: void (STREAMS_TIMEOUT) (void)
                    343: #else
                    344: void
                    345: STREAMS_TIMEOUT __ARGS (())
                    346: #endif
                    347: {
                    348:        pl_t            prev_pl;
                    349:        timeout_t     * scan;
                    350: 
                    351:        prev_pl = TIMEOUT_GLOBAL_LOCK ();
                    352: 
                    353:        /*
                    354:         * Now that we have the timeout queue locked, decrement the delta
                    355:         * value of the entry at the front of the queue. After that, work out
                    356:         * whether any entries have been triggered as a result.
                    357:         */
                    358: 
                    359:        if ((scan = TIMEDATA ()->td_first) != NULL) {
                    360: 
                    361:                ASSERT (scan->t_delta > 0);
                    362: 
                    363:                if (-- scan->t_delta == 0) {
                    364: 
                    365:                        if (TIMEDATA ()->td_run == NULL)
                    366:                                TIMEDATA ()->td_run = scan;
                    367: 
                    368:                        /*
                    369:                         * At least one entry has been set off. Loop over the
                    370:                         * entries, notifying each CPU that has an event bound
                    371:                         * to it. If an event is not bound to any CPU, bind it
                    372:                         * to the current CPU.
                    373:                         */
                    374: 
                    375:                        do
                    376:                                SCHEDULE_TIMEOUT (scan);
                    377:                        while ((scan = scan->t_next) != NULL &&
                    378:                               scan->t_delta == 0);
                    379: 
                    380:                        TIMEDATA ()->td_first = scan;
                    381:                }
                    382:        }
                    383: 
                    384:        TIMEOUT_GLOBAL_UNLOCK (prev_pl);
                    385: }
                    386: 
                    387: 
                    388: /*
                    389:  * This internal function factors out the common elements of timer event
                    390:  * scheduling from itimeout () and ltimeout ().
                    391:  */
                    392: 
                    393: #if    __USE_PROTO__
                    394: __LOCAL__ toid_t (QUEUE_TIMEOUT) (__tfuncp_t fn, _VOID * arg, __clock_t ticks,
                    395:                                  lock_t * lockp, processorid_t cpu, pl_t pl)
                    396: #else
                    397: __LOCAL__ toid_t
                    398: QUEUE_TIMEOUT __ARGS ((fn, arg, ticks, lockp, cpu, pl))
                    399: __tfuncp_t     fn;
                    400: _VOID        * arg;
                    401: __clock_t      ticks;
                    402: lock_t       * lockp;
                    403: processorid_t  cpu;
                    404: pl_t           pl;
                    405: #endif
                    406: {
                    407:        pl_t            prev_pl;
                    408:        timeout_t     * timep;
                    409:        timeout_t     * scan;
                    410:        timeout_t     * prev;
                    411: 
                    412:        if ((timep = (timeout_t *) kmem_alloc (sizeof (* timep),
                    413:                                               KM_NOSLEEP)) == NULL)
                    414:                return 0;
                    415: 
                    416:        timep->t_funcp = fn;
                    417:        timep->t_arg = arg;
                    418:        timep->t_pl = pl;
                    419:        timep->t_lockp = lockp;
                    420:        timep->t_cpu = cpu;
                    421:        ATOMIC_STORE_UCHAR (timep->t_ticket, 0);
                    422:        ATOMIC_STORE_UCHAR (timep->t_ticket_holder, 0);
                    423: 
                    424:        if (ticks == 0)
                    425:                ticks = 1;
                    426: 
                    427:        /*
                    428:         * Having created and mostly filled in the timeout structure, we now
                    429:         * lock the delta-queue and try and find the place where our structure
                    430:         * needs to be inserted.
                    431:         *
                    432:         * We also use the delta-queue lock to protect our access to the
                    433:         * timeout ID generator. Since it is in theory possible to wrap around
                    434:         * the ID space, the delta-queue walk will look for a duplicate ID.
                    435:         * We make the simplifying assumption that anything that has lived
                    436:         * that long isn't going to be cancelled anytime soon, so that it
                    437:         * suffices to protect the newer entry from having it's cancel code
                    438:         * shadowed.
                    439:         */
                    440: 
                    441:        prev_pl = TIMEOUT_GLOBAL_LOCK ();
                    442: 
                    443: id_scan:
                    444:        if (TIMEDATA ()->td_id == 0)
                    445:                TIMEDATA ()->td_id = 1;
                    446: 
                    447:        timep->t_id = TIMEDATA ()->td_id ++;
                    448: 
                    449:        /*
                    450:         * We have to deal with the fact that the true first element in the
                    451:         * timeout delta-queue may be represented by either of two pointers.
                    452:         * Since timeouts that have been scheduled to run have a zero
                    453:         * "t_delta", searching those entries won't disrupt the delta-queue,
                    454:         * and until they have been dequeued their timeout id's are still
                    455:         * valid.
                    456:         */
                    457: 
                    458:        if ((scan = TIMEDATA ()->td_run) == NULL)
                    459:                scan = TIMEDATA ()->td_first;
                    460: 
                    461:        for (prev = NULL ; scan != NULL ; scan = (prev = scan)->t_next) {
                    462: 
                    463:                if (scan->t_id == timep->t_id)
                    464:                        goto id_scan;
                    465: 
                    466:                if (ticks < scan->t_delta) {
                    467:                        /*
                    468:                         * OK, we have found our spot. Now we insert our new
                    469:                         * cell in front of the one we have just found.
                    470:                         */
                    471: 
                    472:                        scan->t_delta -= ticks;
                    473:                        break;
                    474:                }
                    475: 
                    476:                ticks -= scan->t_delta;
                    477:        }
                    478: 
                    479:        timep->t_delta = ticks;
                    480:        timep->t_next = scan;
                    481: 
                    482:        if (scan == TIMEDATA ()->td_first)
                    483:                TIMEDATA ()->td_first = timep;
                    484: 
                    485:        if (prev != NULL)
                    486:                prev->t_next = timep;
                    487: 
                    488:        TIMEOUT_GLOBAL_UNLOCK (prev_pl);
                    489: 
                    490:        return timep->t_id;
                    491: }
                    492: 
                    493: 
                    494: /*
                    495:  * This internal function is a direct equivalent to itimeout (), with the
                    496:  * following additional behaviour; the caller supplies the address of a basic
                    497:  * lock which this code will attempt to acquire before running the timeout
                    498:  * function. If the lock cannot be acquired immediately, the next timeout
                    499:  * function will be considered.
                    500:  *
                    501:  * This behaviour allows untimeout () to be safely used to cancel the timeout
                    502:  * request while holding the basic lock that this function will attempt to
                    503:  * acquire.
                    504:  *
                    505:  * A "timeout" value of NULL yields identical behaviour to itimeout ().
                    506:  */
                    507: 
                    508: #if    __USE_PROTO__
                    509: toid_t (ltimeout) (__tfuncp_t fn, _VOID * arg, __clock_t ticks,
                    510:                   lock_t * lockp, pl_t pl)
                    511: #else
                    512: toid_t
                    513: ltimeout __ARGS ((fn, arg, ticks, lockp, pl))
                    514: __tfuncp_t     fn;
                    515: _VOID        * arg;
                    516: __clock_t      ticks;
                    517: lock_t       * lockp;
                    518: pl_t           pl;
                    519: #endif
                    520: {
                    521:        ASSERT (fn != (__tfuncp_t) NULL);
                    522:        ASSERT (lockp != NULL);
                    523: 
                    524:        return QUEUE_TIMEOUT (fn, arg, ticks, lockp, NOCPU, pl);
                    525: }
                    526: 
                    527: 
                    528: /*
                    529:  *-STATUS:
                    530:  *     DDI/DKI
                    531:  *
                    532:  *-NAME:
                    533:  *     itimeout        Execute a function after a specified length of time.
                    534:  *
                    535:  *-SYNOPSIS:
                    536:  *     #include <sys/types.h>
                    537:  *
                    538:  *     toid_t itimeout (void (* fn) (), void * arg, long ticks, pl_t pl);
                    539:  *
                    540:  *-ARGUMENTS:
                    541:  *     fn              Function to execute when the time interval expires.
                    542:  *
                    543:  *     arg             Argument to the function.
                    544:  *
                    545:  *     ticks           Number of clock ticks to wait before the function is
                    546:  *                     called.
                    547:  *
                    548:  *     pl              The interrupt priority level at which the function
                    549:  *                     will be called. "pl" must specify a priority level
                    550:  *                     greater than or equal to "pltimeout"; thus, "plbase"
                    551:  *                     cannot not be used. See LOCK_ALLOC () for a list of
                    552:  *                     values for "pl".
                    553:  *
                    554:  *-DESCRIPTION:
                    555:  *     itimeout () causes the function specified by "fn" to be called after
                    556:  *     the time interval specified by "ticks", at the interrupt priority
                    557:  *     specified by "pl". "arg" will be passed as the only argument to
                    558:  *     function "fn". The itimeout () call returns immediately without
                    559:  *     waiting for the specified function to execute.
                    560:  *
                    561:  *     The length of time before the function is called is not guaranteed to
                    562:  *     be exactly equal to the requested time, but will be at least "ticks-1"
                    563:  *     clock ticks in length. The function specified by "fn" must neither
                    564:  *     sleep nor reference process context.
                    565:  *
                    566:  *-RETURN VALUE:
                    567:  *     If the function specfied by "fn" is successfully scheduled,
                    568:  *     itimeout () returns a non-zero identifier that can be passed to
                    569:  *     untimeout () to cancel the request. If the function could not be
                    570:  *     scheduled, itimeout () returns a value of 0.
                    571:  *
                    572:  *-LEVEL:
                    573:  *     Base or Interrupt.
                    574:  *
                    575:  *-NOTES:
                    576:  *     Does not sleep.
                    577:  *
                    578:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                    579:  *     held across calls to this function.
                    580:  *
                    581:  *     Drivers should be careful to cancel any pending itimeout () functions
                    582:  *     that access data structures before these structures are de-initialized
                    583:  *     or deallocated.
                    584:  *
                    585:  *     After the time interval has expired, "fn" only runs if the processor
                    586:  *     is at base level. Otherwise, "fn" is deferred until sometime in the
                    587:  *     near future.
                    588:  *
                    589:  *     If itimeout () is called holding a lock that is contended for by "fn",
                    590:  *     the caller must hold the lock at a processor level greater than the
                    591:  *     base processor level.
                    592:  *
                    593:  *     A "ticks" argument of 0 has the same effect as a "ticks" argument of
                    594:  *     1. Both will result in an approximate wait of between 0 and 1 tick
                    595:  *     (possibly longer).
                    596:  *
                    597:  *-SEE ALSO:
                    598:  *     LOCK_ALLOC (), untimeout ()
                    599:  */
                    600: 
                    601: #if    __USE_PROTO__
                    602: toid_t (itimeout) (__tfuncp_t fn, _VOID * arg, __clock_t ticks, pl_t pl)
                    603: #else
                    604: toid_t
                    605: itimeout __ARGS ((fn, arg, ticks, pl))
                    606: __tfuncp_t    *        fn;
                    607: _VOID        * arg;
                    608: __clock_t      ticks;
                    609: pl_t           pl;
                    610: #endif
                    611: {
                    612:        ASSERT (fn != (__tfuncp_t) NULL);
                    613: 
                    614:        return QUEUE_TIMEOUT (fn, arg, ticks, NULL, NOCPU, pl);
                    615: }
                    616: 
                    617: 
                    618: /*
                    619:  *-STATUS:
                    620:  *     DDI/DKI
                    621:  *
                    622:  *-NAME:
                    623:  *     untimeout       Cancel previous timeout request.
                    624:  *
                    625:  *-SYNOPSIS:
                    626:  *     #include <sys/types.h>
                    627:  *
                    628:  *     void untimeout (toid_t id);
                    629:  *
                    630:  *-ARGUMENTS:
                    631:  *     id              Identifier returned from a previous call to
                    632:  *                     itimeout ().
                    633:  *
                    634:  *-DESCRIPTION:
                    635:  *     untimeout () cancels a previous timeout request. If the untimeout ()
                    636:  *     is called while the function is running, then untimeout () will not
                    637:  *     return until the function has completed. The function that runs as a
                    638:  *     result of itimeout () cannot use untimeout () to cancel itself.
                    639:  *
                    640:  *-RETURN VALUE:
                    641:  *     None.
                    642:  *
                    643:  *-LEVEL:
                    644:  *     Base or interrupt, with the following exception; the untimeout () can
                    645:  *     only be performed from interrupt levels less than, or equal to, the
                    646:  *     level specified when the function was scheduled.
                    647:  *
                    648:  *-NOTES:
                    649:  *     Does not sleep.
                    650:  *
                    651:  *     Driver-defined basic locks, read/write locks, and sleep locks may not
                    652:  *     be held across calls to this function if these locks are contended by
                    653:  *     the function being scheduled.
                    654:  *
                    655:  *-SEE ALSO:
                    656:  *     delay (), itimeout (), unbufcall ()
                    657:  */
                    658: 
                    659: #if    __USE_PROTO__
                    660: void (untimeout) (toid_t id)
                    661: #else
                    662: void
                    663: untimeout __ARGS ((id))
                    664: toid_t         id;
                    665: #endif
                    666: {
                    667:        pl_t            prev_pl;
                    668:        timeout_t     * scan;
                    669: 
                    670:        prev_pl = TIMEOUT_GLOBAL_LOCK ();
                    671: 
                    672:        for (scan = TIMEDATA ()->td_first ; scan != NULL ;
                    673:             scan = scan->t_next) {
                    674:                unsigned short  ticket;
                    675: 
                    676:                if (scan->t_id != id)
                    677:                        continue;
                    678: 
                    679:                /*
                    680:                 * Take a ticket, and wait for the cell's event routine to
                    681:                 * finish. If it was not running before we took a ticket, it
                    682:                 * never will.
                    683:                 */
                    684: 
                    685:                ticket = ATOMIC_FETCH_UCHAR (scan->t_ticket);
                    686:                ATOMIC_STORE_UCHAR (scan->t_ticket, ticket + 1);
                    687: 
                    688:                scan->t_cpu = ddi_cpu_id ();
                    689: 
                    690:                if (ticket != ATOMIC_FETCH_UCHAR (scan->t_ticket_holder)) {
                    691:                        /*
                    692:                         * Wait for the event routine to complete.
                    693:                         */
                    694: 
                    695:                        TIMEOUT_GLOBAL_UNLOCK (prev_pl);
                    696: 
                    697:                        while (ATOMIC_FETCH_UCHAR (scan->t_ticket_holder)
                    698:                               != ticket)
                    699:                                ; /* DO NOTHING */
                    700: 
                    701: 
                    702:                        prev_pl = TIMEOUT_GLOBAL_LOCK ();
                    703:                }
                    704: 
                    705: 
                    706:                /*
                    707:                 * Pass it on to the next guy.
                    708:                 */
                    709: 
                    710:                ATOMIC_STORE_UCHAR (scan->t_ticket_holder, ticket + 1);
                    711:        }
                    712: 
                    713:        TIMEOUT_GLOBAL_UNLOCK (prev_pl);
                    714: }
                    715: 
                    716: 
                    717: /*
                    718:  * Set up the timeout globals. This function is called via the 'mdevice' init
                    719:  * function table.
                    720:  */
                    721: 
                    722: __EXTERN_C__
                    723: #if    __USE_PROTO__
                    724: int (timeout_init) (void)
                    725: #else
                    726: int
                    727: timeout_init __ARGS (())
                    728: #endif
                    729: {
                    730:        TIMEDATA ()->td_lock = LOCK_ALLOC (timeout_global_hierarchy,
                    731:                                           timeout_global_priority,
                    732:                                           & _timeout_lkinfo, KM_SLEEP);
                    733: 
                    734:        return TIMEDATA ()->td_lock == NULL;
                    735: }

unix.superglobalmegacorp.com

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