*
* @APPLE_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.
+ * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 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. 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@
*/
#include <kern/task.h>
#include <kern/task_swap.h>
#include <kern/thread_act.h>
-#include <kern/thread_pool.h>
#include <kern/sched_prim.h>
#include <kern/misc_protos.h>
#include <kern/assert.h>
* Track the number of times we need to swapin a thread to deallocate it.
*/
int act_free_swapin = 0;
+boolean_t first_act;
/*
* Forward declarations for functions local to this file.
*/
-kern_return_t act_abort( thread_act_t, int);
+kern_return_t act_abort( thread_act_t, boolean_t);
void special_handler(ReturnHandler *, thread_act_t);
-void nudge(thread_act_t);
kern_return_t act_set_state_locked(thread_act_t, int,
thread_state_t,
mach_msg_type_number_t);
kern_return_t act_get_state_locked(thread_act_t, int,
thread_state_t,
mach_msg_type_number_t *);
+void act_set_astbsd(thread_act_t);
void act_set_apc(thread_act_t);
-void act_clr_apc(thread_act_t);
void act_user_to_kernel(thread_act_t);
void act_ulock_release_all(thread_act_t thr_act);
void install_special_handler_locked(thread_act_t);
+static void act_disable(thread_act_t);
+
+struct thread_activation pageout_act;
+
static zone_t thr_act_zone;
/*
/*
* Internal routine to terminate a thread.
- * Called with task locked.
+ * Sometimes called with task already locked.
*/
kern_return_t
thread_terminate_internal(
- register thread_act_t thr_act)
+ register thread_act_t act)
{
- thread_t thread;
- task_t task;
- struct ipc_port *iplock;
- kern_return_t ret;
+ kern_return_t result;
+ thread_t thread;
-#if THREAD_SWAPPER
- thread_swap_disable(thr_act);
-#endif /* THREAD_SWAPPER */
+ thread = act_lock_thread(act);
- thread = act_lock_thread(thr_act);
- if (!thr_act->active) {
- act_unlock_thread(thr_act);
- return(KERN_TERMINATED);
+ if (!act->active) {
+ act_unlock_thread(act);
+ return (KERN_TERMINATED);
}
- act_disable_task_locked(thr_act);
- ret = act_abort(thr_act,FALSE);
+ act_disable(act);
+ result = act_abort(act, FALSE);
-#if NCPUS > 1
/*
* Make sure this thread enters the kernel
+ * Must unlock the act, but leave the shuttle
+ * captured in this act.
*/
if (thread != current_thread()) {
- thread_hold(thr_act);
- act_unlock_thread(thr_act);
+ act_unlock(act);
- if (thread_stop_wait(thread))
+ if (thread_stop(thread))
thread_unstop(thread);
else
- ret = KERN_ABORTED;
+ result = KERN_ABORTED;
- (void)act_lock_thread(thr_act);
- thread_release(thr_act);
+ act_lock(act);
}
-#endif /* NCPUS > 1 */
- act_unlock_thread(thr_act);
- return(ret);
+ clear_wait(thread, act->inited? THREAD_INTERRUPTED: THREAD_AWAKENED);
+ act_unlock_thread(act);
+
+ return (result);
}
/*
- * Terminate a thread. Called with nothing locked.
- * Returns same way.
+ * Terminate a thread.
*/
kern_return_t
thread_terminate(
- register thread_act_t thr_act)
+ register thread_act_t act)
{
- task_t task;
- kern_return_t ret;
+ kern_return_t result;
- if (thr_act == THR_ACT_NULL)
- return KERN_INVALID_ARGUMENT;
+ if (act == THR_ACT_NULL)
+ return (KERN_INVALID_ARGUMENT);
- task = thr_act->task;
- if (((task == kernel_task) || (thr_act->kernel_loaded == TRUE))
- && (current_act() != thr_act)) {
- return(KERN_FAILURE);
- }
+ if ( (act->task == kernel_task ||
+ act->kernel_loaded ) &&
+ act != current_act() )
+ return (KERN_FAILURE);
- /*
- * Take the task lock and then call the internal routine
- * that terminates a thread (it needs the task locked).
- */
- task_lock(task);
- ret = thread_terminate_internal(thr_act);
- task_unlock(task);
+ result = thread_terminate_internal(act);
/*
* If a kernel thread is terminating itself, force an AST here.
* code - and all threads finish their own termination in the
* special handler APC.
*/
- if ( ( thr_act->task == kernel_task ||
- thr_act->kernel_loaded == TRUE ) &&
- current_act() == thr_act ) {
+ if ( act->task == kernel_task ||
+ act->kernel_loaded ) {
+ assert(act == current_act());
ast_taken(AST_APC, FALSE);
- panic("thread_terminate(): returning from ast_taken() for %x kernel activation\n", thr_act);
- }
+ panic("thread_terminate");
+ }
- return ret;
+ return (result);
}
/*
- * thread_hold:
+ * Suspend execution of the specified thread.
+ * This is a recursive-style suspension of the thread, a count of
+ * suspends is maintained.
*
- * Suspend execution of the specified thread.
- * This is a recursive-style suspension of the thread, a count of
- * suspends is maintained.
- *
- * Called with thr_act locked "appropriately" for synchrony with
- * RPC (see act_lock_thread()). Returns same way.
+ * Called with act_lock held.
*/
void
thread_hold(
- register thread_act_t thr_act)
+ register thread_act_t act)
{
- if (thr_act->suspend_count++ == 0) {
- install_special_handler(thr_act);
- nudge(thr_act);
+ thread_t thread = act->thread;
+
+ if (act->suspend_count++ == 0) {
+ install_special_handler(act);
+ if ( act->inited &&
+ thread != THREAD_NULL &&
+ thread->top_act == act )
+ thread_wakeup_one(&act->suspend_count);
}
}
* Decrement internal suspension count for thr_act, setting thread
* runnable when count falls to zero.
*
- * Called with thr_act locked "appropriately" for synchrony
- * with RPC (see act_lock_thread()).
+ * Called with act_lock held.
*/
void
thread_release(
- register thread_act_t thr_act)
+ register thread_act_t act)
{
- if( thr_act->suspend_count &&
- (--thr_act->suspend_count == 0) )
- nudge( thr_act );
+ thread_t thread = act->thread;
+
+ if ( act->suspend_count > 0 &&
+ --act->suspend_count == 0 &&
+ thread != THREAD_NULL &&
+ thread->top_act == act ) {
+ if (!act->inited) {
+ clear_wait(thread, THREAD_AWAKENED);
+ act->inited = TRUE;
+ }
+ else
+ thread_wakeup_one(&act->suspend_count);
+ }
}
kern_return_t
thread_suspend(
- register thread_act_t thr_act)
+ register thread_act_t act)
{
- thread_t thread;
+ thread_t thread;
- if (thr_act == THR_ACT_NULL) {
- return(KERN_INVALID_ARGUMENT);
- }
- thread = act_lock_thread(thr_act);
- if (!thr_act->active) {
- act_unlock_thread(thr_act);
- return(KERN_TERMINATED);
+ if (act == THR_ACT_NULL)
+ return (KERN_INVALID_ARGUMENT);
+
+ thread = act_lock_thread(act);
+
+ if (!act->active) {
+ act_unlock_thread(act);
+ return (KERN_TERMINATED);
}
- if (thr_act->user_stop_count++ == 0 &&
- thr_act->suspend_count++ == 0 ) {
- install_special_handler(thr_act);
- if (thread &&
- thr_act == thread->top_act && thread != current_thread()) {
- nudge(thr_act);
- act_unlock_thread(thr_act);
- (void)thread_wait(thread);
- }
- else {
- /*
- * No need to wait for target thread
- */
- act_unlock_thread(thr_act);
+
+ if ( act->user_stop_count++ == 0 &&
+ act->suspend_count++ == 0 ) {
+ install_special_handler(act);
+ if ( thread != current_thread() &&
+ thread != THREAD_NULL &&
+ thread->top_act == act ) {
+ assert(act->inited);
+ thread_wakeup_one(&act->suspend_count);
+ act_unlock_thread(act);
+
+ thread_wait(thread);
}
+ else
+ act_unlock_thread(act);
}
- else {
- /*
- * Thread is already suspended
- */
- act_unlock_thread(thr_act);
- }
- return(KERN_SUCCESS);
+ else
+ act_unlock_thread(act);
+
+ return (KERN_SUCCESS);
}
kern_return_t
thread_resume(
- register thread_act_t thr_act)
+ register thread_act_t act)
{
- register kern_return_t ret;
- spl_t s;
+ kern_return_t result = KERN_SUCCESS;
thread_t thread;
- if (thr_act == THR_ACT_NULL)
- return(KERN_INVALID_ARGUMENT);
- thread = act_lock_thread(thr_act);
- ret = KERN_SUCCESS;
+ if (act == THR_ACT_NULL)
+ return (KERN_INVALID_ARGUMENT);
- if (thr_act->active) {
- if (thr_act->user_stop_count > 0) {
- if( --thr_act->user_stop_count == 0 ) {
- --thr_act->suspend_count;
- nudge( thr_act );
+ thread = act_lock_thread(act);
+
+ if (act->active) {
+ if (act->user_stop_count > 0) {
+ if ( --act->user_stop_count == 0 &&
+ --act->suspend_count == 0 &&
+ thread != THREAD_NULL &&
+ thread->top_act == act ) {
+ if (!act->inited) {
+ clear_wait(thread, THREAD_AWAKENED);
+ act->inited = TRUE;
+ }
+ else
+ thread_wakeup_one(&act->suspend_count);
}
}
else
- ret = KERN_FAILURE;
+ result = KERN_FAILURE;
}
else
- ret = KERN_TERMINATED;
- act_unlock_thread( thr_act );
- return ret;
+ result = KERN_TERMINATED;
+
+ act_unlock_thread(act);
+
+ return (result);
}
/*
*/
kern_return_t
post_alert(
- register thread_act_t thr_act,
- unsigned alert_bits )
+ register thread_act_t act,
+ unsigned alert_bits)
{
- thread_act_t next;
- thread_t thread;
-
- /*
- * Chase the chain, setting alert bits and installing
- * special handlers for each thread act.
- */
- /*** Not yet SMP safe ***/
- /*** Worse, where's the activation locking as the chain is walked? ***/
- for (next = thr_act; next != THR_ACT_NULL; next = next->higher) {
- next->alerts |= alert_bits;
- install_special_handler_locked(next);
- }
-
- return(KERN_SUCCESS);
+ panic("post_alert");
}
/*
/*
- * Already locked: all RPC-related locks for thr_act (see
- * act_lock_thread()).
+ * Indicate that the activation should run its
+ * special handler to detect the condition.
+ *
+ * Called with act_lock held.
*/
kern_return_t
-act_abort( thread_act_t thr_act, int chain_break )
+act_abort(
+ thread_act_t act,
+ boolean_t chain_break )
{
- spl_t spl;
- thread_t thread;
- struct ipc_port *iplock = thr_act->pool_port;
- thread_act_t orphan;
- kern_return_t kr;
- etap_data_t probe_data;
-
- ETAP_DATA_LOAD(probe_data[0], thr_act);
- ETAP_DATA_LOAD(probe_data[1], thr_act->thread);
- ETAP_PROBE_DATA(ETAP_P_ACT_ABORT,
- 0,
- current_thread(),
- &probe_data,
- ETAP_DATA_ENTRY*2);
+ thread_t thread = act->thread;
+ spl_t s = splsched();
- /*
- * If the target thread activation is not the head...
- */
- if ( thr_act->thread->top_act != thr_act ) {
- /*
- * mark the activation for abort,
- * update the suspend count,
- * always install the special handler
- */
- install_special_handler(thr_act);
-
-#ifdef AGRESSIVE_ABORT
- /* release state buffer for target's outstanding invocation */
- if (unwind_invoke_state(thr_act) != KERN_SUCCESS) {
- panic("unwind_invoke_state failure");
- }
+ assert(thread->top_act == act);
- /* release state buffer for target's incoming invocation */
- if (thr_act->lower != THR_ACT_NULL) {
- if (unwind_invoke_state(thr_act->lower)
- != KERN_SUCCESS) {
- panic("unwind_invoke_state failure");
- }
- }
-
- /* unlink target thread activation from shuttle chain */
- if ( thr_act->lower == THR_ACT_NULL ) {
- /*
- * This is the root thread activation of the chain.
- * Unlink the root thread act from the bottom of
- * the chain.
- */
- thr_act->higher->lower = THR_ACT_NULL;
- } else {
- /*
- * This thread act is in the middle of the chain.
- * Unlink the thread act from the middle of the chain.
- */
- thr_act->higher->lower = thr_act->lower;
- thr_act->lower->higher = thr_act->higher;
-
- /* set the terminated bit for RPC return processing */
- thr_act->lower->alerts |= SERVER_TERMINATED;
- }
-
- orphan = thr_act->higher;
-
- /* remove the activation from its thread pool */
- /* (note: this is okay for "rooted threads," too) */
- act_locked_act_set_thread_pool(thr_act, IP_NULL);
-
- /* (just to be thorough) release the IP lock */
- if (iplock != IP_NULL) ip_unlock(iplock);
-
- /* release one more reference for a rooted thread */
- if (iplock == IP_NULL) act_locked_act_deallocate(thr_act);
-
- /* Presumably, the only reference to this activation is
- * now held by the caller of this routine. */
- assert(thr_act->ref_count == 1);
-#else /*AGRESSIVE_ABORT*/
- /* If there is a lower activation in the RPC chain... */
- if (thr_act->lower != THR_ACT_NULL) {
- /* ...indicate the server activation was terminated */
- thr_act->lower->alerts |= SERVER_TERMINATED;
- }
- /* Mark (and process) any orphaned activations */
- orphan = thr_act->higher;
-#endif /*AGRESSIVE_ABORT*/
-
- /* indicate client of orphaned chain has been terminated */
- orphan->alerts |= CLIENT_TERMINATED;
-
- /*
- * Set up posting of alert to headward portion of
- * the RPC chain.
- */
- /*** fix me -- orphan act is not locked ***/
- post_alert(orphan, ORPHANED);
-
- /*
- * Get attention of head of RPC chain.
- */
- nudge(thr_act->thread->top_act);
- return (KERN_SUCCESS);
+ thread_lock(thread);
+ if (!(thread->state & TH_ABORT)) {
+ thread->state |= TH_ABORT;
+ install_special_handler_locked(act);
+ } else {
+ thread->state &= ~TH_ABORT_SAFELY;
}
+ thread_unlock(thread);
+ splx(s);
- /*
- * If the target thread is the end of the chain, the thread
- * has to be marked for abort and rip it out of any wait.
- */
- spl = splsched();
- thread_lock(thr_act->thread);
- if (thr_act->thread->top_act == thr_act) {
- thr_act->thread->state |= TH_ABORT;
- clear_wait_internal(thr_act->thread, THREAD_INTERRUPTED);
- thread_unlock(thr_act->thread);
- splx(spl);
- install_special_handler(thr_act);
- nudge( thr_act );
- }
- return KERN_SUCCESS;
+ return (KERN_SUCCESS);
}
kern_return_t
thread_abort(
- register thread_act_t thr_act)
+ register thread_act_t act)
{
- int ret;
+ kern_return_t result;
thread_t thread;
- if (thr_act == THR_ACT_NULL || thr_act == current_act())
+ if (act == THR_ACT_NULL)
return (KERN_INVALID_ARGUMENT);
- /*
- * Lock the target thread and the current thread now,
- * in case thread_halt() ends up being called below.
- */
- thread = act_lock_thread(thr_act);
- if (!thr_act->active) {
- act_unlock_thread(thr_act);
- return(KERN_TERMINATED);
+
+ thread = act_lock_thread(act);
+
+ if (!act->active) {
+ act_unlock_thread(act);
+ return (KERN_TERMINATED);
}
- ret = act_abort( thr_act, FALSE );
- act_unlock_thread( thr_act );
- return ret;
+ result = act_abort(act, FALSE);
+ clear_wait(thread, THREAD_INTERRUPTED);
+ act_unlock_thread(act);
+
+ return (result);
}
kern_return_t
thread_abort_safely(
- register thread_act_t thr_act)
+ thread_act_t act)
{
thread_t thread;
+ kern_return_t ret;
spl_t s;
- if (thr_act == THR_ACT_NULL || thr_act == current_act())
- return(KERN_INVALID_ARGUMENT);
+ if ( act == THR_ACT_NULL )
+ return (KERN_INVALID_ARGUMENT);
- thread = act_lock_thread(thr_act);
- if (!thr_act->active) {
- act_unlock_thread(thr_act);
- return(KERN_TERMINATED);
- }
- if (thread->top_act != thr_act) {
- act_unlock_thread(thr_act);
- return(KERN_FAILURE);
+ thread = act_lock_thread(act);
+
+ if (!act->active) {
+ act_unlock_thread(act);
+ return (KERN_TERMINATED);
}
+
s = splsched();
thread_lock(thread);
-
- if ( thread->at_safe_point ) {
- /*
- * It's an abortable wait, clear it, then
- * let the thread go and return successfully.
- */
- clear_wait_internal(thread, THREAD_INTERRUPTED);
- thread_unlock(thread);
- act_unlock_thread(thr_act);
- splx(s);
- return KERN_SUCCESS;
+ 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);
+ install_special_handler_locked(act);
+ }
}
-
- /*
- * if not stopped at a safepoint, just let it go and return failure.
- */
thread_unlock(thread);
- act_unlock_thread(thr_act);
splx(s);
- return KERN_FAILURE;
+
+ act_unlock_thread(act);
+
+ return (KERN_SUCCESS);
}
/*** backward compatibility hacks ***/
*/
kern_return_t
thread_get_state(
- register thread_act_t thr_act,
- int flavor,
- thread_state_t state, /* pointer to OUT array */
+ register thread_act_t act,
+ int flavor,
+ thread_state_t state, /* pointer to OUT array */
mach_msg_type_number_t *state_count) /*IN/OUT*/
{
- kern_return_t ret;
- thread_t thread, nthread;
+ kern_return_t result = KERN_SUCCESS;
+ thread_t thread;
- if (thr_act == THR_ACT_NULL || thr_act == current_act())
+ if (act == THR_ACT_NULL || act == current_act())
return (KERN_INVALID_ARGUMENT);
- thread = act_lock_thread(thr_act);
- if (!thr_act->active) {
- act_unlock_thread(thr_act);
- return(KERN_TERMINATED);
+ thread = act_lock_thread(act);
+
+ if (!act->active) {
+ act_unlock_thread(act);
+ return (KERN_TERMINATED);
}
- thread_hold(thr_act);
- while (1) {
- if (!thread || thr_act != thread->top_act)
+ thread_hold(act);
+
+ for (;;) {
+ thread_t thread1;
+
+ if ( thread == THREAD_NULL ||
+ thread->top_act != act )
break;
- act_unlock_thread(thr_act);
- (void)thread_stop_wait(thread);
- nthread = act_lock_thread(thr_act);
- if (nthread == thread)
+ act_unlock_thread(act);
+
+ if (!thread_stop(thread)) {
+ result = KERN_ABORTED;
+ (void)act_lock_thread(act);
+ thread = THREAD_NULL;
+ break;
+ }
+
+ thread1 = act_lock_thread(act);
+ if (thread1 == thread)
break;
+
thread_unstop(thread);
- thread = nthread;
+ thread = thread1;
}
- ret = act_machine_get_state(thr_act, flavor,
- state, state_count);
- if (thread && thr_act == thread->top_act)
- thread_unstop(thread);
- thread_release(thr_act);
- act_unlock_thread(thr_act);
- return(ret);
+ if (result == KERN_SUCCESS)
+ result = act_machine_get_state(act, flavor, state, state_count);
+
+ if ( thread != THREAD_NULL &&
+ thread->top_act == act )
+ thread_unstop(thread);
+
+ thread_release(act);
+ act_unlock_thread(act);
+
+ return (result);
}
/*
*/
kern_return_t
thread_set_state(
- register thread_act_t thr_act,
- int flavor,
- thread_state_t state,
+ register thread_act_t act,
+ int flavor,
+ thread_state_t state,
mach_msg_type_number_t state_count)
{
- kern_return_t ret;
- thread_t thread, nthread;
+ kern_return_t result = KERN_SUCCESS;
+ thread_t thread;
- if (thr_act == THR_ACT_NULL || thr_act == current_act())
+ if (act == THR_ACT_NULL || act == current_act())
return (KERN_INVALID_ARGUMENT);
- /*
- * We have no kernel activations, so Utah's MO fails for signals etc.
- *
- * If we're blocked in the kernel, use non-blocking method, else
- * pass locked thr_act+thread in to "normal" act_[gs]et_state().
- */
- thread = act_lock_thread(thr_act);
- if (!thr_act->active) {
- act_unlock_thread(thr_act);
- return(KERN_TERMINATED);
+ thread = act_lock_thread(act);
+
+ if (!act->active) {
+ act_unlock_thread(act);
+ return (KERN_TERMINATED);
}
- thread_hold(thr_act);
- while (1) {
- if (!thread || thr_act != thread->top_act)
+ thread_hold(act);
+
+ for (;;) {
+ thread_t thread1;
+
+ if ( thread == THREAD_NULL ||
+ thread->top_act != act )
break;
- act_unlock_thread(thr_act);
- (void)thread_stop_wait(thread);
- nthread = act_lock_thread(thr_act);
- if (nthread == thread)
+ act_unlock_thread(act);
+
+ if (!thread_stop(thread)) {
+ result = KERN_ABORTED;
+ (void)act_lock_thread(act);
+ thread = THREAD_NULL;
break;
+ }
+
+ thread1 = act_lock_thread(act);
+ if (thread1 == thread)
+ break;
+
thread_unstop(thread);
- thread = nthread;
+ thread = thread1;
}
- ret = act_machine_set_state(thr_act, flavor,
- state, state_count);
- if (thread && thr_act == thread->top_act)
+
+ if (result == KERN_SUCCESS)
+ result = act_machine_set_state(act, flavor, state, state_count);
+
+ if ( thread != THREAD_NULL &&
+ thread->top_act == act )
thread_unstop(thread);
- thread_release(thr_act);
- act_unlock_thread(thr_act);
- return(ret);
+ thread_release(act);
+ act_unlock_thread(act);
+
+ return (result);
}
/*
kern_return_t
thread_dup(
- thread_act_t source_thr_act,
- thread_act_t target_thr_act)
+ register thread_act_t target)
{
- kern_return_t ret;
- thread_t thread, nthread;
+ kern_return_t result = KERN_SUCCESS;
+ thread_act_t self = current_act();
+ thread_t thread;
- if (target_thr_act == THR_ACT_NULL || target_thr_act == current_act())
+ if (target == THR_ACT_NULL || target == self)
return (KERN_INVALID_ARGUMENT);
- thread = act_lock_thread(target_thr_act);
- if (!target_thr_act->active) {
- act_unlock_thread(target_thr_act);
- return(KERN_TERMINATED);
+ thread = act_lock_thread(target);
+
+ if (!target->active) {
+ act_unlock_thread(target);
+ return (KERN_TERMINATED);
}
- thread_hold(target_thr_act);
- while (1) {
- if (!thread || target_thr_act != thread->top_act)
+ thread_hold(target);
+
+ for (;;) {
+ thread_t thread1;
+
+ if ( thread == THREAD_NULL ||
+ thread->top_act != target )
+ break;
+ act_unlock_thread(target);
+
+ if (!thread_stop(thread)) {
+ result = KERN_ABORTED;
+ (void)act_lock_thread(target);
+ thread = THREAD_NULL;
break;
- act_unlock_thread(target_thr_act);
- (void)thread_stop_wait(thread);
- nthread = act_lock_thread(target_thr_act);
- if (nthread == thread)
+ }
+
+ thread1 = act_lock_thread(target);
+ if (thread1 == thread)
break;
+
thread_unstop(thread);
- thread = nthread;
+ thread = thread1;
}
- ret = act_thread_dup(source_thr_act, target_thr_act);
- if (thread && target_thr_act == thread->top_act)
+
+ if (result == KERN_SUCCESS)
+ result = act_thread_dup(self, target);
+
+ if ( thread != THREAD_NULL &&
+ thread->top_act == target )
thread_unstop(thread);
- thread_release(target_thr_act);
- act_unlock_thread(target_thr_act);
- return(ret);
+ thread_release(target);
+ act_unlock_thread(target);
+
+ return (result);
}
*/
kern_return_t
thread_setstatus(
- thread_act_t thr_act,
- int flavor,
- thread_state_t tstate,
+ register thread_act_t act,
+ int flavor,
+ thread_state_t tstate,
mach_msg_type_number_t count)
{
- kern_return_t kr;
- thread_t thread;
+ kern_return_t result = KERN_SUCCESS;
+ thread_t thread;
- thread = act_lock_thread(thr_act);
- assert(thread);
- assert(thread->top_act == thr_act);
- kr = act_machine_set_state(thr_act, flavor, tstate, count);
- act_unlock_thread(thr_act);
- return(kr);
+ thread = act_lock_thread(act);
+
+ if ( act != current_act() &&
+ (act->suspend_count == 0 ||
+ thread == THREAD_NULL ||
+ (thread->state & TH_RUN) ||
+ thread->top_act != act) )
+ result = KERN_FAILURE;
+
+ if (result == KERN_SUCCESS)
+ result = act_machine_set_state(act, flavor, tstate, count);
+
+ act_unlock_thread(act);
+
+ return (result);
}
/*
*/
kern_return_t
thread_getstatus(
- thread_act_t thr_act,
- int flavor,
- thread_state_t tstate,
+ register thread_act_t act,
+ int flavor,
+ thread_state_t tstate,
mach_msg_type_number_t *count)
{
- kern_return_t kr;
- thread_t thread;
+ kern_return_t result = KERN_SUCCESS;
+ thread_t thread;
- thread = act_lock_thread(thr_act);
- assert(thread);
- assert(thread->top_act == thr_act);
- kr = act_machine_get_state(thr_act, flavor, tstate, count);
- act_unlock_thread(thr_act);
- return(kr);
+ thread = act_lock_thread(act);
+
+ if ( act != current_act() &&
+ (act->suspend_count == 0 ||
+ thread == THREAD_NULL ||
+ (thread->state & TH_RUN) ||
+ thread->top_act != act) )
+ result = KERN_FAILURE;
+
+ if (result == KERN_SUCCESS)
+ result = act_machine_get_state(act, flavor, tstate, count);
+
+ act_unlock_thread(act);
+
+ return (result);
}
/*
ACT_MAX * sizeof(struct thread_activation), /* XXX */
ACT_CHUNK * sizeof(struct thread_activation),
"activations");
+ first_act = TRUE;
act_machine_init();
}
int rc;
vm_map_t map;
- thr_act = (thread_act_t)zalloc(thr_act_zone);
+ if (first_act) {
+ thr_act = &pageout_act;
+ first_act = FALSE;
+ } else
+ thr_act = (thread_act_t)zalloc(thr_act_zone);
if (thr_act == 0)
return(KERN_RESOURCE_SHORTAGE);
/* Start by zeroing everything; then init non-zero items only */
bzero((char *)thr_act, sizeof(*thr_act));
+ if (thr_act == &pageout_act)
+ thr_act->thread = &pageout_thread;
+
#ifdef MACH_BSD
{
/*
* handling trivial
* uthread_alloc() will bzero the storage allocated.
*/
- extern void *uthread_alloc(void);
- thr_act->uthread = uthread_alloc();
+ extern void *uthread_alloc(task_t, thread_act_t);
+
+ thr_act->uthread = uthread_alloc(task, thr_act);
if(thr_act->uthread == 0) {
/* Put the thr_act back on the thr_act zone */
zfree(thr_act_zone, (vm_offset_t)thr_act);
thr_act->task = task;
task_reference(task);
- /* Initialize sigbufp for High-Watermark buffer allocation */
- thr_act->r_sigbufp = (routine_descriptor_t) &thr_act->r_sigbuf;
- thr_act->r_sigbuf_size = sizeof(thr_act->r_sigbuf);
-
-#if THREAD_SWAPPER
- thr_act->swap_state = TH_SW_IN;
-#if MACH_ASSERT
- thr_act->kernel_stack_swapped_in = TRUE;
-#endif /* MACH_ASSERT */
-#endif /* THREAD_SWAPPER */
-
/* special_handler will always be last on the returnhandlers list. */
thr_act->special_handler.next = 0;
thr_act->special_handler.handler = special_handler;
/* Inline vm_map_reference cause we don't want to increment res_count */
mutex_lock(&map->s_lock);
-#if TASK_SWAPPER
- assert(map->res_count > 0);
- assert(map->ref_count >= map->res_count);
-#endif /* TASK_SWAPPER */
map->ref_count++;
mutex_unlock(&map->s_lock);
thread_t thr;
vm_map_t map;
unsigned int ref;
+ void * task_proc;
#if MACH_ASSERT
if (watchacts & WA_EXIT)
- printf("act_free(%x(%d)) thr=%x tsk=%x(%d) pport=%x%sactive\n",
+ printf("act_free(%x(%d)) thr=%x tsk=%x(%d) %sactive\n",
thr_act, thr_act->ref_count, thr_act->thread,
thr_act->task,
thr_act->task ? thr_act->task->ref_count : 0,
- thr_act->pool_port,
thr_act->active ? " " : " !");
#endif /* MACH_ASSERT */
-
-#if THREAD_SWAPPER
- assert(thr_act->kernel_stack_swapped_in);
-#endif /* THREAD_SWAPPER */
-
assert(!thr_act->active);
- assert(!thr_act->pool_port);
task = thr_act->task;
task_lock(task);
+ task_proc = task->bsd_info;
if (thr = thr_act->thread) {
time_value_t user_time, system_time;
queue_remove(&task->thr_acts, thr_act, thread_act_t, thr_acts);
thr_act->thr_acts.next = NULL;
task->thr_act_count--;
-
-#if THREAD_SWAPPER
- /*
- * Thread is supposed to be unswappable by now...
- */
- assert(thr_act->swap_state == TH_SW_UNSWAPPABLE ||
- !thread_swap_unwire_stack);
-#endif /* THREAD_SWAPPER */
-
task->res_act_count--;
task_unlock(task);
task_deallocate(task);
task_deallocate(task);
}
- sigbuf_dealloc(thr_act);
act_prof_deallocate(thr_act);
ipc_thr_act_terminate(thr_act);
*/
map = thr_act->map;
mutex_lock(&map->s_lock);
-#if TASK_SWAPPER
- assert(map->res_count >= 0);
- assert(map->ref_count > map->res_count);
-#endif /* TASK_SWAPPER */
ref = --map->ref_count;
mutex_unlock(&map->s_lock);
if (ref == 0)
* Free uthread BEFORE the bzero.
* Not doing so will result in a leak.
*/
- extern void uthread_free(void *);
+ extern void uthread_free(task_t, void *, void *);
+
void *ut = thr_act->uthread;
thr_act->uthread = 0;
- uthread_free(ut);
+ uthread_free(task, ut, task_proc);
}
#endif /* MACH_BSD */
* act_attach - Attach an thr_act to the top of a thread ("push the stack").
*
* The thread_shuttle must be either the current one or a brand-new one.
- * Assumes the thr_act is active but not in use, also, that if it is
- * attached to an thread_pool (i.e. the thread_pool pointer is nonzero),
- * the thr_act has already been taken off the thread_pool's list.
+ * Assumes the thr_act is active but not in use.
*
* Already locked: thr_act plus "appropriate" thread-related locks
* (see act_lock_thread()).
cur_act->ref_count--;
assert(cur_act->ref_count > 0);
- thread_pool_put_act(cur_act);
-
#if MACH_ASSERT
cur_act->lower = cur_act->higher = THR_ACT_NULL;
if (cur_thread->top_act)
/*
- * Synchronize a thread operation with RPC. Called with nothing
- * locked. Returns with thr_act locked, plus one of four
- * combinations of other locks held:
- * none - for new activation not yet associated with thread_pool
- * or shuttle
- * rpc_lock(thr_act->thread) only - for base activation (one
- * without pool_port)
- * ip_lock(thr_act->pool_port) only - for empty activation (one
- * with no associated shuttle)
- * both locks - for "active" activation (has shuttle, lives
- * on thread_pool)
- * If thr_act has an associated shuttle, this function returns
- * its address. Otherwise it returns zero.
+ * Synchronize a thread operation with migration.
+ * Called with nothing locked.
+ * Returns with thr_act locked.
*/
thread_t
act_lock_thread(
thread_act_t thr_act)
{
- ipc_port_t pport;
/*
- * Allow the shuttle cloning code (q.v., when it
- * exists :-}) to obtain ip_lock()'s while holding
- * an rpc_lock().
+ * JMM - We have moved away from explicit RPC locks
+ * and towards a generic migration approach. The wait
+ * queue lock will be the point of synchronization for
+ * the shuttle linkage when this is rolled out. Until
+ * then, just lock the act.
*/
- while (1) {
- act_lock(thr_act);
- pport = thr_act->pool_port;
- if (!pport || ip_lock_try(pport)) {
- if (!thr_act->thread)
- break;
- if (rpc_lock_try(thr_act->thread))
- break;
- if (pport)
- ip_unlock(pport);
- }
- act_unlock(thr_act);
- mutex_pause();
- }
+ act_lock(thr_act);
return (thr_act->thread);
}
/*
- * Unsynchronize with RPC (i.e., undo an act_lock_thread() call).
+ * Unsynchronize with migration (i.e., undo an act_lock_thread() call).
* Called with thr_act locked, plus thread locks held that are
* "correct" for thr_act's state. Returns with nothing locked.
*/
void
act_unlock_thread(thread_act_t thr_act)
{
- if (thr_act->thread)
- rpc_unlock(thr_act->thread);
- if (thr_act->pool_port)
- ip_unlock(thr_act->pool_port);
act_unlock(thr_act);
}
/*
- * Synchronize with RPC given a pointer to a shuttle (instead of an
+ * Synchronize with migration given a pointer to a shuttle (instead of an
* activation). Called with nothing locked; returns with all
* "appropriate" thread-related locks held (see act_lock_thread()).
*/
thread_act_t thr_act;
while (1) {
- rpc_lock(thread);
thr_act = thread->top_act;
if (!thr_act)
break;
if (!act_lock_try(thr_act)) {
- rpc_unlock(thread);
- mutex_pause();
- continue;
- }
- if (thr_act->pool_port &&
- !ip_lock_try(thr_act->pool_port)) {
- rpc_unlock(thread);
- act_unlock(thr_act);
mutex_pause();
continue;
}
}
/*
- * Unsynchronize with RPC starting from a pointer to a shuttle.
- * Called with RPC-related locks held that are appropriate to
- * shuttle's state; any activation is also locked.
+ * Unsynchronize with an activation starting from a pointer to
+ * a shuttle.
*/
void
thread_unlock_act(
thread_act_t thr_act;
if (thr_act = thread->top_act) {
- if (thr_act->pool_port)
- ip_unlock(thr_act->pool_port);
act_unlock(thr_act);
}
- rpc_unlock(thread);
}
/*
*
* If a new activation is given, switch to it. If not,
* switch to the lower activation (pop). Returns the old
- * activation. This is for RPC support.
+ * activation. This is for migration support.
*/
thread_act_t
switch_act(
}
assert(new != THR_ACT_NULL);
-#if THREAD_SWAPPER
- assert(new->swap_state != TH_SW_OUT &&
- new->swap_state != TH_SW_COMING_IN);
-#endif /* THREAD_SWAPPER */
-
- assert(cpu_data[cpu].active_thread == thread);
+ assert(cpu_to_processor(cpu)->cpu_data->active_thread == thread);
active_kloaded[cpu] = (new->kernel_loaded) ? new : 0;
/* This is where all the work happens */
*/
void
install_special_handler_locked(
- thread_act_t thr_act)
+ thread_act_t act)
{
+ thread_t thread = act->thread;
ReturnHandler **rh;
- thread_t thread = thr_act->thread;
/* 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 = &thr_act->handlers; *rh; rh = &(*rh)->next)
- /* */ ;
- if (rh != &thr_act->special_handler.next) {
- *rh = &thr_act->special_handler;
- }
- if (thread && thr_act == thread->top_act) {
+ for (rh = &act->handlers; *rh; rh = &(*rh)->next)
+ continue;
+ if (rh != &act->special_handler.next)
+ *rh = &act->special_handler;
+
+ if (act == thread->top_act) {
/*
* Temporarily undepress, so target has
* a chance to do locking required to
* block itself in special_handler().
*/
- if (thread->depress_priority >= 0) {
- thread->priority = thread->depress_priority;
-
- /*
- * Use special value -2 to indicate need
- * to redepress priority in special_handler
- * as thread blocks
- */
- thread->depress_priority = -2;
- compute_priority(thread, FALSE);
- }
+ if (thread->sched_mode & TH_MODE_ISDEPRESSED)
+ compute_priority(thread, TRUE);
}
- act_set_apc(thr_act);
-}
-/*
- * JMM -
- * These two routines will be enhanced over time to call the general handler registration
- * mechanism used by special handlers and alerts. They are hack in for now to avoid
- * having to export the gory details of ASTs to the BSD code right now.
- */
-extern thread_apc_handler_t bsd_ast;
+ thread_ast_set(act, AST_APC);
+ if (act == current_act())
+ ast_propagate(act->ast);
+ else {
+ processor_t processor = thread->last_processor;
+
+ if ( processor != PROCESSOR_NULL &&
+ processor->state == PROCESSOR_RUNNING &&
+ processor->cpu_data->active_thread == thread )
+ cause_ast_check(processor);
+ }
+}
kern_return_t
thread_apc_set(
- thread_act_t thr_act,
- thread_apc_handler_t apc)
+ thread_act_t act,
+ thread_apc_handler_t apc)
{
+ extern thread_apc_handler_t bsd_ast;
+
assert(apc == bsd_ast);
- thread_ast_set(thr_act, AST_BSD);
- if (thr_act == current_act())
- ast_propagate(thr_act->ast);
- return KERN_SUCCESS;
+ return (KERN_FAILURE);
}
kern_return_t
thread_apc_clear(
- thread_act_t thr_act,
- thread_apc_handler_t apc)
+ thread_act_t act,
+ thread_apc_handler_t apc)
{
- assert(apc == bsd_ast);
- thread_ast_clear(thr_act, AST_BSD);
- if (thr_act == current_act())
- ast_off(AST_BSD);
- return KERN_SUCCESS;
-}
-
-/*
- * act_set_thread_pool - Assign an activation to a specific thread_pool.
- * Fails if the activation is already assigned to another pool.
- * If thread_pool == 0, we remove the thr_act from its thread_pool.
- *
- * Called the port containing thread_pool already locked.
- * Returns the same way.
- */
-kern_return_t act_set_thread_pool(
- thread_act_t thr_act,
- ipc_port_t pool_port)
-{
- thread_pool_t thread_pool;
-
-#if MACH_ASSERT
- if (watchacts & WA_ACT_LNK)
- printf("act_set_thread_pool: %x(%d) -> %x\n",
- thr_act, thr_act->ref_count, thread_pool);
-#endif /* MACH_ASSERT */
-
- if (pool_port == 0) {
- thread_act_t *lact;
-
- if (thr_act->pool_port == 0)
- return KERN_SUCCESS;
- thread_pool = &thr_act->pool_port->ip_thread_pool;
-
- for (lact = &thread_pool->thr_acts; *lact;
- lact = &((*lact)->thread_pool_next)) {
- if (thr_act == *lact) {
- *lact = thr_act->thread_pool_next;
- break;
- }
- }
- act_lock(thr_act);
- thr_act->pool_port = 0;
- thr_act->thread_pool_next = 0;
- act_unlock(thr_act);
- act_deallocate(thr_act);
- return KERN_SUCCESS;
- }
- if (thr_act->pool_port != pool_port) {
- thread_pool = &pool_port->ip_thread_pool;
- if (thr_act->pool_port != 0) {
-#if MACH_ASSERT
- if (watchacts & WA_ACT_LNK)
- printf("act_set_thread_pool found %x!\n",
- thr_act->pool_port);
-#endif /* MACH_ASSERT */
- return(KERN_FAILURE);
- }
- act_lock(thr_act);
- thr_act->pool_port = pool_port;
-
- /* The pool gets a ref to the activation -- have
- * to inline operation because thr_act is already
- * locked.
- */
- act_locked_act_reference(thr_act);
-
- /* If it is available,
- * add it to the thread_pool's available-activation list.
- */
- if ((thr_act->thread == 0) && (thr_act->suspend_count == 0)) {
- thr_act->thread_pool_next = thread_pool->thr_acts;
- pool_port->ip_thread_pool.thr_acts = thr_act;
- if (thread_pool->waiting)
- thread_pool_wakeup(thread_pool);
- }
- act_unlock(thr_act);
- }
-
- return KERN_SUCCESS;
-}
-
-/*
- * act_locked_act_set_thread_pool- Assign activation to a specific thread_pool.
- * Fails if the activation is already assigned to another pool.
- * If thread_pool == 0, we remove the thr_act from its thread_pool.
- *
- * Called the port containing thread_pool already locked.
- * Also called with the thread activation locked.
- * Returns the same way.
- *
- * This routine is the same as `act_set_thread_pool()' except that it does
- * not call `act_deallocate(),' which unconditionally tries to obtain the
- * thread activation lock.
- */
-kern_return_t act_locked_act_set_thread_pool(
- thread_act_t thr_act,
- ipc_port_t pool_port)
-{
- thread_pool_t thread_pool;
-
-#if MACH_ASSERT
- if (watchacts & WA_ACT_LNK)
- printf("act_set_thread_pool: %x(%d) -> %x\n",
- thr_act, thr_act->ref_count, thread_pool);
-#endif /* MACH_ASSERT */
-
- if (pool_port == 0) {
- thread_act_t *lact;
-
- if (thr_act->pool_port == 0)
- return KERN_SUCCESS;
- thread_pool = &thr_act->pool_port->ip_thread_pool;
-
- for (lact = &thread_pool->thr_acts; *lact;
- lact = &((*lact)->thread_pool_next)) {
- if (thr_act == *lact) {
- *lact = thr_act->thread_pool_next;
- break;
- }
- }
-
- thr_act->pool_port = 0;
- thr_act->thread_pool_next = 0;
- act_locked_act_deallocate(thr_act);
- return KERN_SUCCESS;
- }
- if (thr_act->pool_port != pool_port) {
- thread_pool = &pool_port->ip_thread_pool;
- if (thr_act->pool_port != 0) {
-#if MACH_ASSERT
- if (watchacts & WA_ACT_LNK)
- printf("act_set_thread_pool found %x!\n",
- thr_act->pool_port);
-#endif /* MACH_ASSERT */
- return(KERN_FAILURE);
- }
- thr_act->pool_port = pool_port;
-
- /* The pool gets a ref to the activation -- have
- * to inline operation because thr_act is already
- * locked.
- */
- act_locked_act_reference(thr_act);
-
- /* If it is available,
- * add it to the thread_pool's available-activation list.
- */
- if ((thr_act->thread == 0) && (thr_act->suspend_count == 0)) {
- thr_act->thread_pool_next = thread_pool->thr_acts;
- pool_port->ip_thread_pool.thr_acts = thr_act;
- if (thread_pool->waiting)
- thread_pool_wakeup(thread_pool);
- }
- }
+ extern thread_apc_handler_t bsd_ast;
- return KERN_SUCCESS;
+ assert(apc == bsd_ast);
+ return (KERN_FAILURE);
}
/*
*
* This is called by system-dependent code when it detects that
* thr_act->handlers is non-null while returning into user mode.
- * Activations linked onto an thread_pool always have null thr_act->handlers,
- * so RPC entry paths need not check it.
*/
-void act_execute_returnhandlers(
- void)
+void
+act_execute_returnhandlers(void)
{
- spl_t s;
- thread_t thread;
- thread_act_t thr_act = current_act();
+ thread_act_t act = current_act();
#if MACH_ASSERT
if (watchacts & WA_ACT_HDLR)
- printf("execute_rtn_hdlrs: thr_act=%x\n", thr_act);
+ printf("execute_rtn_hdlrs: act=%x\n", act);
#endif /* MACH_ASSERT */
- s = splsched();
- act_clr_apc(thr_act);
+ thread_ast_clear(act, AST_APC);
spllo();
- while (1) {
- ReturnHandler *rh;
- /* Grab the next returnhandler */
- thread = act_lock_thread(thr_act);
+ for (;;) {
+ ReturnHandler *rh;
+ thread_t thread = act_lock_thread(act);
+
(void)splsched();
thread_lock(thread);
- rh = thr_act->handlers;
+ rh = act->handlers;
if (!rh) {
thread_unlock(thread);
- splx(s);
- act_unlock_thread(thr_act);
+ spllo();
+ act_unlock_thread(act);
return;
}
- thr_act->handlers = rh->next;
+ act->handlers = rh->next;
thread_unlock(thread);
spllo();
- act_unlock_thread(thr_act);
+ act_unlock_thread(act);
#if MACH_ASSERT
if (watchacts & WA_ACT_HDLR)
- printf( (rh == &thr_act->special_handler) ?
- "\tspecial_handler\n" : "\thandler=%x\n",
- rh->handler);
+ printf( (rh == &act->special_handler) ?
+ "\tspecial_handler\n" : "\thandler=%x\n", rh->handler);
#endif /* MACH_ASSERT */
/* Execute it */
- (*rh->handler)(rh, thr_act);
+ (*rh->handler)(rh, act);
}
}
void
special_handler_continue(void)
{
- thread_act_t cur_act = current_act();
- thread_t thread = cur_act->thread;
- spl_t s;
+ thread_act_t self = current_act();
- if (cur_act->suspend_count)
- install_special_handler(cur_act);
+ if (self->suspend_count > 0)
+ install_special_handler(self);
else {
- s = splsched();
+ thread_t thread = self->thread;
+ spl_t s = splsched();
+
thread_lock(thread);
- if (thread->depress_priority == -2) {
- /*
- * We were temporarily undepressed by
- * install_special_handler; restore priority
- * depression.
- */
- thread->depress_priority = thread->priority;
- thread->priority = thread->sched_pri = DEPRESSPRI;
+ if (thread->sched_mode & TH_MODE_ISDEPRESSED) {
+ 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);
}
+
thread_exception_return();
+ /*NOTREACHED*/
}
/*
void
special_handler(
ReturnHandler *rh,
- thread_act_t cur_act)
+ thread_act_t self)
{
- spl_t s;
- thread_t lthread;
- thread_t thread = act_lock_thread(cur_act);
- unsigned alert_bits;
- exception_data_type_t
- codes[EXCEPTION_CODE_MAX];
- kern_return_t kr;
- kern_return_t exc_kr;
+ thread_t thread = act_lock_thread(self);
+ spl_t s;
assert(thread != THREAD_NULL);
-#if MACH_ASSERT
- if (watchacts & WA_ACT_HDLR)
- printf("\t\tspecial_handler(thr_act=%x(%d))\n", cur_act,
- (cur_act ? cur_act->ref_count : 0));
-#endif /* MACH_ASSERT */
s = splsched();
-
thread_lock(thread);
- thread->state &= ~TH_ABORT; /* clear any aborts */
+ thread->state &= ~(TH_ABORT|TH_ABORT_SAFELY); /* clear any aborts */
thread_unlock(thread);
splx(s);
* If someone has killed this invocation,
* invoke the return path with a terminated exception.
*/
- if (!cur_act->active) {
- act_unlock_thread(cur_act);
+ if (!self->active) {
+ act_unlock_thread(self);
act_machine_return(KERN_TERMINATED);
}
-#ifdef CALLOUT_RPC_MODEL
- /*
- * JMM - We don't intend to support this RPC model in Darwin.
- * We will support inheritance through chains of activations
- * on shuttles, but it will be universal and not just for RPC.
- * As such, each activation will always have a base shuttle.
- * Our RPC model will probably even support the notion of
- * alerts (thrown up the chain of activations to affect the
- * work done on our behalf), but the unlinking of the shuttles
- * will be completely difference because we will never have
- * to clone them.
- */
-
- /* strip server terminated bit */
- alert_bits = cur_act->alerts & (~SERVER_TERMINATED);
-
- /* clear server terminated bit */
- cur_act->alerts &= ~SERVER_TERMINATED;
-
- if ( alert_bits ) {
- /*
- * currently necessary to coordinate with the exception
- * code -fdr
- */
- act_unlock_thread(cur_act);
-
- /* upcall exception/alert port */
- codes[0] = alert_bits;
-
- /*
- * Exception makes a lot of assumptions. If there is no
- * exception handler or the exception reply is broken, the
- * thread will be terminated and exception will not return. If
- * we decide we don't like that behavior, we need to check
- * for the existence of an exception port before we call
- * exception.
- */
- exc_kr = exception( EXC_RPC_ALERT, codes, 1 );
-
- /* clear the orphaned and time constraint indications */
- cur_act->alerts &= ~(ORPHANED | TIME_CONSTRAINT_UNSATISFIED);
-
- /* if this orphaned activation should be terminated... */
- if (exc_kr == KERN_RPC_TERMINATE_ORPHAN) {
- /*
- * ... terminate the activation
- *
- * This is done in two steps. First, the activation is
- * disabled (prepared for termination); second, the
- * `special_handler()' is executed again -- this time
- * to terminate the activation.
- * (`act_disable_task_locked()' arranges for the
- * additional execution of the `special_handler().')
- */
-
-#if THREAD_SWAPPER
- thread_swap_disable(cur_act);
-#endif /* THREAD_SWAPPER */
-
- /* acquire appropriate locks */
- task_lock(cur_act->task);
- act_lock_thread(cur_act);
-
- /* detach the activation from its task */
- kr = act_disable_task_locked(cur_act);
- assert( kr == KERN_SUCCESS );
-
- /* release locks */
- task_unlock(cur_act->task);
- }
- else {
- /* acquire activation lock again (released below) */
- act_lock_thread(cur_act);
- s = splsched();
- thread_lock(thread);
- if (thread->depress_priority == -2) {
- /*
- * We were temporarily undepressed by
- * install_special_handler; restore priority
- * depression.
- */
- thread->depress_priority = thread->priority;
- thread->priority = thread->sched_pri = DEPRESSPRI;
- }
- thread_unlock(thread);
- splx(s);
- }
- }
-#endif /* CALLOUT_RPC_MODEL */
-
/*
* If we're suspended, go to sleep and wait for someone to wake us up.
*/
- if (cur_act->suspend_count) {
- if( cur_act->handlers == NULL ) {
- assert_wait((event_t)&cur_act->suspend_count,
- THREAD_ABORTSAFE);
- act_unlock_thread(cur_act);
+ if (self->suspend_count > 0) {
+ if (self->handlers == NULL) {
+ assert_wait(&self->suspend_count, THREAD_ABORTSAFE);
+ act_unlock_thread(self);
thread_block(special_handler_continue);
/* NOTREACHED */
}
- special_handler_continue();
- }
- act_unlock_thread(cur_act);
-}
+ act_unlock_thread(self);
-/*
- * Try to nudge a thr_act into executing its returnhandler chain.
- * Ensures that the activation will execute its returnhandlers
- * before it next executes any of its user-level code.
- *
- * Called with thr_act's act_lock() and "appropriate" thread-related
- * locks held. (See act_lock_thread().) Returns same way.
- */
-void
-nudge(thread_act_t thr_act)
-{
-#if MACH_ASSERT
- if (watchacts & WA_ACT_HDLR)
- printf("\tact_%x: nudge(%x)\n", current_act(), thr_act);
-#endif /* MACH_ASSERT */
-
- /*
- * Don't need to do anything at all if this thr_act isn't the topmost.
- */
- if (thr_act->thread && thr_act->thread->top_act == thr_act) {
- /*
- * If it's suspended, wake it up.
- * This should nudge it even on another CPU.
- */
- thread_wakeup((event_t)&thr_act->suspend_count);
+ special_handler_continue();
+ /*NOTREACHED*/
}
+
+ act_unlock_thread(self);
}
/*
}
/*
- * Already locked: thr_act->task, RPC-related locks for thr_act
+ * Already locked: activation (shuttle frozen within)
*
- * Detach an activation from its task, and prepare it to terminate
+ * Mark an activation inactive, and prepare it to terminate
* itself.
*/
-kern_return_t
-act_disable_task_locked(
+static void
+act_disable(
thread_act_t thr_act)
{
- thread_t thread = thr_act->thread;
- task_t task = thr_act->task;
#if MACH_ASSERT
if (watchacts & WA_EXIT) {
- printf("act_%x: act_disable_tl(thr_act=%x(%d))%sactive task=%x(%d)",
+ printf("act_%x: act_disable_tl(thr_act=%x(%d))%sactive",
current_act(), thr_act, thr_act->ref_count,
- (thr_act->active ? " " : " !"),
- thr_act->task, thr_act->task? thr_act->task->ref_count : 0);
- if (thr_act->pool_port)
- printf(", pool_port %x", thr_act->pool_port);
+ (thr_act->active ? " " : " !"));
printf("\n");
(void) dump_act(thr_act);
}
#endif /* MACH_ASSERT */
- /* This will allow no more control ops on this thr_act. */
thr_act->active = 0;
- ipc_thr_act_disable(thr_act);
-
- /* Clean-up any ulocks that are still owned by the thread
- * activation (acquired but not released or handed-off).
- */
- act_ulock_release_all(thr_act);
-
- /* When the special_handler gets executed,
- * it will see the terminated condition and exit
- * immediately.
- */
- install_special_handler(thr_act);
-
-
- /* If the target happens to be suspended,
- * give it a nudge so it can exit.
- */
- if (thr_act->suspend_count)
- nudge(thr_act);
/* Drop the thr_act reference taken for being active.
* (There is still at least one reference left:
* Inline the deallocate because thr_act is locked.
*/
act_locked_act_deallocate(thr_act);
-
- return(KERN_SUCCESS);
}
/*
* thread-related locks held. (See act_lock_thread().)
*/
kern_return_t
-get_set_state(thread_act_t thr_act, int flavor, thread_state_t state, int *pcount,
- void (*handler)(ReturnHandler *rh, thread_act_t thr_act))
+get_set_state(
+ thread_act_t act,
+ int flavor,
+ thread_state_t state,
+ int *pcount,
+ void (*handler)(
+ ReturnHandler *rh,
+ thread_act_t act))
{
- GetSetState gss;
- spl_t s;
+ GetSetState gss;
/* Initialize a small parameter structure */
gss.rh.handler = handler;
gss.result = KERN_ABORTED; /* iff wait below is interrupted */
/* Add it to the thr_act's return handler list */
- gss.rh.next = thr_act->handlers;
- thr_act->handlers = &gss.rh;
+ gss.rh.next = act->handlers;
+ act->handlers = &gss.rh;
- s = splsched();
- act_set_apc(thr_act);
- splx(s);
+ act_set_apc(act);
#if MACH_ASSERT
if (watchacts & WA_ACT_HDLR) {
- printf("act_%x: get_set_state(thr_act=%x flv=%x state=%x ptr@%x=%x)",
- current_act(), thr_act, flavor, state,
+ printf("act_%x: get_set_state(act=%x flv=%x state=%x ptr@%x=%x)",
+ current_act(), act, flavor, state,
pcount, (pcount ? *pcount : 0));
printf((handler == get_state_handler ? "get_state_hdlr\n" :
(handler == set_state_handler ? "set_state_hdlr\n" :
}
#endif /* MACH_ASSERT */
- assert(thr_act->thread); /* Callers must ensure these */
- assert(thr_act != current_act());
+ assert(act->thread);
+ assert(act != current_act());
+
for (;;) {
- nudge(thr_act);
+ wait_result_t result;
+
+ if ( act->inited &&
+ act->thread->top_act == act )
+ thread_wakeup_one(&act->suspend_count);
+
/*
* Wait must be interruptible to avoid deadlock (e.g.) with
* task_suspend() when caller and target of get_set_state()
* are in same task.
*/
- assert_wait((event_t)&gss, THREAD_ABORTSAFE);
- act_unlock_thread(thr_act);
- thread_block((void (*)(void))0);
- if (gss.result != KERN_ABORTED)
+ result = assert_wait(&gss, THREAD_ABORTSAFE);
+ act_unlock_thread(act);
+
+ if (result == THREAD_WAITING)
+ result = thread_block(THREAD_CONTINUE_NULL);
+
+ assert(result != THREAD_WAITING);
+
+ if (gss.result != KERN_ABORTED) {
+ assert(result != THREAD_INTERRUPTED);
break;
+ }
+
+ /* JMM - What about other aborts (like BSD signals)? */
if (current_act()->handlers)
act_execute_returnhandlers();
- act_lock_thread(thr_act);
+
+ act_lock_thread(act);
}
#if MACH_ASSERT
current_act(), gss.result);
#endif /* MACH_ASSERT */
- return gss.result;
+ return (gss.result);
}
void
return(act_get_state_locked(thr_act, flavor, state, pcount));
}
-/*
- * These two should be called at splsched()
- * Set/clear indicator to run APC (layered on ASTs)
- */
void
-act_set_apc(thread_act_t thr_act)
+act_set_astbsd(
+ thread_act_t act)
{
-
- processor_t prssr;
- thread_t thread;
-
- mp_disable_preemption();
+ spl_t s = splsched();
- thread_ast_set(thr_act, AST_APC);
- if (thr_act == current_act()) {
- ast_propagate(thr_act->ast);
- mp_enable_preemption();
- return; /* If we are current act, we can't be on the other processor so leave now */
+ if (act == current_act()) {
+ thread_ast_set(act, AST_BSD);
+ ast_propagate(act->ast);
}
+ else {
+ thread_t thread = act->thread;
+ processor_t processor;
-/*
- * Here we want to make sure that the apc is taken quickly. Therefore, we check
- * if, and where, the activation is running. If it is not running, we don't need to do
- * anything. If it is, we need to signal the other processor to trigger it to
- * check the asts. Note that there is a race here and we may end up sending a signal
- * after the thread has been switched off. Hopefully this is no big deal.
- */
-
- thread = thr_act->thread; /* Get the thread for the signaled activation */
- prssr = thread->last_processor; /* get the processor it was last on */
- if(prssr && (cpu_data[prssr->slot_num].active_thread == thread)) { /* Is the thread active on its processor? */
- cause_ast_check(prssr); /* Yes, kick it */
+ thread_lock(thread);
+ thread_ast_set(act, AST_BSD);
+ processor = thread->last_processor;
+ if ( processor != PROCESSOR_NULL &&
+ processor->state == PROCESSOR_RUNNING &&
+ processor->cpu_data->active_thread == thread )
+ cause_ast_check(processor);
+ thread_unlock(thread);
}
- mp_enable_preemption();
+ splx(s);
}
void
-act_clr_apc(thread_act_t thr_act)
+act_set_apc(
+ thread_act_t act)
{
- thread_ast_clear(thr_act, AST_APC);
+ spl_t s = splsched();
+
+ if (act == current_act()) {
+ thread_ast_set(act, AST_APC);
+ ast_propagate(act->ast);
+ }
+ else {
+ thread_t thread = act->thread;
+ processor_t processor;
+
+ thread_lock(thread);
+ thread_ast_set(act, AST_APC);
+ processor = thread->last_processor;
+ if ( processor != PROCESSOR_NULL &&
+ processor->state == PROCESSOR_RUNNING &&
+ processor->cpu_data->active_thread == thread )
+ cause_ast_check(processor);
+ thread_unlock(thread);
+ }
+
+ splx(s);
}
void
* Provide routines (for export to other components) of things that
* are implemented as macros insternally.
*/
-#undef current_act
-thread_act_t
-current_act(void)
-{
- return(current_act_fast());
-}
-
thread_act_t
thread_self(void)
{
{
act_deallocate_fast(thr_act);
}
-