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

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

unix.superglobalmegacorp.com

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