X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..21362eb3e66fd2c787aee132bce100a44d71a99c:/osfmk/kern/mk_sp.c diff --git a/osfmk/kern/mk_sp.c b/osfmk/kern/mk_sp.c index 2ba137750..9df11b215 100644 --- a/osfmk/kern/mk_sp.c +++ b/osfmk/kern/mk_sp.c @@ -1,35 +1,36 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ * */ -/*** - *** ??? The following lines were picked up when code was incorporated - *** into this file from `kern/syscall_subr.c.' These should be moved - *** with the code if it moves again. Otherwise, they should be trimmed, - *** based on the files included above. - ***/ +/* The routines in this module are all obsolete */ #include #include @@ -42,20 +43,12 @@ #include #include #include -#include #include #include #include #include -/*** - *** ??? End of lines picked up when code was incorporated - *** into this file from `kern/syscall_subr.c.' - ***/ - -#include -#include #include #include #include @@ -63,319 +56,20 @@ #include #include #include - -/* Forwards */ -void _mk_sp_thread_depress_priority( - sf_object_t policy, - mach_msg_timeout_t depress_time); - -/*** - *** ??? The next two files supply the prototypes for `thread_set_policy()' - *** and `thread_policy.' These routines cannot stay here if they are - *** exported Mach system calls. - ***/ #include #include -/* - * Vector containing standard scheduling policy operations - */ -sp_ops_t mk_sp_ops = { - _mk_sp_thread_update_mpri, - _mk_sp_thread_unblock, - _mk_sp_thread_done, - _mk_sp_thread_begin, - _mk_sp_thread_dispatch, - _mk_sp_thread_attach, - _mk_sp_thread_detach, - _mk_sp_thread_processor, - _mk_sp_thread_processor_set, - _mk_sp_thread_setup, - _mk_sp_swtch_pri, - _mk_sp_thread_switch, - _mk_sp_thread_depress_abort, - _mk_sp_thread_depress_timeout, - _mk_sp_thread_runnable, -}; - -/* Forwards */ -kern_return_t thread_policy_common( - thread_t thread, - int policy, - int data, - processor_set_t pset); - -/* - * Standard operations for MK Scheduling Policy - */ - -sf_return_t -_mk_sp_thread_update_mpri( - sf_object_t policy, - thread_t thread) -{ - if (thread->sched_stamp != sched_tick) - update_priority(thread); - - return(SF_SUCCESS); -} - -sf_return_t -_mk_sp_thread_unblock( - sf_object_t policy, - thread_t thread) -{ - /* indicate thread is now runnable */ - thread->sp_state = MK_SP_RUNNABLE; - - /* place thread at end of appropriate run queue */ - if (!(thread->state&TH_IDLE)) - thread_setrun(thread, TRUE, TAIL_Q); - - return(SF_SUCCESS); -} - -sf_return_t -_mk_sp_thread_done( - sf_object_t policy, - thread_t old_thread) -{ - processor_t myprocessor = cpu_to_processor(cpu_number()); - - /* - * A running thread is being taken off a processor: - * - * - update the thread's `unconsumed_quantum' field - * - update the thread's state field - */ - - old_thread->unconsumed_quantum = myprocessor->quantum; - - if (old_thread->state & TH_WAIT) - old_thread->sp_state = MK_SP_BLOCKED; - - return(SF_SUCCESS); -} - -sf_return_t -_mk_sp_thread_begin( - sf_object_t policy, - thread_t thread) -{ - - processor_t myprocessor = cpu_to_processor(cpu_number()); - processor_set_t pset; - - pset = myprocessor->processor_set; - /* - * The designated thread is about to begin execution: - * - * - update the processor's `quantum' field - */ - /* check for legal thread state */ - assert(thread->sp_state == MK_SP_RUNNABLE); - - if (thread->policy & (POLICY_RR|POLICY_FIFO)) - myprocessor->quantum = thread->unconsumed_quantum; - else - myprocessor->quantum = (thread->bound_processor ? - min_quantum : pset->set_quantum); - - return(SF_SUCCESS); -} - -sf_return_t -_mk_sp_thread_dispatch( - sf_object_t policy, - thread_t old_thread) -{ - if (old_thread->sp_state & MK_SP_RUNNABLE) { - if (old_thread->reason & AST_QUANTUM) { - thread_setrun(old_thread, FALSE, TAIL_Q); - old_thread->unconsumed_quantum = min_quantum; - } - else - thread_setrun(old_thread, FALSE, HEAD_Q); - } - - if (old_thread->sp_state & MK_SP_ATTACHED) { - /* indicate thread is now runnable */ - old_thread->sp_state = MK_SP_RUNNABLE; - - /* place thread at end of appropriate run queue */ - thread_setrun(old_thread, FALSE, TAIL_Q); - } - - return(SF_SUCCESS); -} - -/* - * Thread must already be locked. - */ -sf_return_t -_mk_sp_thread_attach( - sf_object_t policy, - thread_t thread) -{ - thread->sp_state = MK_SP_ATTACHED; - - thread->max_priority = thread->priority = BASEPRI_DEFAULT; - thread->depress_priority = -1; - - thread->cpu_usage = 0; - thread->sched_usage = 0; - thread->sched_stamp = 0; - - thread->unconsumed_quantum = min_quantum; - - /* Reflect this policy in thread data structure */ - thread->policy = policy->policy_id; - - return(SF_SUCCESS); -} - -/* - * Check to make sure that thread is removed from run - * queues and active execution; and clear pending - * priority depression. - * - * Thread must already be locked. - */ -sf_return_t -_mk_sp_thread_detach( - sf_object_t policy, - thread_t thread) -{ - struct run_queue *rq; - - assert(thread->policy == policy->policy_id); - - /* make sure that the thread is no longer on any run queue */ - if (thread->runq != RUN_QUEUE_NULL) { - rq = rem_runq(thread); - if (rq == RUN_QUEUE_NULL) { - panic("mk_sp_thread_detach: missed thread"); - } - } - - /* clear pending priority depression */ - - if (thread->depress_priority >= 0) { - thread->priority = thread->depress_priority; - thread->depress_priority = -1; - if (thread_call_cancel(&thread->depress_timer)) - thread_call_enter(&thread->depress_timer); - } - - /* clear the thread's policy field */ - thread->policy = POLICY_NULL; - - return(SF_SUCCESS); -} - -sf_return_t -_mk_sp_thread_processor( - sf_object_t policy, - thread_t *thread, - processor_t processor) -{ - return(SF_FAILURE); -} - -sf_return_t -_mk_sp_thread_processor_set( - sf_object_t policy, - thread_t thread, - processor_set_t processor_set) -{ - pset_add_thread(processor_set, thread); - - return(SF_SUCCESS); -} - -sf_return_t -_mk_sp_thread_setup( - sf_object_t policy, - thread_t thread) -{ - /* - * Determine thread's state. (It may be an "older" thread - * that has just been associated with this policy.) - */ - if (thread->state & TH_WAIT) - thread->sp_state = MK_SP_BLOCKED; - - /* recompute priority */ - thread->sched_stamp = sched_tick; - compute_priority(thread, TRUE); - - return(SF_SUCCESS); -} - -/* - * thread_priority_internal: - * - * Kernel-internal work function for thread_priority(). Called - * with thread "properly locked" to ensure synchrony with RPC - * (see act_lock_thread()). - */ -kern_return_t -thread_priority_internal( - thread_t thread, - int priority) -{ - kern_return_t result = KERN_SUCCESS; - spl_t s; - - s = splsched(); - thread_lock(thread); - - /* - * Check for violation of max priority - */ - if (priority > thread->max_priority) - priority = thread->max_priority; - - /* - * Set priorities. If a depression is in progress, - * change the priority to restore. - */ - if (thread->depress_priority >= 0) - thread->depress_priority = priority; - else { - thread->priority = priority; - compute_priority(thread, TRUE); - - /* - * If the current thread has changed its - * priority let the ast code decide whether - * a different thread should run. - */ - if (thread == current_thread()) - ast_on(AST_BLOCK); - } - - thread_unlock(thread); - splx(s); - - return (result); -} - /* * thread_policy_common: * - * Set scheduling policy for thread. If pset == PROCESSOR_SET_NULL, - * policy will be checked to make sure it is enabled. + * Set scheduling policy & priority for thread. */ -kern_return_t +static kern_return_t thread_policy_common( thread_t thread, integer_t policy, - integer_t data, - processor_set_t pset) + integer_t priority) { - kern_return_t result = KERN_SUCCESS; - register int temp; spl_t s; if ( thread == THREAD_NULL || @@ -385,34 +79,60 @@ thread_policy_common( s = splsched(); thread_lock(thread); - /* - * Check if changing policy. - */ - if (policy != thread->policy) { - /* - * Changing policy. Check if new policy is allowed. - */ - if ( pset == PROCESSOR_SET_NULL && - (thread->processor_set->policies & policy) == 0 ) - result = KERN_FAILURE; - else { - if (pset != thread->processor_set) - result = KERN_FAILURE; - else { - /* - * Changing policy. Calculate new - * priority. - */ - thread->policy = policy; - compute_priority(thread, TRUE); + if ( !(thread->sched_mode & TH_MODE_REALTIME) && + !(thread->safe_mode & TH_MODE_REALTIME) ) { + if (!(thread->sched_mode & TH_MODE_FAILSAFE)) { + integer_t oldmode = (thread->sched_mode & TH_MODE_TIMESHARE); + + if (policy == POLICY_TIMESHARE && !oldmode) { + thread->sched_mode |= TH_MODE_TIMESHARE; + + if (thread->state & TH_RUN) + pset_share_incr(thread->processor_set); + } + else + if (policy != POLICY_TIMESHARE && oldmode) { + thread->sched_mode &= ~TH_MODE_TIMESHARE; + + if (thread->state & TH_RUN) + pset_share_decr(thread->processor_set); } - } + } + else { + if (policy == POLICY_TIMESHARE) + thread->safe_mode |= TH_MODE_TIMESHARE; + else + thread->safe_mode &= ~TH_MODE_TIMESHARE; + } + + if (priority >= thread->max_priority) + priority = thread->max_priority - thread->task_priority; + else + if (priority >= MINPRI_KERNEL) + priority -= MINPRI_KERNEL; + else + if (priority >= MINPRI_RESERVED) + priority -= MINPRI_RESERVED; + else + priority -= BASEPRI_DEFAULT; + + priority += thread->task_priority; + + if (priority > thread->max_priority) + priority = thread->max_priority; + else + if (priority < MINPRI) + priority = MINPRI; + + thread->importance = priority - thread->task_priority; + + set_priority(thread, priority); } thread_unlock(thread); splx(s); - return (result); + return (KERN_SUCCESS); } /* @@ -424,7 +144,7 @@ thread_policy_common( */ kern_return_t thread_set_policy( - thread_act_t thr_act, + thread_t thread, processor_set_t pset, policy_t policy, policy_base_t base, @@ -432,25 +152,19 @@ thread_set_policy( policy_limit_t limit, mach_msg_type_number_t limit_count) { - thread_t thread; - int max, bas, dat, incr; + int max, bas; kern_return_t result = KERN_SUCCESS; - if ( thr_act == THR_ACT_NULL || + if ( thread == THREAD_NULL || pset == PROCESSOR_SET_NULL ) return (KERN_INVALID_ARGUMENT); - thread = act_lock_thread(thr_act); - if (thread == THREAD_NULL) { - act_unlock_thread(thr_act); - - return(KERN_INVALID_ARGUMENT); - } + thread_mtx_lock(thread); if (pset != thread->processor_set) { - act_unlock_thread(thr_act); + thread_mtx_unlock(thread); - return(KERN_FAILURE); + return (KERN_FAILURE); } switch (policy) { @@ -466,7 +180,6 @@ thread_set_policy( break; } - dat = rr_base->quantum; bas = rr_base->base_priority; max = rr_limit->max_priority; if (invalid_pri(bas) || invalid_pri(max)) { @@ -488,7 +201,6 @@ thread_set_policy( break; } - dat = 0; bas = fifo_base->base_priority; max = fifo_limit->max_priority; if (invalid_pri(bas) || invalid_pri(max)) { @@ -511,7 +223,6 @@ thread_set_policy( break; } - dat = 0; bas = ts_base->base_priority; max = ts_limit->max_priority; if (invalid_pri(bas) || invalid_pri(max)) { @@ -527,17 +238,16 @@ thread_set_policy( } if (result != KERN_SUCCESS) { - act_unlock_thread(thr_act); + thread_mtx_unlock(thread); - return(result); + return (result); } - result = thread_priority_internal(thread, bas); - if (result == KERN_SUCCESS) - result = thread_policy_common(thread, policy, dat, pset); - act_unlock_thread(thr_act); + result = thread_policy_common(thread, policy, bas); - return(result); + thread_mtx_unlock(thread); + + return (result); } @@ -550,38 +260,37 @@ thread_set_policy( */ kern_return_t thread_policy( - thread_act_t thr_act, + thread_t thread, policy_t policy, policy_base_t base, mach_msg_type_number_t count, boolean_t set_limit) { - thread_t thread; - processor_set_t pset; kern_return_t result = KERN_SUCCESS; + processor_set_t pset; policy_limit_t limit; int limcount; policy_rr_limit_data_t rr_limit; policy_fifo_limit_data_t fifo_limit; policy_timeshare_limit_data_t ts_limit; - if (thr_act == THR_ACT_NULL) + if (thread == THREAD_NULL) return (KERN_INVALID_ARGUMENT); - thread = act_lock_thread(thr_act); + thread_mtx_lock(thread); + pset = thread->processor_set; - if ( thread == THREAD_NULL || - pset == PROCESSOR_SET_NULL ){ - act_unlock_thread(thr_act); + if (pset == PROCESSOR_SET_NULL) { + thread_mtx_unlock(thread); - return(KERN_INVALID_ARGUMENT); + return (KERN_INVALID_ARGUMENT); } - if ( invalid_policy(policy) || - (pset->policies & policy) == 0 ) { - act_unlock_thread(thr_act); + if ( invalid_policy(policy) || + ((POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO) & policy) == 0 ) { + thread_mtx_unlock(thread); - return(KERN_INVALID_POLICY); + return (KERN_INVALID_POLICY); } if (set_limit) { @@ -727,554 +436,11 @@ thread_policy( } - act_unlock_thread(thr_act); + thread_mtx_unlock(thread); if (result == KERN_SUCCESS) - result = thread_set_policy(thr_act, pset, + result = thread_set_policy(thread, pset, policy, base, count, limit, limcount); return(result); } - -/* - * Define shifts for simulating (5/8)**n - */ - -shift_data_t wait_shift[32] = { - {1,1},{1,3},{1,-3},{2,-7},{3,5},{3,-5},{4,-8},{5,7}, - {5,-7},{6,-10},{7,10},{7,-9},{8,-11},{9,12},{9,-11},{10,-13}, - {11,14},{11,-13},{12,-15},{13,17},{13,-15},{14,-17},{15,19},{16,18}, - {16,-19},{17,22},{18,20},{18,-20},{19,26},{20,22},{20,-22},{21,-27}}; - -/* - * do_priority_computation: - * - * Calculate new priority for thread based on its base priority plus - * accumulated usage. PRI_SHIFT and PRI_SHIFT_2 convert from - * usage to priorities. SCHED_SHIFT converts for the scaling - * of the sched_usage field by SCHED_SCALE. This scaling comes - * from the multiplication by sched_load (thread_timer_delta) - * in sched.h. sched_load is calculated as a scaled overload - * factor in compute_mach_factor (mach_factor.c). - */ -#ifdef PRI_SHIFT_2 -#if PRI_SHIFT_2 > 0 -#define do_priority_computation(thread, pri) \ - MACRO_BEGIN \ - (pri) = (thread)->priority /* start with base priority */ \ - - ((thread)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)) \ - - ((thread)->sched_usage >> (PRI_SHIFT_2 + SCHED_SHIFT)); \ - if ((pri) < MINPRI_STANDARD) \ - (pri) = MINPRI_STANDARD; \ - else \ - if ((pri) > MAXPRI_STANDARD) \ - (pri) = MAXPRI_STANDARD; \ - MACRO_END -#else /* PRI_SHIFT_2 */ -#define do_priority_computation(thread, pri) \ - MACRO_BEGIN \ - (pri) = (thread)->priority /* start with base priority */ \ - - ((thread)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)) \ - + ((thread)->sched_usage >> (SCHED_SHIFT - PRI_SHIFT_2)); \ - if ((pri) < MINPRI_STANDARD) \ - (pri) = MINPRI_STANDARD; \ - else \ - if ((pri) > MAXPRI_STANDARD) \ - (pri) = MAXPRI_STANDARD; \ - MACRO_END -#endif /* PRI_SHIFT_2 */ -#else /* defined(PRI_SHIFT_2) */ -#define do_priority_computation(thread, pri) \ - MACRO_BEGIN \ - (pri) = (thread)->priority /* start with base priority */ \ - - ((thread)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)); \ - if ((pri) < MINPRI_STANDARD) \ - (pri) = MINPRI_STANDARD; \ - else \ - if ((pri) > MAXPRI_STANDARD) \ - (pri) = MAXPRI_STANDARD; \ - MACRO_END -#endif /* defined(PRI_SHIFT_2) */ - -/* - * compute_priority: - * - * Compute the effective priority of the specified thread. - * The effective priority computation is as follows: - * - * Take the base priority for this thread and add - * to it an increment derived from its cpu_usage. - * - * The thread *must* be locked by the caller. - */ - -void -compute_priority( - register thread_t thread, - boolean_t resched) -{ - register int pri; - - if (thread->policy == POLICY_TIMESHARE) { - do_priority_computation(thread, pri); - if (thread->depress_priority < 0) - set_pri(thread, pri, resched); - else - thread->depress_priority = pri; - } - else - set_pri(thread, thread->priority, resched); -} - -/* - * compute_my_priority: - * - * Version of compute priority for current thread or thread - * being manipulated by scheduler (going on or off a runq). - * Only used for priority updates. Policy or priority changes - * must call compute_priority above. Caller must have thread - * locked and know it is timesharing and not depressed. - */ - -void -compute_my_priority( - register thread_t thread) -{ - register int pri; - - do_priority_computation(thread, pri); - assert(thread->runq == RUN_QUEUE_NULL); - thread->sched_pri = pri; -} - -#if DEBUG -struct mk_sp_usage { - natural_t cpu_delta, sched_delta; - natural_t sched_tick, ticks; - natural_t cpu_usage, sched_usage, - aged_cpu, aged_sched; - thread_t thread; -} idled_info, loaded_info; -#endif - -/* - * update_priority - * - * Cause the priority computation of a thread that has been - * sleeping or suspended to "catch up" with the system. Thread - * *MUST* be locked by caller. If thread is running, then this - * can only be called by the thread on itself. - */ -void -update_priority( - register thread_t thread) -{ - register unsigned int ticks; - register shift_t shiftp; - - ticks = sched_tick - thread->sched_stamp; - assert(ticks != 0); - - /* - * If asleep for more than 30 seconds forget all - * cpu_usage, else catch up on missed aging. - * 5/8 ** n is approximated by the two shifts - * in the wait_shift array. - */ - thread->sched_stamp += ticks; - thread_timer_delta(thread); - if (ticks > 30) { - thread->cpu_usage = 0; - thread->sched_usage = 0; - } - else { -#if DEBUG - struct mk_sp_usage *sp_usage; -#endif - - thread->cpu_usage += thread->cpu_delta; - thread->sched_usage += thread->sched_delta; - -#if DEBUG - if (thread->state & TH_IDLE) - sp_usage = &idled_info; - else - if (thread == loaded_info.thread) - sp_usage = &loaded_info; - else - sp_usage = NULL; - - if (sp_usage != NULL) { - sp_usage->cpu_delta = thread->cpu_delta; - sp_usage->sched_delta = thread->sched_delta; - sp_usage->sched_tick = thread->sched_stamp; - sp_usage->ticks = ticks; - sp_usage->cpu_usage = thread->cpu_usage; - sp_usage->sched_usage = thread->sched_usage; - sp_usage->thread = thread; - } -#endif - - shiftp = &wait_shift[ticks]; - if (shiftp->shift2 > 0) { - thread->cpu_usage = - (thread->cpu_usage >> shiftp->shift1) + - (thread->cpu_usage >> shiftp->shift2); - thread->sched_usage = - (thread->sched_usage >> shiftp->shift1) + - (thread->sched_usage >> shiftp->shift2); - } - else { - thread->cpu_usage = - (thread->cpu_usage >> shiftp->shift1) - - (thread->cpu_usage >> -(shiftp->shift2)); - thread->sched_usage = - (thread->sched_usage >> shiftp->shift1) - - (thread->sched_usage >> -(shiftp->shift2)); - } - -#if DEBUG - if (sp_usage != NULL) { - sp_usage->aged_cpu = thread->cpu_usage; - sp_usage->aged_sched = thread->sched_usage; - } -#endif - } - thread->cpu_delta = 0; - thread->sched_delta = 0; - - /* - * Recompute priority if appropriate. - */ - if ( thread->policy == POLICY_TIMESHARE && - thread->depress_priority < 0 ) { - register int new_pri; - run_queue_t runq; - - do_priority_computation(thread, new_pri); - if (new_pri != thread->sched_pri) { - runq = rem_runq(thread); - thread->sched_pri = new_pri; - if (runq != RUN_QUEUE_NULL) - thread_setrun(thread, TRUE, TAIL_Q); - } - } -} - -/* - * `mk_sp_swtch_pri()' attempts to context switch (logic in - * thread_block no-ops the context switch if nothing would happen). - * A boolean is returned that indicates whether there is anything - * else runnable. - * - * This boolean can be used by a thread waiting on a - * lock or condition: If FALSE is returned, the thread is justified - * in becoming a resource hog by continuing to spin because there's - * nothing else useful that the processor could do. If TRUE is - * returned, the thread should make one more check on the - * lock and then be a good citizen and really suspend. - */ - -void -_mk_sp_swtch_pri( - sf_object_t policy, - int pri) -{ - register thread_t self = current_thread(); - extern natural_t min_quantum_ms; - -#ifdef lint - pri++; -#endif /* lint */ - - /* - * XXX need to think about depression duration. - * XXX currently using min quantum. - */ - _mk_sp_thread_depress_priority(policy, min_quantum_ms); - - thread_block((void (*)(void)) 0); - - _mk_sp_thread_depress_abort(policy, self); -} - -/* - * thread_switch_continue: - * - * Continuation routine for a thread switch. - * - * Just need to arrange the return value gets sent out correctly and that - * we cancel the timer or the depression called for by the options to the - * thread_switch call. - */ -void -_mk_sp_thread_switch_continue(void) -{ - thread_t self = current_thread(); - int wait_result = self->wait_result; - int option = self->saved.swtch.option; - sf_object_t policy = self->saved.swtch.policy; - - if (option == SWITCH_OPTION_WAIT && wait_result != THREAD_TIMED_OUT) - thread_cancel_timer(); - else if (option == SWITCH_OPTION_DEPRESS) - _mk_sp_thread_depress_abort(policy, self); - thread_syscall_return(KERN_SUCCESS); -} - -/* - * thread_switch: - * - * Context switch. User may supply thread hint. - * - * Fixed priority threads that call this get what they asked for - * even if that violates priority order. - */ -kern_return_t -_mk_sp_thread_switch( - sf_object_t policy, - thread_act_t hint_act, - int option, - mach_msg_timeout_t option_time) -{ - register thread_t self = current_thread(); - register processor_t myprocessor; - int s; - - /* - * Check and use thr_act hint if appropriate. It is not - * appropriate to give a hint that shares the current shuttle. - */ - if (hint_act != THR_ACT_NULL) { - register thread_t thread = act_lock_thread(hint_act); - - if ( thread != THREAD_NULL && - thread != self && - thread->top_act == hint_act ) { - s = splsched(); - thread_lock(thread); - - /* - * Check if the thread is in the right pset. Then - * pull it off its run queue. If it - * doesn't come, then it's not eligible. - */ - if ( thread->processor_set == self->processor_set && - rem_runq(thread) != RUN_QUEUE_NULL ) { - /* - * Hah, got it!! - */ - if (thread->policy & (POLICY_FIFO|POLICY_RR)) { - myprocessor = current_processor(); - - myprocessor->quantum = thread->unconsumed_quantum; - myprocessor->first_quantum = TRUE; - } - thread_unlock(thread); - - act_unlock_thread(hint_act); - act_deallocate(hint_act); - - if (option == SWITCH_OPTION_WAIT) - assert_wait_timeout(option_time, THREAD_ABORTSAFE); - else if (option == SWITCH_OPTION_DEPRESS) - _mk_sp_thread_depress_priority(policy, option_time); - - self->saved.swtch.policy = policy; - self->saved.swtch.option = option; - - thread_run(self, _mk_sp_thread_switch_continue, thread); - splx(s); - - goto out; - } - - thread_unlock(thread); - splx(s); - } - - act_unlock_thread(hint_act); - act_deallocate(hint_act); - } - - /* - * No handoff hint supplied, or hint was wrong. Call thread_block() in - * hopes of running something else. If nothing else is runnable, - * thread_block will detect this. WARNING: thread_switch with no - * option will not do anything useful if the thread calling it is the - * highest priority thread (can easily happen with a collection - * of timesharing threads). - */ - mp_disable_preemption(); - myprocessor = current_processor(); - if ( option != SWITCH_OPTION_NONE || - myprocessor->processor_set->runq.count > 0 || - myprocessor->runq.count > 0 ) { - myprocessor->first_quantum = FALSE; - mp_enable_preemption(); - - if (option == SWITCH_OPTION_WAIT) - assert_wait_timeout(option_time, THREAD_ABORTSAFE); - else if (option == SWITCH_OPTION_DEPRESS) - _mk_sp_thread_depress_priority(policy, option_time); - - self->saved.swtch.policy = policy; - self->saved.swtch.option = option; - - thread_block(_mk_sp_thread_switch_continue); - } - else - mp_enable_preemption(); - -out: - if (option == SWITCH_OPTION_WAIT) - thread_cancel_timer(); - else if (option == SWITCH_OPTION_DEPRESS) - _mk_sp_thread_depress_abort(policy, self); - - return (KERN_SUCCESS); -} - -/* - * mk_sp_thread_depress_priority - * - * Depress thread's priority to lowest possible for specified period. - * Intended for use when thread wants a lock but doesn't know which - * other thread is holding it. As with thread_switch, fixed - * priority threads get exactly what they asked for. Users access - * this by the SWITCH_OPTION_DEPRESS option to thread_switch. A Time - * of zero will result in no timeout being scheduled. - */ -void -_mk_sp_thread_depress_priority( - sf_object_t policy, - mach_msg_timeout_t interval) -{ - register thread_t self = current_thread(); - AbsoluteTime deadline; - boolean_t release = FALSE; - spl_t s; - - s = splsched(); - thread_lock(self); - - if (self->policy == policy->policy_id) { - /* - * If we haven't already saved the priority to be restored - * (depress_priority), then save it. - */ - if (self->depress_priority < 0) - self->depress_priority = self->priority; - else if (thread_call_cancel(&self->depress_timer)) - release = TRUE; - - self->sched_pri = self->priority = DEPRESSPRI; - - if (interval != 0) { - clock_interval_to_deadline( - interval, 1000*NSEC_PER_USEC, &deadline); - thread_call_enter_delayed(&self->depress_timer, deadline); - if (!release) - self->ref_count++; - else - release = FALSE; - } - } - - thread_unlock(self); - splx(s); - - if (release) - thread_deallocate(self); -} - -/* - * mk_sp_thread_depress_timeout: - * - * Timeout routine for priority depression. - */ -void -_mk_sp_thread_depress_timeout( - sf_object_t policy, - register thread_t thread) -{ - spl_t s; - - s = splsched(); - thread_lock(thread); - if (thread->policy == policy->policy_id) { - /* - * If we lose a race with mk_sp_thread_depress_abort, - * then depress_priority might be -1. - */ - if ( thread->depress_priority >= 0 && - !thread_call_is_delayed(&thread->depress_timer, NULL) ) { - thread->priority = thread->depress_priority; - thread->depress_priority = -1; - compute_priority(thread, FALSE); - } - else - if (thread->depress_priority == -2) { - /* - * Thread was temporarily undepressed by thread_suspend, to - * be redepressed in special_handler as it blocks. We need to - * prevent special_handler from redepressing it, since depression - * has timed out: - */ - thread->depress_priority = -1; - } - } - thread_unlock(thread); - splx(s); -} - -/* - * mk_sp_thread_depress_abort: - * - * Prematurely abort priority depression if there is one. - */ -kern_return_t -_mk_sp_thread_depress_abort( - sf_object_t policy, - register thread_t thread) -{ - kern_return_t result = KERN_SUCCESS; - boolean_t release = FALSE; - spl_t s; - - s = splsched(); - thread_lock(thread); - - if (thread->policy == policy->policy_id) { - if (thread->depress_priority >= 0) { - if (thread_call_cancel(&thread->depress_timer)) - release = TRUE; - thread->priority = thread->depress_priority; - thread->depress_priority = -1; - compute_priority(thread, FALSE); - } - else - result = KERN_NOT_DEPRESSED; - } - - thread_unlock(thread); - splx(s); - - if (release) - thread_deallocate(thread); - - return (result); -} - -/* - * mk_sp_thread_runnable: - * - * Return TRUE iff policy believes thread is runnable - */ -boolean_t -_mk_sp_thread_runnable( - sf_object_t policy, - thread_t thread) -{ - return (thread->sp_state == MK_SP_RUNNABLE); -}