/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
*
*/
-/***
- *** ??? 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 <mach/boolean.h>
#include <mach/thread_switch.h>
#include <kern/spl.h>
#include <kern/task.h>
#include <kern/thread.h>
-#include <kern/ast.h>
#include <mach/policy.h>
#include <kern/syscall_subr.h>
#include <mach/mach_host_server.h>
#include <mach/mach_syscalls.h>
-/***
- *** ??? End of lines picked up when code was incorporated
- *** into this file from `kern/syscall_subr.c.'
- ***/
-
-#include <kern/sf.h>
-#include <kern/mk_sp.h>
#include <kern/misc_protos.h>
#include <kern/spl.h>
#include <kern/sched.h>
#include <kern/assert.h>
#include <kern/thread.h>
#include <mach/mach_host_server.h>
-
-/* 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 <mach/thread_act_server.h>
#include <mach/host_priv_server.h>
-/*
- * 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 ||
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);
}
/*
*/
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,
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) {
break;
}
- dat = rr_base->quantum;
bas = rr_base->base_priority;
max = rr_limit->max_priority;
if (invalid_pri(bas) || invalid_pri(max)) {
break;
}
- dat = 0;
bas = fifo_base->base_priority;
max = fifo_limit->max_priority;
if (invalid_pri(bas) || invalid_pri(max)) {
break;
}
- dat = 0;
bas = ts_base->base_priority;
max = ts_limit->max_priority;
if (invalid_pri(bas) || invalid_pri(max)) {
}
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);
}
*/
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) {
}
- 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);
-}