Annotation of XNU/osfmk/kern/thread_call.c, revision 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.