Annotation of XNU/osfmk/kern/thread_call.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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