Annotation of kernel/kern/thread_call.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:  * Copyright (c) 1993, 1994, 1995 NeXT Computer, Inc.
                     27:  *
                     28:  * Thread-based callout module.
                     29:  *
                     30:  * 3 July 1993 ? at NeXT
                     31:  *     Created.
                     32:  */
                     33:  
                     34: #import <mach/mach_types.h>
                     35: 
                     36: #import <kern/sched_prim.h>
                     37: #import <kern/clock.h>
                     38: 
                     39: #import <kern/thread_call.h>
                     40: #import <kern/thread_call_private.h>
                     41: 
                     42: #include <kern/kdebug.h>
                     43: 
                     44: #define internal_call_num      768
                     45: 
                     46: static
                     47: struct _thread_call
                     48:        internal_call_storage[internal_call_num];
                     49: 
                     50: static
                     51: simple_lock_data_t
                     52:        thread_call_lock;
                     53: 
                     54: static
                     55: queue_head_t
                     56:        internal_call_free_queue,
                     57:        pending_call_queue, delayed_call_queue;
                     58: 
                     59: static int
                     60:        pending_call_num, active_call_num,
                     61:        call_thread_num;
                     62: 
                     63: #define call_thread_min                4
                     64:                        
                     65: static boolean_t
                     66:        thread_call_initialized = FALSE;
                     67: 
                     68: static __inline__ _thread_call_t
                     69:        _internal_call_allocate(void);
                     70: 
                     71: static __inline__ _thread_call_t
                     72: thread_call_release(
                     73:        _thread_call_t          call
                     74: );
                     75: 
                     76: static __inline__ void
                     77: _pending_call_enqueue(
                     78:        _thread_call_t          call
                     79: ),
                     80: _pending_call_dequeue(
                     81:        _thread_call_t          call
                     82: ),
                     83: _delayed_call_enqueue(
                     84:        _thread_call_t          call
                     85: ),
                     86: _delayed_call_dequeue(
                     87:        _thread_call_t          call
                     88: );
                     89: 
                     90: static void __inline__
                     91: _set_delayed_call_timer(
                     92:        _thread_call_t          call
                     93: );
                     94:                                        
                     95: static boolean_t
                     96: _remove_from_pending_queue(
                     97:        thread_call_func_t      func,
                     98:        thread_call_spec_t      spec,
                     99:        boolean_t               remove_all
                    100: ),
                    101: _remove_from_delayed_queue(
                    102:        thread_call_func_t      func,
                    103:        thread_call_spec_t      spec,
                    104:        boolean_t               remove_all
                    105: );
                    106: 
                    107: static __inline__ void
                    108:        _call_thread_wake(void);
                    109: 
                    110: static void
                    111:        _call_thread(void),
                    112:        _call_activate_thread(void);
                    113: 
                    114: static void
                    115: _delayed_call_interrupt(
                    116:        tvalspec_t              timestamp
                    117: );
                    118: 
                    119: #define qe(x)          ((queue_entry_t)(x))
                    120: #define TC(x)          ((_thread_call_t)(x))
                    121: 
                    122: /*
                    123:  * Routine:    thread_call_initialized [public]
                    124:  *
                    125:  * Description:        Initialize this module, called
                    126:  *             early during system initialization.
                    127:  *
                    128:  * Preconditions:      None.
                    129:  *
                    130:  * Postconditions:     None.
                    131:  */
                    132: 
                    133: void
                    134: thread_call_init(void)
                    135: {
                    136:     _thread_call_t     call;
                    137: 
                    138:     if (thread_call_initialized)
                    139:        panic("thread_call_init");
                    140: 
                    141:     simple_lock_init(&thread_call_lock);
                    142: 
                    143:     queue_init(&pending_call_queue);
                    144:     queue_init(&delayed_call_queue);
                    145: 
                    146:     queue_init(&internal_call_free_queue);
                    147:     for (
                    148:            call = internal_call_storage;
                    149:            call < &internal_call_storage[internal_call_num];
                    150:            call++) {
                    151: 
                    152:        enqueue_tail(&internal_call_free_queue, qe(call));
                    153:     }
                    154: 
                    155:     (void) kernel_thread(kernel_task, _call_activate_thread, (void *)0);
                    156: 
                    157:     timer_set_expire_func(SystemWide, (timer_func_t)_delayed_call_interrupt);
                    158: 
                    159:     thread_call_initialized = TRUE;
                    160: }
                    161: 
                    162: /*
                    163:  * Routine:    _internal_call_allocate [private, inline]
                    164:  *
                    165:  * Purpose:    Allocate an internal callout entry.
                    166:  *
                    167:  * Preconditions:      thread_call_lock held.
                    168:  *
                    169:  * Postconditions:     None.
                    170:  */
                    171: 
                    172: static __inline__ _thread_call_t
                    173: _internal_call_allocate(void)
                    174: {
                    175:     _thread_call_t     call;
                    176:     
                    177:     if (queue_empty(&internal_call_free_queue))
                    178:        panic("_internal_call_allocate");
                    179:        
                    180:     call = TC(dequeue_head(&internal_call_free_queue));
                    181:     
                    182:     return (call);
                    183: }
                    184: 
                    185: /*
                    186:  * Routine:    thread_call_release [private, inline]
                    187:  *
                    188:  * Purpose:    Release a callout entry which is no
                    189:  *             longer pending (or delayed).  Returns
                    190:  *             its argument for external entries, zero
                    191:  *             otherwise.
                    192:  *
                    193:  * Preconditions:      thread_call_lock held.
                    194:  *
                    195:  * Postconditions:     None.
                    196:  */
                    197: 
                    198: static __inline__
                    199: _thread_call_t
                    200: thread_call_release(
                    201:     _thread_call_t     call
                    202: )
                    203: {
                    204:     if (
                    205:            call >= internal_call_storage
                    206:        &&
                    207:            call < &internal_call_storage[internal_call_num]) {
                    208:     
                    209:        enqueue_tail(&internal_call_free_queue, qe(call)); call = 0;
                    210:     }
                    211:     
                    212:     return (call);
                    213: }
                    214: 
                    215: /*
                    216:  * Routine:    _pending_call_enqueue [private, inline]
                    217:  *
                    218:  * Purpose:    Place an entry at the end of the
                    219:  *             pending queue, to be executed soon.
                    220:  *
                    221:  * Preconditions:      thread_call_lock held.
                    222:  *
                    223:  * Postconditions:     None.
                    224:  */
                    225: 
                    226: static __inline__
                    227: void
                    228: _pending_call_enqueue(
                    229:     _thread_call_t     call
                    230: )
                    231: {
                    232:     enqueue_tail(&pending_call_queue, qe(call)); pending_call_num++;
                    233: 
                    234:     call->status = PENDING;
                    235: }
                    236: 
                    237: /*
                    238:  * Routine:    _pending_call_dequeue [private, inline]
                    239:  *
                    240:  * Purpose:    Remove an entry from the pending queue,
                    241:  *             effectively unscheduling it.
                    242:  *
                    243:  * Preconditions:      thread_call_lock held.
                    244:  *
                    245:  * Postconditions:     None.
                    246:  */
                    247: 
                    248: static __inline__
                    249: void
                    250: _pending_call_dequeue(
                    251:     _thread_call_t     call
                    252: )
                    253: {
                    254:     remqueue(&pending_call_queue, qe(call)); pending_call_num--;
                    255:     
                    256:     call->status = IDLE;
                    257: }
                    258: 
                    259: /*
                    260:  * Routine:    _delayed_call_enqueue [private, inline]
                    261:  *
                    262:  * Purpose:    Place an entry on the delayed queue,
                    263:  *             after existing entries with an earlier
                    264:  *             (or identical) deadline.
                    265:  *
                    266:  * Preconditions:      thread_call_lock held.
                    267:  *
                    268:  * Postconditions:     None.
                    269:  */
                    270: 
                    271: static __inline__
                    272: void
                    273: _delayed_call_enqueue(
                    274:     _thread_call_t     call
                    275: )
                    276: {
                    277:     _thread_call_t     current;
                    278:     int                        deadline_cmp;
                    279:     
                    280:     current = TC(queue_first(&delayed_call_queue));
                    281:     
                    282:     while (TRUE) {
                    283:        if (
                    284:                queue_end(&delayed_call_queue, qe(current))
                    285:            ||
                    286:                (deadline_cmp = CMP_TVALSPEC(&call->deadline,
                    287:                                                &current->deadline)) < 0) {
                    288:            current = TC(queue_prev(qe(current)));
                    289:            break;
                    290:        }
                    291:        else if (deadline_cmp == 0)
                    292:            break;
                    293:            
                    294:        current = TC(queue_next(qe(current)));
                    295:     }
                    296: 
                    297:     insque(qe(call), qe(current));
                    298:     
                    299:     call->status = DELAYED;
                    300: }
                    301: 
                    302: /*
                    303:  * Routine:    _delayed_call_dequeue [private, inline]
                    304:  *
                    305:  * Purpose:    Remove an entry from the delayed queue,
                    306:  *             effectively unscheduling it.
                    307:  *
                    308:  * Preconditions:      thread_call_lock held.
                    309:  *
                    310:  * Postconditions:     None.
                    311:  */
                    312: 
                    313: static __inline__
                    314: void
                    315: _delayed_call_dequeue(
                    316:     _thread_call_t     call
                    317: )
                    318: {
                    319:     remqueue(&delayed_call_queue, qe(call));
                    320:     
                    321:     call->status = IDLE;
                    322: }
                    323: 
                    324: /*
                    325:  * Routine:    _set_delayed_call_timer [private]
                    326:  *
                    327:  * Purpose:    Reset the timer so that it
                    328:  *             next expires when the entry is due.
                    329:  *
                    330:  * Preconditions:      thread_call_lock held.
                    331:  *
                    332:  * Postconditions:     None.
                    333:  */
                    334: 
                    335: static __inline__ void
                    336: _set_delayed_call_timer(
                    337:     _thread_call_t     call
                    338: )
                    339: {
                    340:     timer_set_deadline(SystemWide, call->deadline);
                    341: }
                    342: 
                    343: /*
                    344:  * Routine:    _remove_from_pending_queue [private]
                    345:  *
                    346:  * Purpose:    Remove the first (or all) matching
                    347:  *             entries from the pending queue,
                    348:  *             effectively unscheduling them.
                    349:  *             Returns whether any matching entries
                    350:  *             were found for the !removeAll case,
                    351:  *             FALSE otherwise.
                    352:  *
                    353:  * Preconditions:      thread_call_lock held.
                    354:  *
                    355:  * Postconditions:     None.
                    356:  */
                    357: 
                    358: static
                    359: boolean_t
                    360: _remove_from_pending_queue(
                    361:     thread_call_func_t func,
                    362:     thread_call_spec_t spec,
                    363:     boolean_t          remove_all
                    364: )
                    365: {
                    366:     boolean_t          call_removed = FALSE;
                    367:     _thread_call_t     call;
                    368:     
                    369:     call = TC(queue_first(&pending_call_queue));
                    370:     
                    371:     while (!queue_end(&pending_call_queue, qe(call))) {
                    372:        if (
                    373:                call->func == func
                    374:            &&
                    375:                call->spec == spec) {
                    376:            _thread_call_t      next = TC(queue_next(qe(call)));
                    377:                
                    378:            _pending_call_dequeue(call);
                    379:            
                    380:            thread_call_release(call);
                    381:            
                    382:            call_removed = TRUE;
                    383:            if (!remove_all)
                    384:                break;
                    385:                
                    386:            call = next;
                    387:        }
                    388:        else    
                    389:            call = TC(queue_next(qe(call)));
                    390:     }
                    391:     
                    392:     return (!remove_all? call_removed : FALSE);
                    393: }
                    394: 
                    395: /*
                    396:  * Routine:    _remove_from_delayed_queue [private]
                    397:  *
                    398:  * Purpose:    Remove the first (or all) matching
                    399:  *             entries from the delayed queue,
                    400:  *             effectively unscheduling them.
                    401:  *             Returns whether any matching entries
                    402:  *             were found for the !removeAll case,
                    403:  *             FALSE otherwise.
                    404:  *
                    405:  * Preconditions:      thread_call_lock held.
                    406:  *
                    407:  * Postconditions:     None.
                    408:  */
                    409: 
                    410: static
                    411: boolean_t
                    412: _remove_from_delayed_queue(
                    413:     thread_call_func_t func,
                    414:     thread_call_spec_t spec,
                    415:     boolean_t          remove_all
                    416: )
                    417: {
                    418:     boolean_t          call_removed = FALSE;
                    419:     _thread_call_t     call;
                    420:     
                    421:     call = TC(queue_first(&delayed_call_queue));
                    422:     
                    423:     while (!queue_end(&delayed_call_queue, qe(call))) {
                    424:        if (
                    425:                call->func == func
                    426:            &&
                    427:                call->spec == spec) {
                    428:            _thread_call_t      next = TC(queue_next(qe(call)));
                    429:                
                    430:            _delayed_call_dequeue(call);
                    431:            
                    432:            thread_call_release(call);
                    433:            
                    434:            call_removed = TRUE;
                    435:            if (!remove_all)
                    436:                break;
                    437:                
                    438:            call = next;
                    439:        }
                    440:        else    
                    441:            call = TC(queue_next(qe(call)));
                    442:     }
                    443:     
                    444:     return (!remove_all? call_removed : FALSE);
                    445: }
                    446: 
                    447: tvalspec_t
                    448: deadline_from_interval(
                    449:     tvalspec_t         interval
                    450: )
                    451: {
                    452:     tvalspec_t         result = clock_get_counter(System);
                    453: 
                    454:     ADD_TVALSPEC(&result, &interval);
                    455: 
                    456:     return (result);
                    457: }
                    458: 
                    459: /*
                    460:  * Routine:    thread_call_func [public]
                    461:  *
                    462:  * Purpose:    Schedule a function callout.
                    463:  *             Guarantees { function, argument }
                    464:  *             uniqueness if unique_call is TRUE.
                    465:  *
                    466:  * Preconditions:      Callable from an interrupt context
                    467:  *                     below splsched.
                    468:  *
                    469:  * Postconditions:     None.
                    470:  */
                    471: 
                    472: void
                    473: thread_call_func(
                    474:     thread_call_func_t func,
                    475:     thread_call_spec_t spec,
                    476:     boolean_t          unique_call
                    477: )
                    478: {
                    479:     _thread_call_t     call;
                    480:     int                        s;
                    481:     
                    482:     if (!thread_call_initialized)
                    483:        panic("thread_call_func_unique");
                    484:        
                    485:     s = splsched();
                    486:     
                    487:     simple_lock(&thread_call_lock);
                    488:     
                    489:     call = TC(queue_first(&pending_call_queue));
                    490:     
                    491:     if (unique_call) while (!queue_end(&pending_call_queue, qe(call))) {
                    492:        if (
                    493:                call->func == func
                    494:            &&
                    495:                call->spec == spec) {
                    496:                
                    497:            break;
                    498:        }
                    499:        
                    500:        call = TC(queue_next(qe(call)));
                    501:     }
                    502:     
                    503:     if (!unique_call || queue_end(&pending_call_queue, qe(call))) {
                    504:     
                    505:        call = _internal_call_allocate();
                    506:     
                    507:        KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALLOUT),
                    508:                     0, call->func, call->spec,
                    509:                     0, 0);
                    510:        call->func              = func;
                    511:        call->spec              = spec;
                    512:        call->spec_proto        = 0;
                    513:        
                    514:        _pending_call_enqueue(call);
                    515:                
                    516:        _call_thread_wake();
                    517:     }
                    518:     else
                    519:        simple_unlock(&thread_call_lock);
                    520:     
                    521:     splx(s);
                    522: }
                    523: 
                    524: /*
                    525:  * Routine:    thread_call_func_delayed [public]
                    526:  *
                    527:  * Purpose:    Schedule a function callout to
                    528:  *             occur at the stated time.
                    529:  *
                    530:  * Preconditions:      Callable from an interrupt context
                    531:  *                     below splsched.
                    532:  *
                    533:  * Postconditions:     None.
                    534:  */
                    535: 
                    536: void
                    537: thread_call_func_delayed(
                    538:     thread_call_func_t func,
                    539:     thread_call_spec_t spec,
                    540:     tvalspec_t         deadline
                    541: )
                    542: {
                    543:     _thread_call_t     call;
                    544:     int                        s;
                    545:     
                    546:     if (!thread_call_initialized)
                    547:        panic("thread_call_func_delayed");
                    548: 
                    549:     if (BAD_TVALSPEC(&deadline))
                    550:        deadline = TVALSPEC_ZERO;
                    551: 
                    552:     s = splsched();
                    553: 
                    554:     simple_lock(&thread_call_lock);
                    555:     
                    556:     call = _internal_call_allocate();
                    557: 
                    558:     KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALLOUT),
                    559:                 1, func, spec,
                    560:                 deadline.tv_sec, deadline.tv_nsec);
                    561:     call->func         = func;
                    562:     call->spec         = spec;
                    563:     call->spec_proto   = 0;
                    564:     call->deadline     = deadline;
                    565:     
                    566:     _delayed_call_enqueue(call);
                    567:     
                    568:     if (queue_first(&delayed_call_queue) == qe(call))
                    569:        _set_delayed_call_timer(call);
                    570:     
                    571:     simple_unlock(&thread_call_lock);
                    572:     
                    573:     splx(s);
                    574: }
                    575: 
                    576: /*
                    577:  * Routine:    thread_call_func_cancel [public]
                    578:  *
                    579:  * Purpose:    Unschedule a function callout.
                    580:  *             Removes one (or all)
                    581:  *             { function, argument }
                    582:  *             instance(s) from either (or both)
                    583:  *             the pending and the delayed queue,
                    584:  *             in that order.
                    585:  *
                    586:  * Preconditions:      Callable from an interrupt context
                    587:  *                     below splsched.
                    588:  *
                    589:  * Postconditions:     None.
                    590:  */
                    591: 
                    592: void
                    593: thread_call_func_cancel(
                    594:     thread_call_func_t func,
                    595:     thread_call_spec_t spec,
                    596:     boolean_t          cancel_all
                    597: )
                    598: {
                    599:     int                        s;
                    600:     
                    601:     s = splsched();
                    602:     
                    603:     simple_lock(&thread_call_lock);
                    604:     
                    605:     KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALLOUT),
                    606:                 2, func, spec,
                    607:                 cancel_all, 0);
                    608:     _remove_from_pending_queue(func, spec, cancel_all) ||
                    609:        _remove_from_delayed_queue(func, spec, cancel_all);
                    610:     
                    611:     simple_unlock(&thread_call_lock);
                    612:     
                    613:     splx(s);
                    614: }
                    615: 
                    616: /*
                    617:  * Routine:    thread_call_allocate [public]
                    618:  *
                    619:  * Purpose:    Allocate an external callout
                    620:  *             entry.
                    621:  *
                    622:  * Preconditions:      None.
                    623:  *
                    624:  * Postconditions:     None.
                    625:  */
                    626: 
                    627: thread_call_t
                    628: thread_call_allocate(
                    629:     thread_call_func_t func,
                    630:     thread_call_spec_t spec
                    631: )
                    632: {
                    633:     _thread_call_t     call = (void *)kalloc(sizeof (struct _thread_call));
                    634:     
                    635:     call->func         = func;
                    636:     call->spec         = 0;
                    637:     call->spec_proto   = spec;
                    638:     call->deadline     = TVALSPEC_ZERO;
                    639:     call->status       = IDLE;
                    640:     
                    641:     return (call);
                    642: }
                    643: 
                    644: /*
                    645:  * Routine:    thread_call_free [public]
                    646:  *
                    647:  * Purpose:    Free an external callout
                    648:  *             entry.
                    649:  *
                    650:  * Preconditions:      None.
                    651:  *
                    652:  * Postconditions:     None.
                    653:  */
                    654: 
                    655: void
                    656: thread_call_free(
                    657:     thread_call_t      _call
                    658: )
                    659: {
                    660:     _thread_call_t     call = _call;
                    661:     int                        s;
                    662:     
                    663:     s = splsched();
                    664:     
                    665:     simple_lock(&thread_call_lock);
                    666:     
                    667:     if (call->status != IDLE) {
                    668:        simple_unlock(&thread_call_lock);
                    669:        panic("thread_call_free");
                    670:     }
                    671:     
                    672:     simple_unlock(&thread_call_lock);
                    673:     
                    674:     splx(s);
                    675:     
                    676:     kfree((void *)call, sizeof (struct _thread_call));
                    677: }
                    678: 
                    679: /*
                    680:  * Routine:    thread_call_enter [public]
                    681:  *
                    682:  * Purpose:    Schedule an external callout 
                    683:  *             entry.  There is no effect if
                    684:  *             the entry is not idle.
                    685:  *
                    686:  * Preconditions:      Callable from an interrupt context
                    687:  *                     below splsched.
                    688:  *
                    689:  * Postconditions:     None.
                    690:  */
                    691: 
                    692: void
                    693: thread_call_enter(
                    694:     thread_call_t      _call
                    695: )
                    696: {
                    697:     _thread_call_t     call = _call;
                    698:     int                        s;
                    699:     
                    700:     s = splsched();
                    701:     
                    702:     simple_lock(&thread_call_lock);
                    703:     
                    704:     if (call->status == IDLE) {
                    705:        call->spec = call->spec_proto;
                    706: 
                    707:        _pending_call_enqueue(call);
                    708:        
                    709:        _call_thread_wake();
                    710:     }
                    711:     else
                    712:        simple_unlock(&thread_call_lock);
                    713: 
                    714:     splx(s);
                    715: }
                    716: 
                    717: void
                    718: thread_call_enter_spec(
                    719:     thread_call_t      _call,
                    720:     thread_call_spec_t spec
                    721: )
                    722: {
                    723:     _thread_call_t     call = _call;
                    724:     int                        s;
                    725:     
                    726:     s = splsched();
                    727:     
                    728:     simple_lock(&thread_call_lock);
                    729:     
                    730:     if (call->status == IDLE) {
                    731:        call->spec = spec;
                    732: 
                    733:        _pending_call_enqueue(call);
                    734:        
                    735:        _call_thread_wake();
                    736:     }
                    737:     else
                    738:        simple_unlock(&thread_call_lock);
                    739: 
                    740:     splx(s);
                    741: }
                    742: 
                    743: /*
                    744:  * Routine:    thread_call_enter_delayed [public]
                    745:  *
                    746:  * Purpose:    Schedule an external callout 
                    747:  *             entry to occur at the stated time.
                    748:  *             There is no effect if the entry
                    749:  *             is not idle.
                    750:  *
                    751:  * Preconditions:      Callable from an interrupt context
                    752:  *                     below splsched.
                    753:  *
                    754:  * Postconditions:     None.
                    755:  */
                    756: 
                    757: void
                    758: thread_call_enter_delayed(
                    759:     thread_call_t      _call,
                    760:     tvalspec_t         deadline
                    761: )
                    762: {
                    763:     _thread_call_t     call = _call;
                    764:     int                        s;
                    765: 
                    766:     if (BAD_TVALSPEC(&deadline))
                    767:        deadline = TVALSPEC_ZERO;
                    768: 
                    769:     s = splsched();
                    770: 
                    771:     simple_lock(&thread_call_lock);
                    772: 
                    773:     if (call->status == IDLE) {
                    774:        call->spec      = call->spec_proto;
                    775:        call->deadline  = deadline;
                    776: 
                    777:        _delayed_call_enqueue(call);
                    778: 
                    779:        if (queue_first(&delayed_call_queue) == qe(call))
                    780:            _set_delayed_call_timer(call);
                    781:     }
                    782: 
                    783:     simple_unlock(&thread_call_lock);
                    784: 
                    785:     splx(s);
                    786: }
                    787: 
                    788: void
                    789: thread_call_enter_spec_delayed(
                    790:     thread_call_t      _call,
                    791:     thread_call_spec_t spec,
                    792:     tvalspec_t         deadline
                    793: )
                    794: {
                    795:     _thread_call_t     call = _call;
                    796:     int                        s;
                    797: 
                    798:     if (BAD_TVALSPEC(&deadline))
                    799:        deadline = TVALSPEC_ZERO;
                    800: 
                    801:     s = splsched();
                    802: 
                    803:     simple_lock(&thread_call_lock);
                    804: 
                    805:     if (call->status == IDLE) {
                    806:        call->spec      = spec;
                    807:        call->deadline  = deadline;
                    808: 
                    809:        _delayed_call_enqueue(call);
                    810: 
                    811:        if (queue_first(&delayed_call_queue) == qe(call))
                    812:            _set_delayed_call_timer(call);
                    813:     }
                    814: 
                    815:     simple_unlock(&thread_call_lock);
                    816: 
                    817:     splx(s);
                    818: }
                    819: 
                    820: /*
                    821:  * Routine:    thread_call_cancel [public]
                    822:  *
                    823:  * Purpose:    Unschedule a callout entry.
                    824:  *             There is no effect if the
                    825:  *             entry is already idle.
                    826:  *
                    827:  * Preconditions:      Callable from an interrupt context
                    828:  *                     below splsched.
                    829:  *
                    830:  * Postconditions:     None.
                    831:  */
                    832: 
                    833: void
                    834: thread_call_cancel(
                    835:     thread_call_t      _call
                    836: )
                    837: {
                    838:     _thread_call_t     call = _call;
                    839:     int                        s;
                    840:     
                    841:     s = splsched();
                    842:     
                    843:     simple_lock(&thread_call_lock);
                    844:     
                    845:     if (call->status == PENDING) {
                    846:        _pending_call_dequeue(call);
                    847:        
                    848:        thread_call_release(call);
                    849:     }
                    850:     else if (call->status == DELAYED) {
                    851:        _delayed_call_dequeue(call);
                    852:        
                    853:        thread_call_release(call);
                    854:     }
                    855:     else
                    856:        /* do nothing */;
                    857:        
                    858:     simple_unlock(&thread_call_lock);
                    859:     
                    860:     splx(s);
                    861: }
                    862: 
                    863: /*
                    864:  * Routine:    _call_thread_wake [private]
                    865:  *
                    866:  * Purpose:    Wakeup one callout thread to handle
                    867:  *             a new callout entry.  May wakeup
                    868:  *             the callout activate thread to
                    869:  *             create a new callout thread.
                    870:  *
                    871:  * Preconditions:      thread_call_lock held.
                    872:  *
                    873:  * Postconditions:     thread_call_lock released.
                    874:  */
                    875: 
                    876: static __inline__
                    877: void
                    878: _call_thread_wake(void)
                    879: {
                    880:     boolean_t          wake_activate_thread = FALSE;
                    881:     
                    882:     if (call_thread_num < (active_call_num + pending_call_num))
                    883:        wake_activate_thread = TRUE;
                    884:        
                    885:     simple_unlock(&thread_call_lock);
                    886: 
                    887:     thread_wakeup_one(&pending_call_num);
                    888:     
                    889:     if (wake_activate_thread)
                    890:        thread_wakeup_one(&call_thread_num);
                    891: }
                    892: 
                    893: /*
                    894:  * Routine:    _call_thread [private]
                    895:  *
                    896:  * Purpose:    Executed by a callout thread.
                    897:  *
                    898:  * Preconditions:      None.
                    899:  *
                    900:  * Postconditions:     None.
                    901:  */
                    902: 
                    903: static
                    904: void
                    905: _call_thread_continue(void)
                    906: {
                    907:     thread_t           self = current_thread();
                    908:     
                    909:     (void) splsched();
                    910:     
                    911:     simple_lock(&thread_call_lock);
                    912: 
                    913:     while (pending_call_num > 0) {
                    914:        _thread_call_t          call;
                    915:        thread_call_func_t              func;
                    916:        thread_call_spec_t              spec;
                    917: 
                    918:        call = TC(dequeue_head(&pending_call_queue)); pending_call_num--;
                    919: 
                    920:        func = call->func;
                    921:        spec = call->spec;
                    922:        
                    923:        call->status = IDLE;
                    924: 
                    925:        call = thread_call_release(call);
                    926: 
                    927:        active_call_num++; simple_unlock(&thread_call_lock);
                    928:        
                    929:        KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALLOUT) | DBG_FUNC_START,
                    930:                     3, self, func, 
                    931:                     spec, 0);
                    932: 
                    933:        (void) spl0(); (*func)(spec, call); (void) splsched();
                    934:        
                    935:        KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALLOUT) | DBG_FUNC_END,
                    936:                     4, self, 
                    937:                     func, spec,
                    938:                     0);
                    939: 
                    940:        simple_lock(&thread_call_lock); active_call_num--;
                    941:     }
                    942:        
                    943:     if ((call_thread_num - active_call_num) <= call_thread_min) {
                    944:            
                    945:        assert_wait(&pending_call_num, FALSE);
                    946:        
                    947:        simple_unlock(&thread_call_lock);
                    948:        
                    949:        thread_block_with_continuation(_call_thread_continue);
                    950:        /* NOTREACHED */
                    951:     }
                    952:     
                    953:     call_thread_num--;
                    954:     
                    955:     simple_unlock(&thread_call_lock);
                    956:     
                    957:     (void) spl0();
                    958:     
                    959:     (void) thread_terminate(self); thread_halt_self();
                    960: }
                    961: 
                    962: static
                    963: void
                    964: _call_thread(void)
                    965: {
                    966:     stack_privilege(current_thread());
                    967:     
                    968:     _call_thread_continue();
                    969:     /* NOTREACHED */
                    970: }
                    971: 
                    972: /*
                    973:  * Routine:    _call_activate_thread [private]
                    974:  *
                    975:  * Purpose:    Executed by the callout activate thread.
                    976:  *
                    977:  * Preconditions:      None.
                    978:  *
                    979:  * Postconditions:     Never terminates.
                    980:  */
                    981: 
                    982: static
                    983: void
                    984: _call_activate_thread_continue(void)
                    985: {
                    986:     thread_t           self = current_thread();
                    987:         
                    988:     (void) splsched();
                    989:     
                    990:     simple_lock(&thread_call_lock);
                    991:         
                    992:     if (call_thread_num < (active_call_num + pending_call_num)) {
                    993: 
                    994:        call_thread_num++; simple_unlock(&thread_call_lock);
                    995:        
                    996:        (void) kernel_thread(self->task, _call_thread, (void *)0);
                    997:        
                    998:        thread_block_with_continuation(_call_activate_thread_continue);
                    999:        /* NOTREACHED */
                   1000:     }
                   1001:                
                   1002:     assert_wait(&call_thread_num, FALSE);
                   1003:     
                   1004:     simple_unlock(&thread_call_lock);
                   1005:     
                   1006:     thread_block_with_continuation(_call_activate_thread_continue);
                   1007:     /* NOTREACHED */
                   1008: }
                   1009: 
                   1010: static
                   1011: void
                   1012: _call_activate_thread(void)
                   1013: {
                   1014:     stack_privilege(current_thread());
                   1015:     
                   1016:     _call_activate_thread_continue();
                   1017:     /* NOTREACHED */
                   1018: }
                   1019: 
                   1020: static
                   1021: void
                   1022: _delayed_call_interrupt(
                   1023:     tvalspec_t         timestamp
                   1024: )
                   1025: {
                   1026:     _thread_call_t     call;
                   1027:     queue_head_t       intransit_call_queue;
                   1028:     int                        s;
                   1029:     
                   1030:     queue_init(&intransit_call_queue);
                   1031:     
                   1032:     s = splsched();
                   1033:     
                   1034:     simple_lock(&thread_call_lock);
                   1035:     
                   1036:     call = TC(queue_first(&delayed_call_queue));
                   1037:     
                   1038:     while (!queue_end(&delayed_call_queue, qe(call))) {
                   1039:        if (CMP_TVALSPEC(&call->deadline, &timestamp) <= 0) {
                   1040:            _delayed_call_dequeue(call);
                   1041:            
                   1042:            enqueue_tail(&intransit_call_queue, qe(call));
                   1043:        }
                   1044:        else
                   1045:            break;
                   1046:            
                   1047:        call = TC(queue_first(&delayed_call_queue));
                   1048:     }
                   1049:     
                   1050:     if (!queue_end(&delayed_call_queue, qe(call)))
                   1051:        _set_delayed_call_timer(call);
                   1052:     
                   1053:     while (call = TC(dequeue_head(&intransit_call_queue))) {
                   1054:        _pending_call_enqueue(call);
                   1055:            
                   1056:        _call_thread_wake();
                   1057:            
                   1058:        simple_lock(&thread_call_lock);
                   1059:     }
                   1060:     
                   1061:     simple_unlock(&thread_call_lock);
                   1062:     
                   1063:     splx(s);
                   1064: }

unix.superglobalmegacorp.com

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