Annotation of XNU/osfmk/kern/mk_sp.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_COPYRIGHT@
        !            24:  * 
        !            25:  */
        !            26: 
        !            27: /***
        !            28:  *** ??? The following lines were picked up when code was incorporated
        !            29:  *** into this file from `kern/syscall_subr.c.'  These should be moved
        !            30:  *** with the code if it moves again.  Otherwise, they should be trimmed,
        !            31:  *** based on the files included above.
        !            32:  ***/
        !            33: 
        !            34: #include <mach/boolean.h>
        !            35: #include <mach/thread_switch.h>
        !            36: #include <ipc/ipc_port.h>
        !            37: #include <ipc/ipc_space.h>
        !            38: #include <kern/counters.h>
        !            39: #include <kern/ipc_kobject.h>
        !            40: #include <kern/processor.h>
        !            41: #include <kern/sched.h>
        !            42: #include <kern/sched_prim.h>
        !            43: #include <kern/spl.h>
        !            44: #include <kern/task.h>
        !            45: #include <kern/thread.h>
        !            46: #include <kern/ast.h>
        !            47: #include <mach/policy.h>
        !            48: 
        !            49: #include <kern/syscall_subr.h>
        !            50: #include <mach/mach_host_server.h>
        !            51: #include <mach/mach_syscalls.h>
        !            52: 
        !            53: /***
        !            54:  *** ??? End of lines picked up when code was incorporated
        !            55:  *** into this file from `kern/syscall_subr.c.'
        !            56:  ***/
        !            57: 
        !            58: #include <kern/sf.h>
        !            59: #include <kern/mk_sp.h>
        !            60: #include <kern/misc_protos.h>
        !            61: #include <kern/spl.h>
        !            62: #include <kern/sched.h>
        !            63: #include <kern/sched_prim.h>
        !            64: #include <kern/assert.h>
        !            65: #include <kern/thread.h>
        !            66: #include <mach/mach_host_server.h>
        !            67: 
        !            68: /* Forwards */
        !            69: void   _mk_sp_thread_depress_priority(
        !            70:                        sf_object_t                     policy,
        !            71:                        mach_msg_timeout_t      depress_time);
        !            72: 
        !            73: /***
        !            74:  *** ??? The next two files supply the prototypes for `thread_set_policy()'
        !            75:  *** and `thread_policy.'  These routines cannot stay here if they are
        !            76:  *** exported Mach system calls.
        !            77:  ***/
        !            78: #include <mach/thread_act_server.h>
        !            79: #include <mach/host_priv_server.h>
        !            80: 
        !            81: /*
        !            82:  * Vector containing standard scheduling policy operations
        !            83:  */
        !            84: sp_ops_t       mk_sp_ops = {
        !            85:                    _mk_sp_init,
        !            86:                    _mk_sp_enable_processor_set,
        !            87:                    _mk_sp_disable_processor_set,
        !            88:                    _mk_sp_enable_processor,
        !            89:                    _mk_sp_disable_processor,
        !            90:                    _mk_sp_thread_update_mpri,
        !            91:                    _mk_sp_thread_unblock,
        !            92:                    _mk_sp_thread_done,
        !            93:                    _mk_sp_thread_begin,
        !            94:                    _mk_sp_thread_dispatch,
        !            95:                    _mk_sp_thread_attach,
        !            96:                    _mk_sp_thread_detach,
        !            97:                    _mk_sp_thread_processor,
        !            98:                    _mk_sp_thread_processor_set,
        !            99:                    _mk_sp_thread_set,
        !           100:                    _mk_sp_thread_get,
        !           101:                    _mk_sp_db_print_sched_stats,
        !           102:                    _mk_sp_swtch_pri,
        !           103:                    _mk_sp_thread_switch,
        !           104:                    _mk_sp_thread_depress_abort,
        !           105:                    _mk_sp_thread_depress_timeout,
        !           106:                    _mk_sp_task_attach,
        !           107:                    _mk_sp_task_detach,
        !           108:                    _mk_sp_task_policy,
        !           109:                    _mk_sp_task_set_policy,
        !           110:                    _mk_sp_task_set_sched,
        !           111:                    _mk_sp_task_get_sched,
        !           112:                    _mk_sp_thread_runnable,
        !           113:                    _mk_sp_alarm_expired
        !           114: };
        !           115: 
        !           116: /* Forwards */
        !           117: kern_return_t  thread_policy_common(
        !           118:                                        thread_t                thread,
        !           119:                                        int                             policy,
        !           120:                                        int                             data,
        !           121:                                        processor_set_t pset);
        !           122: 
        !           123: void           _mk_sp_thread_dump(
        !           124:                                        sched_thread_t  thread);
        !           125: 
        !           126: /*
        !           127:  * Local variables
        !           128:  */
        !           129: #ifdef MACH_ASSERT
        !           130: boolean_t      mk_sp_first_thread = TRUE;
        !           131: #endif /* MACH_ASSERT */
        !           132: 
        !           133: /*
        !           134:  * Counters to monitor policy-related events
        !           135:  */
        !           136: mach_counter_t c_mk_sp_init = 0,
        !           137:                c_mk_sp_enable_processor_set = 0,
        !           138:                c_mk_sp_disable_processor_set = 0,
        !           139:                c_mk_sp_enable_processor = 0,
        !           140:                c_mk_sp_disable_processor = 0,
        !           141:                c_mk_sp_thread_update_mpri = 0,
        !           142:                c_mk_sp_thread_unblock = 0,
        !           143:                c_mk_sp_thread_done = 0,
        !           144:                c_mk_sp_thread_begin = 0,
        !           145:                c_mk_sp_thread_dispatch = 0,
        !           146:                c_mk_sp_thread_attach = 0,
        !           147:                c_mk_sp_thread_detach = 0,
        !           148:                c_mk_sp_thread_processor = 0,
        !           149:                c_mk_sp_thread_processor_set = 0,
        !           150:                c_mk_sp_thread_set = 0,
        !           151:                c_mk_sp_thread_get = 0,
        !           152:                c_mk_sp_db_print_sched_stats = 0,
        !           153:                c_mk_sp_swtch_pri = 0,
        !           154:                c_mk_sp_thread_switch = 0,
        !           155:                c_mk_sp_thread_depress_abort = 0,
        !           156:                c_mk_sp_thread_depress_timeout = 0,
        !           157:                c_mk_sp_task_attach = 0,
        !           158:                c_mk_sp_task_detach = 0,
        !           159:                c_mk_sp_task_policy = 0,
        !           160:                c_mk_sp_task_set_policy = 0,
        !           161:                c_mk_sp_task_set_sched = 0,
        !           162:                c_mk_sp_task_get_sched = 0,
        !           163:                c_mk_sp_thread_runnable = 0,
        !           164:                c_mk_sp_alarm_expired = 0;
        !           165: 
        !           166: /*
        !           167:  * Table to convert computed priorities into allocated priority range.
        !           168:  */
        !           169: int    convert_pri[NRQS];
        !           170: 
        !           171: /*
        !           172:  * Lowest (normal -- i.e., not idle and not depressed) priority
        !           173:  */
        !           174: int    lpri = -1;
        !           175: 
        !           176: natural_t      min_quantum_ms;
        !           177: 
        !           178: /*
        !           179:  * Standard operations for MK Scheduling Policy
        !           180:  */
        !           181: 
        !           182: sf_return_t
        !           183: _mk_sp_init(
        !           184:        sf_object_t                     policy,
        !           185:        int                                     policy_id,
        !           186:        int                                     priority_mask_length,
        !           187:        sf_priority_mask_t      priority_mask)
        !           188: {
        !           189:        int                                     i;
        !           190:        int                                     first_metapri;
        !           191:        int                                     last_metapri;
        !           192: 
        !           193:        counter(c_mk_sp_init++);
        !           194: 
        !           195:        /*
        !           196:         * Initialize fields in the structure
        !           197:         */
        !           198:        policy->policy_id = policy_id;
        !           199:        policy->priority_mask_length = priority_mask_length;
        !           200:        policy->priority_mask = *priority_mask;
        !           201:        /*** ??? should something more dynamic be done here for mask? ***/
        !           202:        policy->sched_attributes_size = sizeof (mk_sp_attribute_struct_t);
        !           203:        policy->sched_info_size = sizeof (mk_sp_info_struct_t);
        !           204: 
        !           205:        /*
        !           206:         * Initialize table that maps computed priority values into
        !           207:         * allocated metapriority values.
        !           208:         */
        !           209: 
        !           210:        /* Find first metapriority value allocated to this policy */
        !           211:        first_metapri = MAXPRI - ffsbit(priority_mask->bitmap);
        !           212:        /*** ??? how to test for no set bits? ***/
        !           213: 
        !           214:        /* Map computed priorities higher than this to first metapriority */
        !           215:        for (i = MAXPRI; i > first_metapri; i--)
        !           216:                convert_pri[i] = first_metapri;
        !           217:  
        !           218:        /* For each remaining computed priority value... */
        !           219:        for (i = first_metapri; i >= 0; i--) {
        !           220:                /* ... is it a metapriority value assigned to this policy ?*/
        !           221:                if (testbit(MAXPRI - i, priority_mask->bitmap)) {
        !           222:                        /* Yes; just use it */
        !           223:                        convert_pri[i] = i;
        !           224:                        last_metapri = i;
        !           225:                }
        !           226:                else {
        !           227:                        /* No, bump it up to the last value assigned */
        !           228:                        convert_pri[i] = last_metapri;
        !           229:                }
        !           230:        }
        !           231: 
        !           232:        /* Remember lowest "normal" priority available to this policy */
        !           233:        lpri = convert_pri[LPRI];
        !           234: 
        !           235:        min_quantum_ms = (1000 / hz) * min_quantum;
        !           236: 
        !           237: #if 0
        !           238:        /* Initialize operation entries in "jump table" */
        !           239:        /***
        !           240:         *** ??? These must be done elsewhere.  Otherwise, there is a
        !           241:         *** circularity: How does the framework find this init operation?
        !           242:         ***/
        !           243:        policy->sp_ops = mk_sp_ops;
        !           244: 
        !           245:        policy->sp_ops.sp_enable_processor_set = sp_mk_enable_processor_set;
        !           246:        policy->sp_ops.sp_disable_processor_set = sp_mk_disable_processor_set;
        !           247:        policy->sp_ops.sp_enable_processor = sp_mk_enable_processor;
        !           248:        policy->sp_ops.sp_disable_processor = sp_mk_disable_processor;
        !           249:        policy->sp_ops.sp_thread_unblock = sp_mk_thread_unblock;
        !           250:        policy->sp_ops.sp_thread_done = sp_mk_thread_done;
        !           251:        policy->sp_ops.sp_thread_begin = sp_mk_thread_begin;
        !           252:        policy->sp_ops.sp_thread_attach = sp_mk_thread_attach;
        !           253:        policy->sp_ops.sp_thread_detach = sp_mk_thread_detach;
        !           254:        policy->sp_ops.sp_thread_processor = sp_mk_thread_processor;
        !           255:        policy->sp_ops.sp_thread_processor_set = sp_mk_thread_processor_set;
        !           256:        policy->sp_ops.sp_thread_set = sp_mk_thread_set;
        !           257:        policy->sp_ops.sp_thread_get = sp_mk_thread_get;
        !           258:        policy->sp_ops.sp_db_print_sched_stats = sp_mk_db_print_sched_stats;
        !           259: #endif
        !           260: 
        !           261:        return(SF_SUCCESS);
        !           262: }
        !           263: 
        !           264: sf_return_t
        !           265: _mk_sp_enable_processor_set(
        !           266:        sf_object_t                     policy,
        !           267:        processor_set_t         processor_set)
        !           268: {
        !           269:        kern_return_t           result;
        !           270: 
        !           271:        counter(c_mk_sp_enable_processor_set++);
        !           272: 
        !           273:        result = processor_set_policy_enable(processor_set, policy->policy_id);
        !           274:        assert(result == KERN_SUCCESS);
        !           275: 
        !           276:        return(SF_SUCCESS);
        !           277: }
        !           278: 
        !           279: sf_return_t
        !           280: _mk_sp_disable_processor_set(
        !           281:        sf_object_t                     policy,
        !           282:        processor_set_t         processor_set)
        !           283: {
        !           284:        kern_return_t           result;
        !           285: 
        !           286:        counter(c_mk_sp_disable_processor_set++);
        !           287: 
        !           288:        result = processor_set_policy_disable(
        !           289:                                                                processor_set, policy->policy_id, TRUE);
        !           290:        assert(result == KERN_SUCCESS);
        !           291: 
        !           292:        return(SF_SUCCESS);
        !           293: }
        !           294: 
        !           295: sf_return_t
        !           296: _mk_sp_enable_processor(
        !           297:        sf_object_t             policy,
        !           298:        processor_t             processor)
        !           299: {
        !           300:        counter(c_mk_sp_enable_processor++);
        !           301: 
        !           302:        panic("not yet implemented???");
        !           303: 
        !           304:        return(SF_FAILURE);
        !           305: }
        !           306: 
        !           307: sf_return_t
        !           308: _mk_sp_disable_processor(
        !           309:        sf_object_t             policy,
        !           310:        processor_t             processor)
        !           311: {
        !           312:        counter(c_mk_sp_disable_processor++);
        !           313: 
        !           314:        panic("not yet implemented???");
        !           315: 
        !           316:        return(SF_FAILURE);
        !           317: }
        !           318: 
        !           319: sf_return_t
        !           320: _mk_sp_thread_update_mpri(
        !           321:        sf_object_t                     policy,
        !           322:        sched_thread_t          thread)
        !           323: {
        !           324:        mk_sp_info_t            sp_info;
        !           325: 
        !           326:        counter(c_mk_sp_thread_update_mpri++);
        !           327: 
        !           328:        /* get pointer to scheduling policy-specific data */
        !           329:        assert(thread->sp_info != SP_INFO_NULL);
        !           330:        sp_info = (mk_sp_info_t)thread->sp_info;
        !           331: 
        !           332:        if (sp_info->sched_stamp != sched_tick)
        !           333:                update_priority(thread);
        !           334: 
        !           335:        return(SF_SUCCESS);
        !           336: }
        !           337: 
        !           338: sf_return_t
        !           339: _mk_sp_thread_unblock(
        !           340:        sf_object_t                     policy,
        !           341:        sched_thread_t          thread)
        !           342: {
        !           343:        mk_sp_info_t            sp_info;
        !           344: 
        !           345:        counter(c_mk_sp_thread_unblock++);
        !           346: 
        !           347:        /* get pointer to scheduling policy-specific data */
        !           348:        assert(thread->sp_info != SP_INFO_NULL);
        !           349:        sp_info = (mk_sp_info_t)thread->sp_info;
        !           350: 
        !           351:        counter(sp_info->c_mk_sp_thread_unblock++);
        !           352: 
        !           353:        /*
        !           354:         * The following assert is removed because we're hacking the
        !           355:         * MK_SP_BLOCKED bit and removing it early to get SMP to work
        !           356:         * with this gosh darned scheduler.  The whole danged thing is lousy and 
        !           357:         * needs to be removed.  Hopefully for now, no one tries to
        !           358:         * unblock a really runnable guy - HACKALERT!!!
        !           359:         */             
        !           360:                                
        !           361:        /* check for legal thread states */
        !           362: #if 0
        !           363:        assert(sp_info->th_state == MK_SP_BLOCKED ||
        !           364:               sp_info->th_state == MK_SP_ATTACHED); /* ??? work to remove*/
        !           365: #endif
        !           366:        /* indicate thread is now runnable */
        !           367:        sp_info->th_state = MK_SP_RUNNABLE;
        !           368: 
        !           369:        /* place thread at end of appropriate run queue */
        !           370:        thread_setrun(thread, TRUE, TAIL_Q);
        !           371: 
        !           372:        return(SF_SUCCESS);
        !           373: }
        !           374: 
        !           375: sf_return_t
        !           376: _mk_sp_thread_done(
        !           377:        sf_object_t                     policy,
        !           378:        sched_thread_t          old_thread)
        !           379: {
        !           380:        processor_t                     myprocessor = cpu_to_processor(cpu_number());
        !           381:        mk_sp_info_t            sp_info;
        !           382: 
        !           383:        counter(c_mk_sp_thread_done++);
        !           384: 
        !           385:        /*
        !           386:         * A running thread is being taken off a processor:
        !           387:         *
        !           388:         *   - update the thread's `unconsumed_quantum' field
        !           389:         *   - update the thread's state field
        !           390:         */
        !           391: 
        !           392:        /* get pointer to scheduling policy-specific data */
        !           393:        assert(old_thread->sp_info != SP_INFO_NULL);
        !           394:        sp_info = (mk_sp_info_t)old_thread->sp_info;
        !           395: 
        !           396:        counter(sp_info->c_mk_sp_thread_done++);
        !           397:        assert((sp_info->c_mk_sp_thread_done
        !           398:                   == sp_info->c_mk_sp_thread_begin + 1) ||
        !           399:               (sp_info->c_mk_sp_thread_done
        !           400:                   == sp_info->c_mk_sp_thread_begin));
        !           401: 
        !           402:        sp_info->unconsumed_quantum = myprocessor->quantum;
        !           403: 
        !           404:        /* check thread's current state */
        !           405:        assert(mk_sp_first_thread || (sp_info->th_state & MK_SP_RUNNABLE));
        !           406: #ifdef MACH_ASSERT
        !           407:        mk_sp_first_thread = FALSE;
        !           408: #endif /* MACH_ASSERT */
        !           409: 
        !           410:        /* update thread's state field based on reason for stopping now */
        !           411:        /*** ??? is this condition correct? should it be more selective? ***/
        !           412:        /*** ??? if ((old_thread->reason != AST_NONE) ||
        !           413:            (old_thread->wait_event != NO_EVENT)) { ***/
        !           414:        if (old_thread->state & TH_WAIT) {
        !           415:                sp_info->th_state = MK_SP_BLOCKED;
        !           416:        }
        !           417: 
        !           418:        return(SF_SUCCESS);
        !           419: }
        !           420: 
        !           421: sf_return_t
        !           422: _mk_sp_thread_begin(
        !           423:        sf_object_t                     policy,
        !           424:        sched_thread_t          thread)
        !           425: {
        !           426: 
        !           427:        processor_t                     myprocessor = cpu_to_processor(cpu_number());
        !           428:        processor_set_t         pset;
        !           429:        mk_sp_info_t            sp_info;
        !           430: 
        !           431:        counter(c_mk_sp_thread_begin++);
        !           432: 
        !           433:        pset = myprocessor->processor_set;
        !           434:        /*
        !           435:         * The designated thread is about to begin execution:
        !           436:         *
        !           437:         *   - update the processor's `quantum' field
        !           438:         */
        !           439: 
        !           440:        /* get pointer to scheduling policy-specific data */
        !           441:        assert(thread->sp_info != SP_INFO_NULL);
        !           442:        sp_info = (mk_sp_info_t)thread->sp_info;
        !           443: 
        !           444:        counter(sp_info->c_mk_sp_thread_begin++);
        !           445:        assert((sp_info->c_mk_sp_thread_done
        !           446:                   == sp_info->c_mk_sp_thread_begin) ||
        !           447:               (sp_info->c_mk_sp_thread_done + 1
        !           448:                   == sp_info->c_mk_sp_thread_begin));
        !           449: 
        !           450:        /* check for legal thread state */
        !           451:        assert(sp_info->th_state == MK_SP_RUNNABLE);
        !           452: 
        !           453:        if (thread->policy & (POLICY_RR|POLICY_FIFO))
        !           454:                myprocessor->quantum = sp_info->unconsumed_quantum;
        !           455:        else
        !           456:                myprocessor->quantum = (thread->bound_processor ?
        !           457:                                                                                min_quantum : pset->set_quantum);
        !           458: 
        !           459:        return(SF_SUCCESS);
        !           460: }
        !           461: 
        !           462: sf_return_t
        !           463: _mk_sp_thread_dispatch(
        !           464:        sf_object_t                     policy,
        !           465:        sched_thread_t          old_thread)
        !           466: {
        !           467:        mk_sp_info_t    sp_info;
        !           468: 
        !           469:        counter(c_mk_sp_thread_dispatch++);
        !           470: 
        !           471:        /* get pointer to scheduling policy-specific data */
        !           472:        assert(old_thread->sp_info != SP_INFO_NULL);
        !           473:        sp_info = (mk_sp_info_t)old_thread->sp_info;
        !           474: 
        !           475:        counter(sp_info->c_mk_sp_thread_dispatch++);
        !           476: 
        !           477:        if (sp_info->th_state & MK_SP_RUNNABLE) {
        !           478:                if (old_thread->reason & AST_QUANTUM) {
        !           479:                        thread_setrun(old_thread, FALSE, TAIL_Q);
        !           480:                        sp_info->unconsumed_quantum = sp_info->sched_data;
        !           481:                }
        !           482:                else
        !           483:                        thread_setrun(old_thread, FALSE, HEAD_Q);
        !           484:        }
        !           485: 
        !           486:        if (sp_info->th_state & MK_SP_ATTACHED) {
        !           487:                /* indicate thread is now runnable */
        !           488:                sp_info->th_state = MK_SP_RUNNABLE;
        !           489: 
        !           490:                /* place thread at end of appropriate run queue */
        !           491:                thread_setrun(old_thread, FALSE, TAIL_Q);
        !           492:        }
        !           493: 
        !           494:        return(SF_SUCCESS);
        !           495: }
        !           496: 
        !           497: /*
        !           498:  * Thread must already be locked.
        !           499:  */
        !           500: sf_return_t
        !           501: _mk_sp_thread_attach(
        !           502:        sf_object_t                     policy,
        !           503:        sched_thread_t          thread)
        !           504: {
        !           505:        mk_sp_info_t            sp_info;
        !           506: 
        !           507:        counter(c_mk_sp_thread_attach++);
        !           508: 
        !           509:        /* Make sure there is a place for policy-specific state */
        !           510:        assert(thread->sp_info != SP_INFO_NULL);
        !           511: 
        !           512:        sp_info = (mk_sp_info_t)thread->sp_info;
        !           513:        sp_info->th_state = MK_SP_ATTACHED;
        !           514:        /*** ??? Do these need to be done here? ***/
        !           515:        /*** ??? If so, could fill from template for speed -- maybe ***/
        !           516:        sp_info->priority = MINPRI;             /*** ??? ***/
        !           517:        sp_info->max_priority = BASEPRI_USER;
        !           518:        /*** ??? sp_info->sched_pri =
        !           519:                        (later - compute_priority); (for now, at least) ***/
        !           520:        sp_info->sched_data = 0;
        !           521:        sp_info->policy = policy->policy_id;    /*** ??? ***/
        !           522:        sp_info->depress_priority = -1;
        !           523:        sp_info->cpu_usage = 0;
        !           524:        sp_info->sched_usage = 0;
        !           525:        sp_info->sched_stamp = 0;               /*** ??? ***/
        !           526:        sp_info->unconsumed_quantum = 0;        /*** ??? ***/
        !           527: 
        !           528: #ifdef MACH_ASSERT
        !           529:        sp_info->c_mk_sp_thread_attach = 1;
        !           530:        sp_info->c_mk_sp_thread_detach = 0;
        !           531:        sp_info->c_mk_sp_thread_begin = 0;
        !           532:        sp_info->c_mk_sp_thread_done = 0;
        !           533:        sp_info->c_mk_sp_thread_dispatch = 0;
        !           534:        sp_info->c_mk_sp_thread_unblock = 0;
        !           535:        sp_info->c_mk_sp_thread_set = 0;
        !           536:        sp_info->c_mk_sp_thread_get = 0;
        !           537: #endif /* MACH_ASSERT */
        !           538: 
        !           539:        /* Reflect this policy in thread data structure */
        !           540:        thread->policy = policy->policy_id;
        !           541: 
        !           542:        return(SF_SUCCESS);
        !           543: }
        !           544: 
        !           545: /*
        !           546:  * Check to make sure that thread is removed from run
        !           547:  * queues and active execution; and clean up the
        !           548:  * policy-specific data structure for thread.
        !           549:  *
        !           550:  * Thread must already be locked.
        !           551:  */
        !           552: sf_return_t
        !           553: _mk_sp_thread_detach(
        !           554:        sf_object_t                     policy,
        !           555:        sched_thread_t          thread)
        !           556: {
        !           557:        mk_sp_info_t            sp_info;
        !           558:        struct run_queue        *rq;
        !           559: 
        !           560:        assert(thread->policy == policy->policy_id);
        !           561: 
        !           562:        counter(c_mk_sp_thread_detach++);
        !           563:        /* get pointer to scheduling policy-specific data */
        !           564:        assert(thread->sp_info != SP_INFO_NULL);
        !           565:        sp_info = (mk_sp_info_t)thread->sp_info;
        !           566: 
        !           567:        counter(sp_info->c_mk_sp_thread_detach++);
        !           568: 
        !           569:        /* make sure that the thread has stopped executing */
        !           570:        /*** ??? look at machine's version of RUN bit, too? ***/
        !           571:        /***
        !           572:         *** Fix for SMP case.
        !           573:         ***/
        !           574: 
        !           575:        /* make sure that the thread is no longer on any run queue */
        !           576:        if (thread->runq != RUN_QUEUE_NULL) {
        !           577:                rq = rem_runq(thread);
        !           578:                if (rq == RUN_QUEUE_NULL) {
        !           579:                        panic("mk_sp_thread_detach: missed thread");
        !           580:                }
        !           581:        }
        !           582: 
        !           583:        /* (optionally) clear policy-specific data structure for the thread */
        !           584: 
        !           585:        if (sp_info->depress_priority >= 0) {
        !           586:                sp_info->priority = sp_info->depress_priority;
        !           587:                sp_info->depress_priority = -1;
        !           588:                if (thread_call_cancel(&thread->depress_timer))
        !           589:                        thread_call_enter(&thread->depress_timer);
        !           590:        }
        !           591: 
        !           592:        /* clear the thread's policy field */
        !           593:        thread->policy = POLICY_NULL;
        !           594: 
        !           595:        return(SF_SUCCESS);
        !           596: }
        !           597: 
        !           598: sf_return_t
        !           599: _mk_sp_thread_processor(
        !           600:        sf_object_t                     policy,
        !           601:        sched_thread_t          *thread,
        !           602:        processor_t                     processor)
        !           603: {
        !           604:        counter(c_mk_sp_thread_processor++);
        !           605: 
        !           606:        panic("not yet implemented???");
        !           607: 
        !           608:        return(SF_FAILURE);
        !           609: }
        !           610: 
        !           611: sf_return_t
        !           612: _mk_sp_thread_processor_set(
        !           613:        sf_object_t                     policy,
        !           614:        sched_thread_t          thread,
        !           615:        processor_set_t         processor_set)
        !           616: {
        !           617:        counter(c_mk_sp_thread_processor_set++);
        !           618: 
        !           619:        pset_add_thread(processor_set, thread);
        !           620: 
        !           621:        return(SF_SUCCESS);
        !           622: }
        !           623: 
        !           624: sf_return_t
        !           625: _mk_sp_thread_set(
        !           626:        sf_object_t                     policy,
        !           627:        sched_thread_t          thread,
        !           628:        sp_attributes_t         policy_attributes)
        !           629: {
        !           630:        mk_sp_info_t            sp_info;
        !           631:        mk_sp_attributes_t      attributes;
        !           632: 
        !           633:        counter(c_mk_sp_thread_set++);
        !           634: 
        !           635:        /* check that attributes are for this policy */
        !           636:        assert(policy_attributes->policy_id == policy->policy_id);
        !           637: 
        !           638:        attributes = (mk_sp_attributes_t)policy_attributes;
        !           639: 
        !           640:        /* get pointer to scheduling policy-specific data */
        !           641:        assert(thread->sp_info != SP_INFO_NULL);
        !           642:        sp_info = (mk_sp_info_t)thread->sp_info;
        !           643: 
        !           644:        counter(sp_info->c_mk_sp_thread_set++);
        !           645: 
        !           646:        /* update scheduling parameters */
        !           647:        sp_info->priority = attributes->priority;
        !           648:        sp_info->max_priority = attributes->max_priority;
        !           649:        sp_info->sched_data = attributes->sched_data;
        !           650:        sp_info->unconsumed_quantum = attributes->unconsumed_quantum;
        !           651: 
        !           652:        /*
        !           653:         * No check is needed against the pset limit.  If the task could raise
        !           654:         * its priority above the limit, then it must have had permisssion.
        !           655:         */
        !           656: 
        !           657:        /*
        !           658:         * Determine thread's state.  (It may be an "older" thread
        !           659:         * that has just been associated with this policy.)
        !           660:         */
        !           661:        if (thread->state & TH_WAIT) {
        !           662:            sp_info->th_state = MK_SP_BLOCKED;
        !           663:        }
        !           664: 
        !           665:        /* recompute priority */
        !           666:        sp_info->sched_stamp = sched_tick;
        !           667:        compute_priority(thread, TRUE);
        !           668: 
        !           669:        return(SF_SUCCESS);
        !           670: }
        !           671: 
        !           672: sf_return_t
        !           673: _mk_sp_thread_get(
        !           674:        sf_object_t                             policy,
        !           675:        sched_thread_t                  thread,
        !           676:        sp_attributes_t                 policy_attributes,
        !           677:        sp_attributes_size_t    size)
        !           678:        /*
        !           679:         * Assumes that thread is locked.
        !           680:         */
        !           681:        /***
        !           682:         *** ??? Does it assume `splsched()'?
        !           683:         ***/
        !           684: {
        !           685:        mk_sp_info_t            sp_info;
        !           686:        mk_sp_attributes_t      attributes;
        !           687: 
        !           688:        counter(c_mk_sp_thread_get++);
        !           689: 
        !           690:        /* check size of attribute structure provided by caller */
        !           691:        if (policy->sched_attributes_size > size)
        !           692:                return(SF_FAILURE);
        !           693: 
        !           694:        attributes = (mk_sp_attributes_t)policy_attributes;
        !           695: 
        !           696: 
        !           697:        /* get pointer to scheduling policy-specific data */
        !           698:        assert(thread->sp_info != SP_INFO_NULL);
        !           699:        sp_info = (mk_sp_info_t)thread->sp_info;
        !           700: 
        !           701:        counter(sp_info->c_mk_sp_thread_get++);
        !           702: 
        !           703:        /* copy scheduling attributes */
        !           704:        attributes->policy_id = policy->policy_id;
        !           705:        attributes->priority = sp_info->priority;
        !           706:        attributes->max_priority = sp_info->max_priority;
        !           707:        attributes->sched_data = sp_info->sched_data;
        !           708:        attributes->unconsumed_quantum = sp_info->unconsumed_quantum;
        !           709: 
        !           710:        return(SF_SUCCESS);
        !           711: }
        !           712: 
        !           713: int
        !           714: _mk_sp_db_print_sched_stats(
        !           715:        sf_object_t                     policy,
        !           716:        sched_thread_t          thread)
        !           717: {
        !           718:        mk_sp_info_t            sp_info;
        !           719: 
        !           720:        counter(c_mk_sp_db_print_sched_stats++);
        !           721: 
        !           722:        /* get pointer to scheduling policy-specific data */
        !           723:        assert(thread->sp_info != SP_INFO_NULL);
        !           724:        sp_info = (mk_sp_info_t)thread->sp_info;
        !           725: 
        !           726:        /* print one field -- `sched_pri' */
        !           727:        return (thread->sched_pri);
        !           728: }
        !           729: 
        !           730: /*
        !           731:  *     thread_priority:
        !           732:  *
        !           733:  *     Set priority (and possibly max priority) for thread.
        !           734:  */
        !           735: kern_return_t
        !           736: thread_priority(
        !           737:        thread_act_t            thr_act,
        !           738:        int                     priority,
        !           739:        boolean_t               set_max)
        !           740: {
        !           741:        kern_return_t           result;
        !           742:        thread_t                thread;
        !           743: 
        !           744:        if (thr_act == THR_ACT_NULL)
        !           745:                return (KERN_INVALID_ARGUMENT);
        !           746: 
        !           747:        thread = act_lock_thread(thr_act);
        !           748:        if (thread == THREAD_NULL || invalid_pri(priority)) {
        !           749:                act_unlock_thread(thr_act);
        !           750:                return (KERN_INVALID_ARGUMENT);
        !           751:        }
        !           752: 
        !           753:        result = thread_priority_locked(thread, priority, set_max);
        !           754:        act_unlock_thread(thr_act);
        !           755: 
        !           756:        return (result);
        !           757: }
        !           758: 
        !           759: /*
        !           760:  *     thread_priority_locked:
        !           761:  *
        !           762:  *     Kernel-internal work function for thread_priority().  Called
        !           763:  *     with thread "properly locked" to ensure synchrony with RPC
        !           764:  *     (see act_lock_thread()).
        !           765:  */
        !           766: kern_return_t
        !           767: thread_priority_locked(
        !           768:        thread_t                thread,
        !           769:        int                     priority,
        !           770:        boolean_t               set_max)
        !           771: {
        !           772:        kern_return_t           result = KERN_SUCCESS;
        !           773:        mk_sp_info_t            sched_info;
        !           774:        spl_t                   s;
        !           775: 
        !           776:        s = splsched();
        !           777:        thread_lock(thread);
        !           778: 
        !           779:        /* get pointer to scheduling policy-specific data */
        !           780:        assert(thread->sp_info != SP_INFO_NULL);
        !           781:        sched_info = (mk_sp_info_t)thread->sp_info;
        !           782: 
        !           783:        /*
        !           784:         *      Check for violation of max priority
        !           785:         */
        !           786:        if (priority > sched_info->max_priority)
        !           787:                result = KERN_FAILURE;
        !           788:        else {
        !           789:                /*
        !           790:                 *      Set priorities.  If a depression is in progress,
        !           791:                 *      change the priority to restore.
        !           792:                 */
        !           793:                if (sched_info->depress_priority >= 0) {
        !           794:                        sched_info->depress_priority = priority;
        !           795:                }
        !           796:                else {
        !           797:                        sched_info->priority = priority;
        !           798:                        compute_priority(thread, TRUE);
        !           799: 
        !           800:                        /*
        !           801:                         * If the current thread has changed its
        !           802:                         * priority let the ast code decide whether
        !           803:                         * a different thread should run.
        !           804:                         */
        !           805:                        if (thread == current_thread())
        !           806:                                ast_on(AST_BLOCK);
        !           807:                }
        !           808: 
        !           809:                if (set_max)
        !           810:                        sched_info->max_priority = priority;
        !           811:        }
        !           812: 
        !           813:        thread_unlock(thread);
        !           814:        splx(s);
        !           815: 
        !           816:        return(result);
        !           817: }
        !           818: 
        !           819: /*
        !           820:  *     thread_set_own_priority:
        !           821:  *
        !           822:  *     Internal use only; sets the priority of the calling thread.
        !           823:  *     Will adjust max_priority if necessary.
        !           824:  */
        !           825: void
        !           826: thread_set_own_priority(
        !           827:        int             priority)
        !           828: {
        !           829:        thread_t        thread = current_thread();
        !           830:        mk_sp_info_t    sched_info;
        !           831:        spl_t           s;
        !           832: 
        !           833:        s = splsched();
        !           834:        thread_lock(thread);
        !           835: 
        !           836:        /* get pointer to scheduling policy-specific data */
        !           837:        assert(thread->sp_info != SP_INFO_NULL);
        !           838:        sched_info = (mk_sp_info_t)thread->sp_info;
        !           839: 
        !           840:        if (priority > sched_info->max_priority)
        !           841:                sched_info->max_priority = priority;
        !           842:        sched_info->priority = priority;
        !           843:        compute_priority(thread, TRUE);
        !           844: 
        !           845:        thread_unlock(thread);
        !           846:        splx(s);
        !           847: }
        !           848: 
        !           849: /*
        !           850:  *     thread_max_priority:
        !           851:  *
        !           852:  *     Reset the max priority for a thread.
        !           853:  */
        !           854: kern_return_t
        !           855: thread_max_priority(
        !           856:        thread_act_t    thr_act,
        !           857:        processor_set_t pset,
        !           858:        int             max_priority)
        !           859: {
        !           860:        thread_t        thread;
        !           861:        kern_return_t   result = KERN_SUCCESS;
        !           862: 
        !           863:        if (thr_act == THR_ACT_NULL)
        !           864:                return(KERN_INVALID_ARGUMENT);
        !           865: 
        !           866:        thread = act_lock_thread(thr_act);
        !           867:        if (thread == THREAD_NULL || pset == PROCESSOR_SET_NULL ||
        !           868:                        invalid_pri(max_priority)) {
        !           869:                act_unlock_thread(thr_act);
        !           870:                return(KERN_INVALID_ARGUMENT);
        !           871:        }
        !           872: 
        !           873:        result = thread_max_priority_locked(thread, pset, max_priority);
        !           874:        act_unlock_thread(thr_act);
        !           875: 
        !           876:        return (result);
        !           877: }
        !           878: 
        !           879: /*
        !           880:  *     thread_max_priority_locked:
        !           881:  *
        !           882:  *     Work function for thread_max_priority.
        !           883:  *
        !           884:  *     Called with all RPC-related locks held for thread (see
        !           885:  *     act_lock_thread()).
        !           886:  */
        !           887: kern_return_t
        !           888: thread_max_priority_locked(
        !           889:        thread_t        thread,
        !           890:        processor_set_t pset,
        !           891:        int             max_priority)
        !           892: {
        !           893:        kern_return_t   result = KERN_SUCCESS;
        !           894:        mk_sp_info_t    sched_info;
        !           895:        spl_t           s;
        !           896: 
        !           897:        s = splsched();
        !           898:        thread_lock(thread);
        !           899: 
        !           900:        /* get pointer to scheduling policy-specific data */
        !           901:        assert(thread->sp_info != SP_INFO_NULL);
        !           902:        sched_info = (mk_sp_info_t)thread->sp_info;
        !           903: 
        !           904: #if    MACH_HOST
        !           905:        /*
        !           906:         *      Check for wrong processor set.
        !           907:         */
        !           908:        if (pset != thread->processor_set)
        !           909:                result = KERN_FAILURE;
        !           910:        else {
        !           911: #endif /* MACH_HOST */
        !           912:                sched_info->max_priority = max_priority;
        !           913: 
        !           914:                /*
        !           915:                 *      Reset priority if it violates new max priority
        !           916:                 */
        !           917:                if (max_priority < sched_info->priority) {
        !           918:                        sched_info->priority = max_priority;
        !           919: 
        !           920:                        compute_priority(thread, TRUE);
        !           921:                }
        !           922:                else if (sched_info->depress_priority >= 0 &&
        !           923:                                max_priority < sched_info->depress_priority)
        !           924:                        sched_info->depress_priority = max_priority;
        !           925: #if    MACH_HOST
        !           926:        }
        !           927: #endif /* MACH_HOST */
        !           928: 
        !           929:        thread_unlock(thread);
        !           930:        splx(s);
        !           931: 
        !           932:        return(result);
        !           933: }
        !           934: 
        !           935: /*
        !           936:  *     thread_policy_common:
        !           937:  *
        !           938:  *     Set scheduling policy for thread. If pset == PROCESSOR_SET_NULL,
        !           939:  *     policy will be checked to make sure it is enabled.
        !           940:  */
        !           941: kern_return_t
        !           942: thread_policy_common(
        !           943:        thread_t        thread,
        !           944:        int             policy,
        !           945:        int             data,
        !           946:        processor_set_t pset)
        !           947: {
        !           948:        kern_return_t   result = KERN_SUCCESS;
        !           949:        mk_sp_info_t    sched_info;
        !           950:        register int    temp;
        !           951:        spl_t           s;
        !           952: 
        !           953:        if (thread == THREAD_NULL || invalid_policy(policy))
        !           954:                return(KERN_INVALID_ARGUMENT);
        !           955: 
        !           956:        s = splsched();
        !           957:        thread_lock(thread);
        !           958: 
        !           959:        /* get pointer to scheduling policy-specific data */
        !           960:        assert(thread->sp_info != SP_INFO_NULL);
        !           961:        sched_info = (mk_sp_info_t)thread->sp_info;
        !           962: 
        !           963:        /*
        !           964:         *      Check if changing policy.
        !           965:         */
        !           966:        if (policy == thread->policy) {
        !           967:            /*
        !           968:             *  Just changing data.  This is meaningless for
        !           969:             *  timeshareing, quantum for fixed priority (but
        !           970:             *  has no effect until current quantum runs out).
        !           971:             */
        !           972:            if (policy == POLICY_FIFO || policy == POLICY_RR) {
        !           973:                temp = data * 1000;
        !           974:                if (temp % tick)
        !           975:                    temp += tick;
        !           976:                sched_info->sched_data = temp/tick;
        !           977:                sched_info->unconsumed_quantum = temp/tick;
        !           978:            }
        !           979:        }
        !           980:        else {
        !           981:            /*
        !           982:             *  Changing policy.  Check if new policy is allowed.
        !           983:             */
        !           984:            if (pset == PROCESSOR_SET_NULL && 
        !           985:                        (thread->processor_set->policies & policy) == 0) {
        !           986:                result = KERN_FAILURE;
        !           987:            }
        !           988:            else {
        !           989:                if (pset != thread->processor_set) {
        !           990:                    result = KERN_FAILURE;
        !           991:                }
        !           992:                else {
        !           993:                    /*
        !           994:                     *  Changing policy.  Save data and calculate new
        !           995:                     *  priority.
        !           996:                     */
        !           997:                    thread->policy = policy;
        !           998:                    sched_info->policy = policy;
        !           999:                    if (policy == POLICY_FIFO || policy == POLICY_RR) {
        !          1000:                        temp = data * 1000;
        !          1001:                        if (temp % tick)
        !          1002:                            temp += tick;
        !          1003:                        sched_info->sched_data = temp/tick;
        !          1004:                        sched_info->unconsumed_quantum = temp/tick;
        !          1005:                    }
        !          1006:                    compute_priority(thread, TRUE);
        !          1007:                }
        !          1008:            }
        !          1009:        }
        !          1010: 
        !          1011:        thread_unlock(thread);
        !          1012:        splx(s);
        !          1013: 
        !          1014:        return(result);
        !          1015: }
        !          1016: 
        !          1017: /*
        !          1018:  *     thread_set_policy
        !          1019:  *
        !          1020:  *     Set scheduling policy and parameters, both base and limit, for 
        !          1021:  *     the given thread. Policy can be any policy implemented by the
        !          1022:  *     processor set, whether enabled or not. 
        !          1023:  */
        !          1024: kern_return_t
        !          1025: thread_set_policy(
        !          1026:        thread_act_t                    thr_act,
        !          1027:        processor_set_t                 pset,
        !          1028:        policy_t                        policy,
        !          1029:        policy_base_t                   base,
        !          1030:        mach_msg_type_number_t          base_count,
        !          1031:        policy_limit_t                  limit,
        !          1032:        mach_msg_type_number_t          limit_count)
        !          1033: {
        !          1034:        thread_t                        thread;
        !          1035:        int                             max, bas, dat;
        !          1036:        kern_return_t                   result = KERN_SUCCESS;
        !          1037: 
        !          1038:        if (thr_act == THR_ACT_NULL || pset == PROCESSOR_SET_NULL)
        !          1039:                return (KERN_INVALID_ARGUMENT);
        !          1040: 
        !          1041:        thread = act_lock_thread(thr_act);
        !          1042:        if (thread == THREAD_NULL) {
        !          1043:                act_unlock_thread(thr_act);
        !          1044:                return(KERN_INVALID_ARGUMENT);
        !          1045:        }
        !          1046: 
        !          1047:        if (pset != thread->processor_set) {
        !          1048:                act_unlock_thread(thr_act);
        !          1049:                return(KERN_FAILURE);
        !          1050:        }
        !          1051: 
        !          1052:        switch (policy) {
        !          1053:        case POLICY_RR:
        !          1054:        {
        !          1055:                 policy_rr_base_t rr_base = (policy_rr_base_t) base;
        !          1056:                 policy_rr_limit_t rr_limit = (policy_rr_limit_t) limit;
        !          1057: 
        !          1058:                 if (base_count != POLICY_RR_BASE_COUNT ||
        !          1059:                     limit_count != POLICY_RR_LIMIT_COUNT) {
        !          1060:                         result = KERN_INVALID_ARGUMENT;
        !          1061:                         break;
        !          1062:                 }
        !          1063:                dat = rr_base->quantum;
        !          1064:                bas = rr_base->base_priority;
        !          1065:                max = rr_limit->max_priority;
        !          1066:                if (invalid_pri(bas) || invalid_pri(max)) {
        !          1067:                        result = KERN_INVALID_ARGUMENT;
        !          1068:                        break;
        !          1069:                }
        !          1070:                break;
        !          1071:        }
        !          1072: 
        !          1073:        case POLICY_FIFO:
        !          1074:        {
        !          1075:                 policy_fifo_base_t fifo_base = (policy_fifo_base_t) base;
        !          1076:                 policy_fifo_limit_t fifo_limit = (policy_fifo_limit_t) limit;
        !          1077: 
        !          1078:                 if (base_count != POLICY_FIFO_BASE_COUNT ||
        !          1079:                     limit_count != POLICY_FIFO_LIMIT_COUNT) {
        !          1080:                         result = KERN_INVALID_ARGUMENT;
        !          1081:                         break;
        !          1082:                 }
        !          1083:                dat = 0;
        !          1084:                bas = fifo_base->base_priority;
        !          1085:                max = fifo_limit->max_priority;
        !          1086:                if (invalid_pri(bas) || invalid_pri(max)) {
        !          1087:                        result = KERN_INVALID_ARGUMENT;
        !          1088:                         break;
        !          1089:                 }
        !          1090:                 break;
        !          1091:        }
        !          1092: 
        !          1093:        case POLICY_TIMESHARE:
        !          1094:         {
        !          1095:                 policy_timeshare_base_t ts_base =
        !          1096:                                         (policy_timeshare_base_t) base;
        !          1097:                 policy_timeshare_limit_t ts_limit =
        !          1098:                                         (policy_timeshare_limit_t) limit;
        !          1099: 
        !          1100:                 if (base_count != POLICY_TIMESHARE_BASE_COUNT ||
        !          1101:                     limit_count != POLICY_TIMESHARE_LIMIT_COUNT) {
        !          1102:                         result = KERN_INVALID_ARGUMENT;
        !          1103:                         break;
        !          1104:                 }
        !          1105:                dat = 0;
        !          1106:                bas = ts_base->base_priority;
        !          1107:                max = ts_limit->max_priority;
        !          1108:                if (invalid_pri(bas) || invalid_pri(max)) {
        !          1109:                        result = KERN_INVALID_ARGUMENT;
        !          1110:                         break;
        !          1111:                 }
        !          1112:                 break;
        !          1113:        }
        !          1114: 
        !          1115:        default:
        !          1116:                result = KERN_INVALID_POLICY;
        !          1117:        }
        !          1118: 
        !          1119:        if (result != KERN_SUCCESS) {
        !          1120:                act_unlock_thread(thr_act);
        !          1121:                return(result);
        !          1122:        }
        !          1123: 
        !          1124:        /*      
        !          1125:         *      We've already checked the inputs for thread_max_priority,
        !          1126:         *      so it's safe to ignore the return value.
        !          1127:         */
        !          1128:        (void) thread_max_priority_locked(thread, pset, max);   
        !          1129:        result = thread_priority_locked(thread, bas, FALSE);
        !          1130:        if (result == KERN_SUCCESS)
        !          1131:                result = thread_policy_common(thread, policy, dat, pset);
        !          1132:        act_unlock_thread(thr_act);
        !          1133:        return(result);
        !          1134: }
        !          1135: 
        !          1136: 
        !          1137: /*
        !          1138:  *     thread_policy
        !          1139:  *
        !          1140:  *     Set scheduling policy and parameters, both base and limit, for
        !          1141:  *     the given thread. Policy must be a policy which is enabled for the
        !          1142:  *     processor set. Change contained threads if requested. 
        !          1143:  */
        !          1144: kern_return_t
        !          1145: thread_policy(
        !          1146:        thread_act_t                    thr_act,
        !          1147:         policy_t                       policy,
        !          1148:         policy_base_t                  base,
        !          1149:        mach_msg_type_number_t          count,
        !          1150:         boolean_t                      set_limit)
        !          1151: {
        !          1152:        thread_t                        thread;
        !          1153:         processor_set_t                        pset;
        !          1154:        mk_sp_info_t                    sched_info;
        !          1155:         kern_return_t                  result = KERN_SUCCESS;
        !          1156:        policy_limit_t                  limit;
        !          1157:         policy_rr_limit_data_t         rr_limit;
        !          1158:         policy_fifo_limit_data_t       fifo_limit;
        !          1159:         policy_timeshare_limit_data_t  ts_limit;
        !          1160:        int                             limcount;
        !          1161:        
        !          1162:        if (thr_act == THR_ACT_NULL)
        !          1163:                return (KERN_INVALID_ARGUMENT);
        !          1164: 
        !          1165:        thread = act_lock_thread(thr_act);
        !          1166:        pset = thread->processor_set;
        !          1167:        if (thread == THREAD_NULL || pset == PROCESSOR_SET_NULL) {
        !          1168:                act_unlock_thread(thr_act);
        !          1169:                return(KERN_INVALID_ARGUMENT);
        !          1170:        }
        !          1171: 
        !          1172:        if (invalid_policy(policy) || (pset->policies & policy) == 0) {
        !          1173:                act_unlock_thread(thr_act);
        !          1174:                return(KERN_INVALID_POLICY);
        !          1175:        }
        !          1176: 
        !          1177:        /* get pointer to scheduling policy-specific data */
        !          1178:        assert(thread->sp_info != SP_INFO_NULL);
        !          1179:        sched_info = (mk_sp_info_t)thread->sp_info;
        !          1180: 
        !          1181:        if (set_limit) {
        !          1182:                /*
        !          1183:                 *      Set scheduling limits to base priority.
        !          1184:                 */
        !          1185:                switch (policy) {
        !          1186:                case POLICY_RR:
        !          1187:                {
        !          1188:                         policy_rr_base_t rr_base;
        !          1189: 
        !          1190:                         if (count != POLICY_RR_BASE_COUNT) {
        !          1191:                                 result = KERN_INVALID_ARGUMENT;
        !          1192:                                break;
        !          1193:                        }
        !          1194:                         limcount = POLICY_RR_LIMIT_COUNT;
        !          1195:                         rr_base = (policy_rr_base_t) base;
        !          1196:                         rr_limit.max_priority = rr_base->base_priority;
        !          1197:                         limit = (policy_limit_t) &rr_limit;
        !          1198:                        break;
        !          1199:                }
        !          1200: 
        !          1201:                case POLICY_FIFO:
        !          1202:                 {
        !          1203:                                policy_fifo_base_t fifo_base;
        !          1204: 
        !          1205:                                if (count != POLICY_FIFO_BASE_COUNT) {
        !          1206:                                 result = KERN_INVALID_ARGUMENT;
        !          1207:                                break;
        !          1208:                        }
        !          1209:                                limcount = POLICY_FIFO_LIMIT_COUNT;
        !          1210:                         fifo_base = (policy_fifo_base_t) base;
        !          1211:                         fifo_limit.max_priority = fifo_base->base_priority;
        !          1212:                         limit = (policy_limit_t) &fifo_limit;
        !          1213:                        break;
        !          1214:                }
        !          1215: 
        !          1216:                case POLICY_TIMESHARE:
        !          1217:                 {
        !          1218:                         policy_timeshare_base_t ts_base;
        !          1219: 
        !          1220:                         if (count != POLICY_TIMESHARE_BASE_COUNT) {
        !          1221:                                 result = KERN_INVALID_ARGUMENT;
        !          1222:                                break;
        !          1223:                        }
        !          1224:                         limcount = POLICY_TIMESHARE_LIMIT_COUNT;
        !          1225:                         ts_base = (policy_timeshare_base_t) base;
        !          1226:                         ts_limit.max_priority = ts_base->base_priority;
        !          1227:                         limit = (policy_limit_t) &ts_limit;
        !          1228:                        break;
        !          1229:                }
        !          1230: 
        !          1231:                default:
        !          1232:                        result = KERN_INVALID_POLICY;
        !          1233:                        break;
        !          1234:                }
        !          1235: 
        !          1236:        } else {
        !          1237:                /*
        !          1238:                 *      Use current scheduling limits. Ensure that the
        !          1239:                 *      new base priority will not exceed current limits.
        !          1240:                 */
        !          1241:                 switch (policy) {
        !          1242:                 case POLICY_RR:
        !          1243:                 {
        !          1244:                         policy_rr_base_t rr_base;
        !          1245: 
        !          1246:                         if (count != POLICY_RR_BASE_COUNT) {
        !          1247:                                 result = KERN_INVALID_ARGUMENT;
        !          1248:                                break;
        !          1249:                        }
        !          1250:                         limcount = POLICY_RR_LIMIT_COUNT;
        !          1251:                         rr_base = (policy_rr_base_t) base;
        !          1252:                        if (rr_base->base_priority >
        !          1253:                                        sched_info->max_priority) {
        !          1254:                                result = KERN_POLICY_LIMIT;
        !          1255:                                break;
        !          1256:                        }
        !          1257:                         rr_limit.max_priority = sched_info->max_priority;
        !          1258:                         limit = (policy_limit_t) &rr_limit;
        !          1259:                         break;
        !          1260:                }
        !          1261: 
        !          1262:                 case POLICY_FIFO:
        !          1263:                 {
        !          1264:                         policy_fifo_base_t fifo_base;
        !          1265: 
        !          1266:                         if (count != POLICY_FIFO_BASE_COUNT) {
        !          1267:                                 result = KERN_INVALID_ARGUMENT;
        !          1268:                                break;
        !          1269:                        }
        !          1270:                         limcount = POLICY_FIFO_LIMIT_COUNT;
        !          1271:                         fifo_base = (policy_fifo_base_t) base;
        !          1272:                        if (fifo_base->base_priority >
        !          1273:                                        sched_info->max_priority) {
        !          1274:                                result = KERN_POLICY_LIMIT;
        !          1275:                                break;
        !          1276:                        }
        !          1277:                         fifo_limit.max_priority = sched_info->max_priority;
        !          1278:                         limit = (policy_limit_t) &fifo_limit;
        !          1279:                         break;
        !          1280:                }
        !          1281: 
        !          1282:                 case POLICY_TIMESHARE:
        !          1283:                 {
        !          1284:                         policy_timeshare_base_t ts_base;
        !          1285: 
        !          1286:                         if (count != POLICY_TIMESHARE_BASE_COUNT) {
        !          1287:                                 result = KERN_INVALID_ARGUMENT;
        !          1288:                                break;
        !          1289:                        }
        !          1290:                         limcount = POLICY_TIMESHARE_LIMIT_COUNT;
        !          1291:                         ts_base = (policy_timeshare_base_t) base;
        !          1292:                        if (ts_base->base_priority >
        !          1293:                                        sched_info->max_priority) {
        !          1294:                                result = KERN_POLICY_LIMIT;
        !          1295:                                break;
        !          1296:                        }
        !          1297:                         ts_limit.max_priority = sched_info->max_priority;
        !          1298:                         limit = (policy_limit_t) &ts_limit;
        !          1299:                         break;
        !          1300:                }
        !          1301: 
        !          1302:                 default:
        !          1303:                        result = KERN_INVALID_POLICY;
        !          1304:                        break;
        !          1305:                 }
        !          1306: 
        !          1307:        }
        !          1308: 
        !          1309:        act_unlock_thread(thr_act);
        !          1310: 
        !          1311:        if (result == KERN_SUCCESS)
        !          1312:            result = thread_set_policy(thr_act, pset,
        !          1313:                                         policy, base, count, limit, limcount);
        !          1314: 
        !          1315:        return(result);
        !          1316: }
        !          1317: 
        !          1318: 
        !          1319: /*
        !          1320:  *     Define shifts for simulating (5/8)**n
        !          1321:  */
        !          1322: 
        !          1323: shift_data_t   wait_shift[32] = {
        !          1324:        {1,1},{1,3},{1,-3},{2,-7},{3,5},{3,-5},{4,-8},{5,7},
        !          1325:        {5,-7},{6,-10},{7,10},{7,-9},{8,-11},{9,12},{9,-11},{10,-13},
        !          1326:        {11,14},{11,-13},{12,-15},{13,17},{13,-15},{14,-17},{15,19},{16,18},
        !          1327:        {16,-19},{17,22},{18,20},{18,-20},{19,26},{20,22},{20,-22},{21,-27}};
        !          1328: 
        !          1329: /*
        !          1330:  *     do_priority_computation:
        !          1331:  *
        !          1332:  *     Calculate new priority for thread based on its base priority plus
        !          1333:  *     accumulated usage.  PRI_SHIFT and PRI_SHIFT_2 convert from
        !          1334:  *     usage to priorities.  SCHED_SHIFT converts for the scaling
        !          1335:  *     of the sched_usage field by SCHED_SCALE.  This scaling comes
        !          1336:  *     from the multiplication by sched_load (thread_timer_delta)
        !          1337:  *     in sched.h.  sched_load is calculated as a scaled overload
        !          1338:  *     factor in compute_mach_factor (mach_factor.c).
        !          1339:  */
        !          1340: #ifdef PRI_SHIFT_2
        !          1341: #if    PRI_SHIFT_2 > 0
        !          1342: #define do_priority_computation(sp_info, pri)                                          \
        !          1343:        MACRO_BEGIN                                                                                                             \
        !          1344:        (pri) = (sp_info)->priority             /* start with base priority */  \
        !          1345:            - ((sp_info)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT))             \
        !          1346:            - ((sp_info)->sched_usage >> (PRI_SHIFT_2 + SCHED_SHIFT));  \
        !          1347:        if ((pri) < lpri) (pri) = lpri;                                                                 \
        !          1348:        (pri) = convert_pri[(pri)];                                                                             \
        !          1349:        MACRO_END
        !          1350: #else  /* PRI_SHIFT_2 */
        !          1351: #define do_priority_computation(sp_info, pri)                                          \
        !          1352:        MACRO_BEGIN                                                                                                             \
        !          1353:        (pri) = (sp_info)->priority             /* start with base priority */  \
        !          1354:            - ((sp_info)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT))             \
        !          1355:            + ((sp_info)->sched_usage >> (SCHED_SHIFT - PRI_SHIFT_2));  \
        !          1356:        if ((pri) < lpri) (pri) = lpri;                                                                 \
        !          1357:        (pri) = convert_pri[(pri)];                                                                             \
        !          1358:        MACRO_END
        !          1359: #endif /* PRI_SHIFT_2 */
        !          1360: #else  /* defined(PRI_SHIFT_2) */
        !          1361: #define do_priority_computation(sp_info, pri)                                          \
        !          1362:        MACRO_BEGIN                                                                                                             \
        !          1363:        (pri) = (sp_info)->priority             /* start with base priority */  \
        !          1364:            - ((sp_info)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT));    \
        !          1365:        if ((pri) < lpri) (pri) = lpri;                                                                 \
        !          1366:        (pri) = convert_pri[(pri)];                                                                             \
        !          1367:        MACRO_END
        !          1368: #endif /* defined(PRI_SHIFT_2) */
        !          1369: 
        !          1370: /*
        !          1371:  *     compute_priority:
        !          1372:  *
        !          1373:  *     Compute the effective priority of the specified thread.
        !          1374:  *     The effective priority computation is as follows:
        !          1375:  *
        !          1376:  *     Take the base priority for this thread and add
        !          1377:  *     to it an increment derived from its cpu_usage.
        !          1378:  *
        !          1379:  *     The thread *must* be locked by the caller. 
        !          1380:  */
        !          1381: 
        !          1382: void
        !          1383: compute_priority(
        !          1384:        register thread_t       thread,
        !          1385:        boolean_t                       resched)
        !          1386: {
        !          1387:        mk_sp_info_t            sp_info = (mk_sp_info_t)thread->sp_info;
        !          1388:        register int            pri;
        !          1389: 
        !          1390:        /* make sure policy-specific data are present */
        !          1391:        assert(sp_info != SP_INFO_NULL);
        !          1392: 
        !          1393:        if (thread->policy == POLICY_TIMESHARE) {
        !          1394:            do_priority_computation(sp_info, pri);
        !          1395:            if (sp_info->depress_priority < 0)
        !          1396:                        set_pri(thread, pri, resched);
        !          1397:            else
        !          1398:                        sp_info->depress_priority = pri;
        !          1399:        }
        !          1400:        else
        !          1401:            set_pri(thread, sp_info->priority, resched);
        !          1402: }
        !          1403: 
        !          1404: /*
        !          1405:  *     compute_my_priority:
        !          1406:  *
        !          1407:  *     Version of compute priority for current thread or thread
        !          1408:  *     being manipulated by scheduler (going on or off a runq).
        !          1409:  *     Only used for priority updates.  Policy or priority changes
        !          1410:  *     must call compute_priority above.  Caller must have thread
        !          1411:  *     locked and know it is timesharing and not depressed.
        !          1412:  */
        !          1413: 
        !          1414: void
        !          1415: compute_my_priority(
        !          1416:        register thread_t       thread)
        !          1417: {
        !          1418:        mk_sp_info_t    sp_info = (mk_sp_info_t)thread->sp_info;
        !          1419:        register int    temp_pri;
        !          1420: 
        !          1421:        /* make sure policy-specific data are present */
        !          1422:        assert(thread->sp_info != SP_INFO_NULL);
        !          1423: 
        !          1424:        do_priority_computation(sp_info,temp_pri);
        !          1425:        assert(thread->runq == RUN_QUEUE_NULL);
        !          1426:        thread->sched_pri = temp_pri;
        !          1427: }
        !          1428: 
        !          1429: struct mk_sp_usage {
        !          1430:        natural_t       cpu_delta, sched_delta;
        !          1431:        natural_t       sched_tick, ticks;
        !          1432:        natural_t       cpu_usage, sched_usage,
        !          1433:                                aged_cpu, aged_sched;
        !          1434:        thread_t        thread;
        !          1435: } idled_info, loaded_info;
        !          1436: 
        !          1437: /*
        !          1438:  *     update_priority
        !          1439:  *
        !          1440:  *     Cause the priority computation of a thread that has been 
        !          1441:  *     sleeping or suspended to "catch up" with the system.  Thread
        !          1442:  *     *MUST* be locked by caller.  If thread is running, then this
        !          1443:  *     can only be called by the thread on itself.
        !          1444:  */
        !          1445: void
        !          1446: update_priority(
        !          1447:        register thread_t               thread)
        !          1448: {
        !          1449:        mk_sp_info_t                    sp_info = (mk_sp_info_t)thread->sp_info;
        !          1450:        register unsigned int   ticks;
        !          1451:        register shift_t                shiftp;
        !          1452: 
        !          1453:        /* make sure policy-specific data are present */
        !          1454:        assert(sp_info != SP_INFO_NULL);
        !          1455: 
        !          1456:        ticks = sched_tick - sp_info->sched_stamp;
        !          1457:        assert(ticks != 0);
        !          1458: 
        !          1459:        /*
        !          1460:         *      If asleep for more than 30 seconds forget all
        !          1461:         *      cpu_usage, else catch up on missed aging.
        !          1462:         *      5/8 ** n is approximated by the two shifts
        !          1463:         *      in the wait_shift array.
        !          1464:         */
        !          1465:        sp_info->sched_stamp += ticks;
        !          1466:        thread_timer_delta(thread);
        !          1467:        if (ticks >  30) {
        !          1468:                sp_info->cpu_usage = 0;
        !          1469:                sp_info->sched_usage = 0;
        !          1470:        }
        !          1471:        else {
        !          1472:                struct mk_sp_usage *sp_usage;
        !          1473: 
        !          1474:                sp_info->cpu_usage += thread->cpu_delta;
        !          1475:                sp_info->sched_usage += thread->sched_delta;
        !          1476: 
        !          1477:                if (thread->state & TH_IDLE)
        !          1478:                        sp_usage = &idled_info;
        !          1479:                else
        !          1480:                if (thread == loaded_info.thread)
        !          1481:                        sp_usage = &loaded_info;
        !          1482:                else
        !          1483:                        sp_usage = NULL;
        !          1484: 
        !          1485:                if (sp_usage != NULL) {
        !          1486:                        sp_usage->cpu_delta = thread->cpu_delta;
        !          1487:                        sp_usage->sched_delta = thread->sched_delta;
        !          1488:                        sp_usage->sched_tick = sp_info->sched_stamp;
        !          1489:                        sp_usage->ticks = ticks;
        !          1490:                        sp_usage->cpu_usage = sp_info->cpu_usage;
        !          1491:                        sp_usage->sched_usage = sp_info->sched_usage;
        !          1492:                        sp_usage->thread = thread;
        !          1493:                }
        !          1494: 
        !          1495:                shiftp = &wait_shift[ticks];
        !          1496:                if (shiftp->shift2 > 0) {
        !          1497:                    sp_info->cpu_usage =
        !          1498:                                                (sp_info->cpu_usage >> shiftp->shift1) +
        !          1499:                                                (sp_info->cpu_usage >> shiftp->shift2);
        !          1500:                    sp_info->sched_usage =
        !          1501:                                                (sp_info->sched_usage >> shiftp->shift1) +
        !          1502:                                                (sp_info->sched_usage >> shiftp->shift2);
        !          1503:                }
        !          1504:                else {
        !          1505:                    sp_info->cpu_usage =
        !          1506:                                                (sp_info->cpu_usage >> shiftp->shift1) -
        !          1507:                                                (sp_info->cpu_usage >> -(shiftp->shift2));
        !          1508:                    sp_info->sched_usage =
        !          1509:                                                (sp_info->sched_usage >> shiftp->shift1) -
        !          1510:                                                (sp_info->sched_usage >> -(shiftp->shift2));
        !          1511:                }
        !          1512: 
        !          1513:                if (sp_usage != NULL) {
        !          1514:                        sp_usage->aged_cpu = sp_info->cpu_usage;
        !          1515:                        sp_usage->aged_sched = sp_info->sched_usage;
        !          1516:                }
        !          1517:        }
        !          1518:        thread->cpu_delta = 0;
        !          1519:        thread->sched_delta = 0;
        !          1520: 
        !          1521:        /*
        !          1522:         *      Recompute priority if appropriate.
        !          1523:         */
        !          1524:        if (    thread->policy == POLICY_TIMESHARE              &&
        !          1525:                        sp_info->depress_priority < 0                   ) {
        !          1526:                register int            new_pri;
        !          1527:                run_queue_t                     runq;
        !          1528: 
        !          1529:                do_priority_computation(sp_info, new_pri);
        !          1530:                runq = rem_runq(thread);
        !          1531:                thread->sched_pri = new_pri;
        !          1532:                if (runq != RUN_QUEUE_NULL)
        !          1533:                        thread_setrun(thread, TRUE, TAIL_Q);
        !          1534:        }
        !          1535: }
        !          1536: 
        !          1537: /*
        !          1538:  *     `mk_sp_swtch_pri()' attempts to context switch (logic in
        !          1539:  *     thread_block no-ops the context switch if nothing would happen).
        !          1540:  *     A boolean is returned that indicates whether there is anything
        !          1541:  *     else runnable.
        !          1542:  *
        !          1543:  *     This boolean can be used by a thread waiting on a
        !          1544:  *     lock or condition:  If FALSE is returned, the thread is justified
        !          1545:  *     in becoming a resource hog by continuing to spin because there's
        !          1546:  *     nothing else useful that the processor could do.  If TRUE is
        !          1547:  *     returned, the thread should make one more check on the
        !          1548:  *     lock and then be a good citizen and really suspend.
        !          1549:  */
        !          1550: 
        !          1551: void
        !          1552: _mk_sp_swtch_pri(
        !          1553:        sf_object_t                     policy,
        !          1554:        int                                     pri)
        !          1555: {
        !          1556:        register thread_t       self = current_thread();
        !          1557: 
        !          1558: #ifdef lint
        !          1559:        pri++;
        !          1560: #endif /* lint */
        !          1561: 
        !          1562:        counter(c_mk_sp_swtch_pri++);
        !          1563:        /*
        !          1564:         *      XXX need to think about depression duration.
        !          1565:         *      XXX currently using min quantum.
        !          1566:         */
        !          1567:        _mk_sp_thread_depress_priority(policy, min_quantum_ms);
        !          1568: 
        !          1569:        counter(c_swtch_pri_block++);
        !          1570:        thread_block((void (*)(void)) 0);
        !          1571: 
        !          1572:        _mk_sp_thread_depress_abort(policy, self);
        !          1573: }
        !          1574: 
        !          1575: /*
        !          1576:  *     thread_switch:
        !          1577:  *
        !          1578:  *     Context switch.  User may supply thread hint.
        !          1579:  *
        !          1580:  *     Fixed priority threads that call this get what they asked for
        !          1581:  *     even if that violates priority order.
        !          1582:  */
        !          1583: kern_return_t
        !          1584: _mk_sp_thread_switch(
        !          1585:        sf_object_t                             policy,
        !          1586:        thread_act_t                    hint_act,
        !          1587:        int                                             option,
        !          1588:        mach_msg_timeout_t              option_time)
        !          1589: {
        !          1590:     register thread_t          self = current_thread();
        !          1591:     register processor_t       myprocessor;
        !          1592:     mk_sp_info_t                       sp_info;
        !          1593:        int                                             s;
        !          1594: 
        !          1595:     counter(c_mk_sp_thread_switch++);
        !          1596: 
        !          1597:     /*
        !          1598:      * Process option.
        !          1599:      */
        !          1600:     switch (option) {
        !          1601: 
        !          1602:        case SWITCH_OPTION_NONE:
        !          1603:            /*
        !          1604:             *  Nothing to do.
        !          1605:             */
        !          1606:            break;
        !          1607: 
        !          1608:        case SWITCH_OPTION_DEPRESS:
        !          1609:            /*
        !          1610:             *  Depress priority for a given time.
        !          1611:             */
        !          1612:            _mk_sp_thread_depress_priority(policy, option_time);
        !          1613:            break;
        !          1614: 
        !          1615:        case SWITCH_OPTION_WAIT:
        !          1616:            assert_wait_timeout(option_time, THREAD_ABORTSAFE);
        !          1617:            break;
        !          1618: 
        !          1619:        default:
        !          1620:            return (KERN_INVALID_ARGUMENT);
        !          1621:     }
        !          1622:     
        !          1623:     /*
        !          1624:      * Check and use thr_act hint if appropriate.  It is not
        !          1625:      *  appropriate to give a hint that shares the current shuttle.
        !          1626:      *
        !          1627:      *  JMM - Is it really appropriate to give a hint that isn't
        !          1628:      *  the top activation for a thread?
        !          1629:      */
        !          1630:     if (hint_act->thread != self) {
        !          1631:        register thread_t               thread = hint_act->thread;
        !          1632:        
        !          1633:                /*
        !          1634:                 *      Check if the thread is in the right pset. Then
        !          1635:                 *      pull it off its run queue.  If it
        !          1636:                 *      doesn't come, then it's not eligible.
        !          1637:                 */
        !          1638:                if (thread) {
        !          1639:                        s = splsched();
        !          1640:                        thread_lock(thread);
        !          1641: 
        !          1642:                        if (    thread->processor_set == self->processor_set    &&
        !          1643:                                        rem_runq(thread) != RUN_QUEUE_NULL                                      ) {
        !          1644:                                /*
        !          1645:                                 *      Hah, got it!!
        !          1646:                                 */
        !          1647:                                if (thread->policy & (POLICY_FIFO|POLICY_RR)) {
        !          1648:                                        myprocessor = current_processor();
        !          1649: 
        !          1650:                                        assert(thread->sp_info != SP_INFO_NULL);
        !          1651:                                        sp_info = (mk_sp_info_t)thread->sp_info;
        !          1652: 
        !          1653:                                        myprocessor->quantum = sp_info->unconsumed_quantum;
        !          1654:                                        myprocessor->first_quantum = TRUE;
        !          1655:                                }
        !          1656:                                thread_unlock(thread);
        !          1657:                                splx(s);
        !          1658:                                act_unlock_thread(hint_act);
        !          1659:                                
        !          1660:                                counter(c_thread_switch_handoff++);
        !          1661:                                thread_run((void(*)(void)) 0, thread);
        !          1662: 
        !          1663:                                goto out;
        !          1664:                        }
        !          1665: 
        !          1666:                        thread_unlock(thread);
        !          1667:                        splx(s);
        !          1668:                }
        !          1669: 
        !          1670:                act_unlock_thread(hint_act);
        !          1671:     }
        !          1672: 
        !          1673:     /*
        !          1674:      * No handoff hint supplied, or hint was wrong.  Call thread_block() in
        !          1675:      * hopes of running something else.  If nothing else is runnable,
        !          1676:      * thread_block will detect this.  WARNING: thread_switch with no
        !          1677:      * option will not do anything useful if the thread calling it is the
        !          1678:      * highest priority thread (can easily happen with a collection
        !          1679:      * of timesharing threads).
        !          1680:      */
        !          1681:        mp_disable_preemption();
        !          1682:     myprocessor = current_processor();
        !          1683:     if (       option != SWITCH_OPTION_NONE                                    ||
        !          1684:                        myprocessor->processor_set->runq.count > 0              ||
        !          1685:                        myprocessor->runq.count > 0                                                     ) {
        !          1686:                myprocessor->first_quantum = FALSE;
        !          1687:                mp_enable_preemption();
        !          1688:          
        !          1689:                counter(c_thread_switch_block++);
        !          1690:                thread_block((void (*)(void)) 0);
        !          1691:        }
        !          1692:        else
        !          1693:                mp_enable_preemption();
        !          1694: 
        !          1695: out:
        !          1696:        if (option == SWITCH_OPTION_WAIT)
        !          1697:                thread_cancel_timer();
        !          1698:        else if (option == SWITCH_OPTION_DEPRESS)
        !          1699:                _mk_sp_thread_depress_abort(policy, self);
        !          1700: 
        !          1701:     return (KERN_SUCCESS);
        !          1702: }
        !          1703: 
        !          1704: /*
        !          1705:  *     mk_sp_thread_depress_priority
        !          1706:  *
        !          1707:  *     Depress thread's priority to lowest possible for specified period.
        !          1708:  *     Intended for use when thread wants a lock but doesn't know which
        !          1709:  *     other thread is holding it.  As with thread_switch, fixed
        !          1710:  *     priority threads get exactly what they asked for.  Users access
        !          1711:  *     this by the SWITCH_OPTION_DEPRESS option to thread_switch.  A Time
        !          1712:  *      of zero will result in no timeout being scheduled.
        !          1713:  */
        !          1714: void
        !          1715: _mk_sp_thread_depress_priority(
        !          1716:        sf_object_t                             policy,
        !          1717:        mach_msg_timeout_t              interval)
        !          1718: {
        !          1719:        register thread_t               self = current_thread();
        !          1720:     mk_sp_info_t                       sp_info;
        !          1721:        AbsoluteTime                    deadline;
        !          1722:        boolean_t                               release = FALSE;
        !          1723:     spl_t                                      s;
        !          1724: 
        !          1725:     s = splsched();
        !          1726:     thread_lock(self);
        !          1727: 
        !          1728:        if (self->policy == policy->policy_id) {
        !          1729:                /* get pointer to scheduling policy-specific data */
        !          1730:                assert(self->sp_info != SP_INFO_NULL);
        !          1731:                sp_info = (mk_sp_info_t)self->sp_info;
        !          1732: 
        !          1733:                /*
        !          1734:                 * If we haven't already saved the priority to be restored
        !          1735:                 * (depress_priority), then save it.
        !          1736:                 */
        !          1737:                if (sp_info->depress_priority < 0)
        !          1738:                        sp_info->depress_priority = sp_info->priority;
        !          1739:                else if (thread_call_cancel(&self->depress_timer))
        !          1740:                        release = TRUE;
        !          1741: 
        !          1742:                self->sched_pri = sp_info->priority = DEPRESSPRI;
        !          1743: 
        !          1744:                if (interval != 0) {
        !          1745:                        clock_interval_to_deadline(
        !          1746:                                                                interval, 1000*NSEC_PER_USEC, &deadline);
        !          1747:                        thread_call_enter_delayed(&self->depress_timer, deadline);
        !          1748:                        if (!release)
        !          1749:                                self->ref_count++;
        !          1750:                        else
        !          1751:                                release = FALSE;
        !          1752:                }
        !          1753:        }
        !          1754: 
        !          1755:     thread_unlock(self);
        !          1756:     splx(s);
        !          1757: 
        !          1758:        if (release)
        !          1759:                thread_deallocate(self);
        !          1760: }      
        !          1761: 
        !          1762: /*
        !          1763:  *     mk_sp_thread_depress_timeout:
        !          1764:  *
        !          1765:  *     Timeout routine for priority depression.
        !          1766:  */
        !          1767: void
        !          1768: _mk_sp_thread_depress_timeout(
        !          1769:        sf_object_t                             policy,
        !          1770:        register thread_t               thread)
        !          1771: {
        !          1772:     mk_sp_info_t                       sp_info;
        !          1773:     spl_t                                      s;
        !          1774: 
        !          1775:     counter(c_mk_sp_thread_depress_timeout++);
        !          1776: 
        !          1777:     s = splsched();
        !          1778:     thread_lock(thread);
        !          1779:        if (thread->policy == policy->policy_id) {
        !          1780:                /* get pointer to scheduling policy-specific data */
        !          1781:                assert(thread->sp_info != SP_INFO_NULL);
        !          1782:                sp_info = (mk_sp_info_t)thread->sp_info;
        !          1783: 
        !          1784:                /*
        !          1785:                 *      If we lose a race with mk_sp_thread_depress_abort,
        !          1786:                 *      then depress_priority might be -1.
        !          1787:                 */
        !          1788:                if (    sp_info->depress_priority >= 0                                          &&
        !          1789:                                !thread_call_is_delayed(&thread->depress_timer, NULL)           ) {
        !          1790:                        sp_info->priority = sp_info->depress_priority;
        !          1791:                        sp_info->depress_priority = -1;
        !          1792:                        compute_priority(thread, FALSE);
        !          1793:                }
        !          1794:                else
        !          1795:                if (sp_info->depress_priority == -2) {
        !          1796:                        /*
        !          1797:                         * Thread was temporarily undepressed by thread_suspend, to
        !          1798:                         * be redepressed in special_handler as it blocks.  We need to
        !          1799:                         * prevent special_handler from redepressing it, since depression
        !          1800:                         * has timed out:
        !          1801:                         */
        !          1802:                        sp_info->depress_priority = -1;
        !          1803:                }
        !          1804:        }
        !          1805:        thread_unlock(thread);
        !          1806:        splx(s);
        !          1807: }
        !          1808: 
        !          1809: /*
        !          1810:  *     mk_sp_thread_depress_abort:
        !          1811:  *
        !          1812:  *     Prematurely abort priority depression if there is one.
        !          1813:  */
        !          1814: kern_return_t
        !          1815: _mk_sp_thread_depress_abort(
        !          1816:        sf_object_t                             policy,
        !          1817:        register thread_t               thread)
        !          1818: {
        !          1819:     mk_sp_info_t                       sp_info;
        !          1820:     kern_return_t                      result = KERN_SUCCESS;
        !          1821:        boolean_t                               release = FALSE;
        !          1822:     spl_t                                      s;
        !          1823: 
        !          1824:     s = splsched();
        !          1825:     thread_lock(thread);
        !          1826: 
        !          1827:        if (thread->policy == policy->policy_id) {
        !          1828:                /* get pointer to scheduling policy-specific data */
        !          1829:                assert(thread->sp_info != SP_INFO_NULL);
        !          1830:                sp_info = (mk_sp_info_t)thread->sp_info;
        !          1831: 
        !          1832:                if (sp_info->depress_priority >= 0) {
        !          1833:                        if (thread_call_cancel(&thread->depress_timer))
        !          1834:                                release = TRUE;
        !          1835:                        sp_info->priority = sp_info->depress_priority;
        !          1836:                        sp_info->depress_priority = -1;
        !          1837:                        compute_priority(thread, FALSE);
        !          1838:                }
        !          1839:                else
        !          1840:                        result = KERN_NOT_DEPRESSED;
        !          1841:        }
        !          1842: 
        !          1843:     thread_unlock(thread);
        !          1844:     splx(s);
        !          1845: 
        !          1846:        if (release)
        !          1847:                thread_deallocate(thread);
        !          1848: 
        !          1849:     return (result);
        !          1850: }
        !          1851: 
        !          1852: /*
        !          1853:  *     mk_sp_thread_runnable:
        !          1854:  *
        !          1855:  *     Return TRUE iff policy believes thread is runnable
        !          1856:  */
        !          1857: boolean_t
        !          1858: _mk_sp_thread_runnable(
        !          1859:        sf_object_t                     policy,
        !          1860:        sched_thread_t          thread)
        !          1861: {
        !          1862:        mk_sp_info_t            sp_info;
        !          1863: 
        !          1864:        counter(c_mk_sp_thread_runnable++);
        !          1865: 
        !          1866:        /* get pointer to scheduling policy-specific data */
        !          1867:        assert(thread->sp_info != SP_INFO_NULL);
        !          1868:        sp_info = (mk_sp_info_t)thread->sp_info;
        !          1869: 
        !          1870:        counter(sp_info->c_mk_sp_thread_runnable++);
        !          1871: 
        !          1872:        return (sp_info->th_state == MK_SP_RUNNABLE);
        !          1873: }
        !          1874: 
        !          1875: sf_return_t
        !          1876: _mk_sp_alarm_expired(
        !          1877:        sf_object_t                     policy,
        !          1878:        long                            alarm_seqno,
        !          1879:        kern_return_t           result,
        !          1880:        int                                     alarm_type,
        !          1881:        mach_timespec_t         wakeup_time,
        !          1882:        void                            *alarm_data)
        !          1883: {
        !          1884:        counter(c_mk_sp_alarm_expired++);
        !          1885: 
        !          1886:        /* this should NEVER happen */
        !          1887:        assert(0);
        !          1888: 
        !          1889:        return (SF_FAILURE);
        !          1890: }
        !          1891: 
        !          1892: 
        !          1893: void
        !          1894: _mk_sp_thread_dump(
        !          1895:        sched_thread_t          thread)         /* thread */
        !          1896: {
        !          1897:        mk_sp_info_t            sp_info;
        !          1898:        int                     count;
        !          1899: 
        !          1900:        /* get pointer to scheduling policy-specific data */
        !          1901:        assert(thread->sp_info != SP_INFO_NULL);
        !          1902:        sp_info = (mk_sp_info_t)thread->sp_info;
        !          1903: 
        !          1904:        /* dump the data in a pretty format */
        !          1905:        printf("\nthread shuttle(0x%x):\n", thread);
        !          1906: 
        !          1907:        printf("\tpolicy: ");
        !          1908:        switch(thread->policy) {
        !          1909:                case POLICY_TIMESHARE:
        !          1910:                        printf("POLICY_TIMESHARE\n");
        !          1911:                        break;
        !          1912: 
        !          1913:                case POLICY_RR:
        !          1914:                        printf("POLICY_RR\n");
        !          1915:                        break;
        !          1916: 
        !          1917:                case POLICY_FIFO:
        !          1918:                        printf("POLICY_FIFO\n");
        !          1919:                        break;
        !          1920: 
        !          1921:                default:
        !          1922:                        printf("NOT an MK Standard Policy\n");
        !          1923:                        return;
        !          1924:        }
        !          1925: 
        !          1926:        printf("\tth_state: ");
        !          1927:        if (sp_info->th_state == 0) {
        !          1928:                printf("NULL");
        !          1929:        }
        !          1930:        else {
        !          1931:                count = 0;
        !          1932:                if (sp_info->th_state & MK_SP_ATTACHED) {
        !          1933:                        printf("MK_SP_ATTACHED ");
        !          1934:                        count++;
        !          1935:                }
        !          1936:                if (sp_info->th_state & MK_SP_RUNNABLE) {
        !          1937:                        if (count > 0) printf(" | ");
        !          1938:                        printf("MK_SP_RUNNABLE ");
        !          1939:                        count++;
        !          1940:                }
        !          1941:                if (sp_info->th_state & MK_SP_BLOCKED) {
        !          1942:                        if (count > 0) printf(" | ");
        !          1943:                        printf("MK_SP_BLOCKED ");
        !          1944:                        count++;
        !          1945:                }
        !          1946:        }
        !          1947:        printf("\n");
        !          1948: 
        !          1949:        printf("\tpriority: %d\n", sp_info->priority);
        !          1950:        printf("\tmax_priority: %d\n", sp_info->max_priority);
        !          1951:        printf("\tsched_data: %d\n", sp_info->sched_data);
        !          1952:        printf("\tdepress_priority: %d\n", sp_info->depress_priority);
        !          1953:        printf("\tcpu_usage: %d\n", sp_info->cpu_usage);
        !          1954:        printf("\tsched_usage: %d\n", sp_info->sched_usage);
        !          1955:        printf("\tsched_stamp: %d\n", sp_info->sched_stamp);
        !          1956:        printf("\tunconsumed_quantum: %d\n", sp_info->unconsumed_quantum);
        !          1957:        printf("\tsched_pri: %d\n", thread->sched_pri);
        !          1958: 
        !          1959: #ifdef MACH_ASSERT
        !          1960:        printf("\tc_mk_sp_thread_attach: %d\n",
        !          1961:               sp_info->c_mk_sp_thread_attach);
        !          1962:        printf("\tc_mk_sp_thread_detach: %d\n",
        !          1963:               sp_info->c_mk_sp_thread_detach);
        !          1964:        printf("\tc_mk_sp_thread_begin: %d\n",
        !          1965:               sp_info->c_mk_sp_thread_begin);
        !          1966:        printf("\tc_mk_sp_thread_done: %d\n",
        !          1967:               sp_info->c_mk_sp_thread_done);
        !          1968:        printf("\tc_mk_sp_thread_dispatch: %d\n",
        !          1969:               sp_info->c_mk_sp_thread_dispatch);
        !          1970:        printf("\tc_mk_sp_thread_unblock: %d\n",
        !          1971:               sp_info->c_mk_sp_thread_unblock);
        !          1972:        printf("\tc_mk_sp_thread_set: %d\n",
        !          1973:               sp_info->c_mk_sp_thread_set);
        !          1974:        printf("\tc_mk_sp_thread_get: %d\n",
        !          1975:               sp_info->c_mk_sp_thread_get);
        !          1976: #endif /* MACH_ASSERT */
        !          1977: 
        !          1978:        return;
        !          1979: }

unix.superglobalmegacorp.com

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