X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8ad349bb6ed4a0be06e34c92be0d98b92e078db4..3e170ce000f1506b7b5d2c5c7faec85ceabb573d:/osfmk/kern/thread_act.c diff --git a/osfmk/kern/thread_act.c b/osfmk/kern/thread_act.c index 71edcc788..6c1b2e379 100644 --- a/osfmk/kern/thread_act.c +++ b/osfmk/kern/thread_act.c @@ -1,31 +1,29 @@ /* - * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * 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. - * - * 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. + * + * 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and * limitations under the License. - * - * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_FREE_COPYRIGHT@ @@ -54,7 +52,6 @@ #include #include #include -#include #include #include @@ -62,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -70,21 +68,42 @@ #include #include #include -#include #include #include #include #include #include #include -#include +#include + #include +#include + void act_abort(thread_t); -void act_set_apc(thread_t); void install_special_handler_locked(thread_t); void special_handler_continue(void); +/* + * Internal routine to mark a thread as started. + * Always called with the thread mutex locked. + * + * Note: function intentionally declared with the noinline attribute to + * prevent multiple declaration of probe symbols in this file; we would + * prefer "#pragma noinline", but gcc does not support it. + * PR-6385749 -- the lwp-start probe should fire from within the context + * of the newly created thread. Commented out for now, in case we + * turn it into a dead code probe. + */ +void +thread_start_internal( + thread_t thread) +{ + clear_wait(thread, THREAD_AWAKENED); + thread->started = TRUE; + // DTRACE_PROC1(lwp__start, thread_t, thread); +} + /* * Internal routine to terminate a thread. * Sometimes called with task already locked. @@ -105,17 +124,19 @@ thread_terminate_internal( if (thread->started) clear_wait(thread, THREAD_INTERRUPTED); else { - clear_wait(thread, THREAD_AWAKENED); - thread->started = TRUE; + thread_start_internal(thread); } } else result = KERN_TERMINATED; + if (thread->affinity_set != NULL) + thread_affinity_terminate(thread); + thread_mtx_unlock(thread); if (thread != current_thread() && result == KERN_SUCCESS) - thread_wait(thread); + thread_wait(thread, FALSE); return (result); } @@ -186,8 +207,7 @@ thread_release( if (thread->started) thread_wakeup_one(&thread->suspend_count); else { - clear_wait(thread, THREAD_AWAKENED); - thread->started = TRUE; + thread_start_internal(thread); } } } @@ -218,7 +238,7 @@ thread_suspend( thread_mtx_unlock(thread); if (thread != self && result == KERN_SUCCESS) - thread_wait(thread); + thread_wait(thread, FALSE); return (result); } @@ -241,8 +261,7 @@ thread_resume( if (thread->started) thread_wakeup_one(&thread->suspend_count); else { - clear_wait(thread, THREAD_AWAKENED); - thread->started = TRUE; + thread_start_internal(thread); } } } @@ -298,12 +317,12 @@ act_abort( thread_lock(thread); - if (!(thread->state & TH_ABORT)) { - thread->state |= TH_ABORT; + if (!(thread->sched_flags & TH_SFLAG_ABORT)) { + thread->sched_flags |= TH_SFLAG_ABORT; install_special_handler_locked(thread); } else - thread->state &= ~TH_ABORT_SAFELY; + thread->sched_flags &= ~TH_SFLAG_ABORTSAFELY; thread_unlock(thread); splx(s); @@ -348,9 +367,9 @@ thread_abort_safely( thread_lock(thread); if (!thread->at_safe_point || - clear_wait_internal(thread, THREAD_INTERRUPTED) != KERN_SUCCESS) { - if (!(thread->state & TH_ABORT)) { - thread->state |= (TH_ABORT|TH_ABORT_SAFELY); + clear_wait_internal(thread, THREAD_INTERRUPTED) != KERN_SUCCESS) { + if (!(thread->sched_flags & TH_SFLAG_ABORT)) { + thread->sched_flags |= TH_SFLAG_ABORTED_MASK; install_special_handler_locked(thread); } } @@ -372,7 +391,7 @@ thread_abort_safely( kern_return_t thread_info( - thread_t thread, + thread_t thread, thread_flavor_t flavor, thread_info_t thread_info_out, mach_msg_type_number_t *thread_info_count) @@ -384,7 +403,7 @@ thread_info( thread_mtx_lock(thread); - if (thread->active) + if (thread->active || thread->inspection) result = thread_info_internal( thread, flavor, thread_info_out, thread_info_count); else @@ -415,7 +434,7 @@ thread_get_state( thread_mtx_unlock(thread); - if (thread_stop(thread)) { + if (thread_stop(thread, FALSE)) { thread_mtx_lock(thread); result = machine_thread_get_state( thread, flavor, state, state_count); @@ -432,6 +451,11 @@ thread_get_state( result = machine_thread_get_state( thread, flavor, state, state_count); } + else if (thread->inspection) + { + result = machine_thread_get_state( + thread, flavor, state, state_count); + } else result = KERN_TERMINATED; @@ -444,12 +468,13 @@ thread_get_state( * Change thread's machine-dependent state. Called with nothing * locked. Returns same way. */ -kern_return_t -thread_set_state( +static kern_return_t +thread_set_state_internal( register thread_t thread, int flavor, thread_state_t state, - mach_msg_type_number_t state_count) + mach_msg_type_number_t state_count, + boolean_t from_user) { kern_return_t result = KERN_SUCCESS; @@ -464,7 +489,7 @@ thread_set_state( thread_mtx_unlock(thread); - if (thread_stop(thread)) { + if (thread_stop(thread, TRUE)) { thread_mtx_lock(thread); result = machine_thread_set_state( thread, flavor, state, state_count); @@ -484,11 +509,41 @@ thread_set_state( else result = KERN_TERMINATED; + if ((result == KERN_SUCCESS) && from_user) + extmod_statistics_incr_thread_set_state(thread); + thread_mtx_unlock(thread); return (result); } + +/* No prototype, since thread_act_server.h has the _from_user version if KERNEL_SERVER */ +kern_return_t +thread_set_state( + register thread_t thread, + int flavor, + thread_state_t state, + mach_msg_type_number_t state_count); + +kern_return_t +thread_set_state( + register thread_t thread, + int flavor, + thread_state_t state, + mach_msg_type_number_t state_count) +{ + return thread_set_state_internal(thread, flavor, state, state_count, FALSE); +} +kern_return_t +thread_set_state_from_user( + register thread_t thread, + int flavor, + thread_state_t state, + mach_msg_type_number_t state_count) +{ + return thread_set_state_internal(thread, flavor, state, state_count, TRUE); +} /* * Kernel-internal "thread" interfaces used outside this file: @@ -514,7 +569,7 @@ thread_state_initialize( thread_mtx_unlock(thread); - if (thread_stop(thread)) { + if (thread_stop(thread, TRUE)) { thread_mtx_lock(thread); result = machine_thread_state_initialize( thread ); thread_unstop(thread); @@ -527,7 +582,7 @@ thread_state_initialize( thread_release(thread); } else - result = machine_thread_state_initialize( thread ); + result = machine_thread_state_initialize( thread ); } else result = KERN_TERMINATED; @@ -555,9 +610,11 @@ thread_dup( thread_mtx_unlock(target); - if (thread_stop(target)) { + if (thread_stop(target, TRUE)) { thread_mtx_lock(target); result = machine_thread_dup(self, target); + if (self->affinity_set != AFFINITY_SET_NULL) + thread_affinity_dup(self, target); thread_unstop(target); } else { @@ -608,6 +665,51 @@ thread_getstatus( return (thread_get_state(thread, flavor, tstate, count)); } +/* + * Change thread's machine-dependent userspace TSD base. + * Called with nothing locked. Returns same way. + */ +kern_return_t +thread_set_tsd_base( + thread_t thread, + mach_vm_offset_t tsd_base) +{ + kern_return_t result = KERN_SUCCESS; + + if (thread == THREAD_NULL) + return (KERN_INVALID_ARGUMENT); + + thread_mtx_lock(thread); + + if (thread->active) { + if (thread != current_thread()) { + thread_hold(thread); + + thread_mtx_unlock(thread); + + if (thread_stop(thread, TRUE)) { + thread_mtx_lock(thread); + result = machine_thread_set_tsd_base(thread, tsd_base); + thread_unstop(thread); + } + else { + thread_mtx_lock(thread); + result = KERN_ABORTED; + } + + thread_release(thread); + } + else + result = machine_thread_set_tsd_base(thread, tsd_base); + } + else + result = KERN_TERMINATED; + + thread_mtx_unlock(thread); + + return (result); +} + /* * install_special_handler: * @@ -639,23 +741,14 @@ void install_special_handler_locked( thread_t thread) { - ReturnHandler **rh; - - /* The work handler must always be the last ReturnHandler on the list, - because it can do tricky things like detach the thr_act. */ - for (rh = &thread->handlers; *rh; rh = &(*rh)->next) - continue; - - if (rh != &thread->special_handler.next) - *rh = &thread->special_handler; - + /* * Temporarily undepress, so target has * a chance to do locking required to * block itself in special_handler(). */ - if (thread->sched_mode & TH_MODE_ISDEPRESSED) - compute_priority(thread, TRUE); + if (thread->sched_flags & TH_SFLAG_DEPRESSED_MASK) + thread_recompute_sched_pri(thread, TRUE); thread_ast_set(thread, AST_APC); @@ -673,46 +766,9 @@ install_special_handler_locked( /* * Activation control support routines internal to this file: + * */ -void -act_execute_returnhandlers(void) -{ - thread_t thread = current_thread(); - - thread_ast_clear(thread, AST_APC); - spllo(); - - for (;;) { - ReturnHandler *rh; - - thread_mtx_lock(thread); - - (void)splsched(); - thread_lock(thread); - - rh = thread->handlers; - if (rh != NULL) { - thread->handlers = rh->next; - - thread_unlock(thread); - spllo(); - - thread_mtx_unlock(thread); - - /* Execute it */ - (*rh->handler)(rh, thread); - } - else - break; - } - - thread_unlock(thread); - spllo(); - - thread_mtx_unlock(thread); -} - /* * special_handler_continue * @@ -735,12 +791,11 @@ special_handler_continue(void) spl_t s = splsched(); thread_lock(thread); - if (thread->sched_mode & TH_MODE_ISDEPRESSED) { + if (thread->sched_flags & TH_SFLAG_DEPRESSED_MASK) { processor_t myprocessor = thread->last_processor; thread->sched_pri = DEPRESSPRI; myprocessor->current_pri = thread->sched_pri; - thread->sched_mode &= ~TH_MODE_PREEMPT; } thread_unlock(thread); splx(s); @@ -758,7 +813,6 @@ special_handler_continue(void) */ void special_handler( - __unused ReturnHandler *rh, thread_t thread) { spl_t s; @@ -767,7 +821,7 @@ special_handler( s = splsched(); thread_lock(thread); - thread->state &= ~(TH_ABORT|TH_ABORT_SAFELY); /* clear any aborts */ + thread->sched_flags &= ~TH_SFLAG_ABORTED_MASK; thread_unlock(thread); splx(s); @@ -776,16 +830,9 @@ special_handler( */ if (thread->active) { if (thread->suspend_count > 0) { - if (thread->handlers == NULL) { - assert_wait(&thread->suspend_count, THREAD_ABORTSAFE); - thread_mtx_unlock(thread); - thread_block((thread_continue_t)special_handler_continue); - /*NOTREACHED*/ - } - + assert_wait(&thread->suspend_count, THREAD_ABORTSAFE); thread_mtx_unlock(thread); - - special_handler_continue(); + thread_block((thread_continue_t)special_handler_continue); /*NOTREACHED*/ } } @@ -799,6 +846,14 @@ special_handler( thread_mtx_unlock(thread); } +/* Prototype, see justification above */ +kern_return_t +act_set_state( + thread_t thread, + int flavor, + thread_state_t state, + mach_msg_type_number_t count); + kern_return_t act_set_state( thread_t thread, @@ -813,6 +868,20 @@ act_set_state( } +kern_return_t +act_set_state_from_user( + thread_t thread, + int flavor, + thread_state_t state, + mach_msg_type_number_t count) +{ + if (thread == current_thread()) + return (KERN_INVALID_ARGUMENT); + + return (thread_set_state_from_user(thread, flavor, state, count)); + +} + kern_return_t act_get_state( thread_t thread, @@ -826,54 +895,64 @@ act_get_state( return (thread_get_state(thread, flavor, state, count)); } -void -act_set_astbsd( - thread_t thread) +static void +act_set_ast( + thread_t thread, + ast_t ast) { - spl_t s = splsched(); - + spl_t s = splsched(); + if (thread == current_thread()) { - thread_ast_set(thread, AST_BSD); + thread_ast_set(thread, ast); ast_propagate(thread->ast); - } - else { - processor_t processor; + } else { + processor_t processor; thread_lock(thread); - thread_ast_set(thread, AST_BSD); + thread_ast_set(thread, ast); processor = thread->last_processor; - if ( processor != PROCESSOR_NULL && - processor->state == PROCESSOR_RUNNING && - processor->active_thread == thread ) + if ( processor != PROCESSOR_NULL && + processor->state == PROCESSOR_RUNNING && + processor->active_thread == thread ) cause_ast_check(processor); thread_unlock(thread); } - + splx(s); } void -act_set_apc( +act_set_astbsd( thread_t thread) { - spl_t s = splsched(); - - if (thread == current_thread()) { - thread_ast_set(thread, AST_APC); - ast_propagate(thread->ast); - } - else { - processor_t processor; + act_set_ast( thread, AST_BSD ); +} - thread_lock(thread); - thread_ast_set(thread, AST_APC); - processor = thread->last_processor; - if ( processor != PROCESSOR_NULL && - processor->state == PROCESSOR_RUNNING && - processor->active_thread == thread ) - cause_ast_check(processor); - thread_unlock(thread); - } - - splx(s); +void +act_set_kperf( + thread_t thread) +{ + /* safety check */ + if (thread != current_thread()) + if( !ml_get_interrupts_enabled() ) + panic("unsafe act_set_kperf operation"); + + act_set_ast( thread, AST_KPERF ); } + +#if CONFIG_MACF +void +act_set_astmacf( + thread_t thread) +{ + act_set_ast( thread, AST_MACF); +} +#endif + +void +set_astledger(thread_t thread) +{ + act_set_ast(thread, AST_LEDGER); +} + +