-/*
- * 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.
- *
- * Already locked: thr_act plus "appropriate" thread-related locks
- * (see act_lock_thread()).
- */
-void
-act_attach(
- thread_act_t thr_act,
- thread_t thread,
- unsigned init_alert_mask)
-{
- thread_act_t lower;
-
-#if MACH_ASSERT
- assert(thread == current_thread() || thread->top_act == THR_ACT_NULL);
- if (watchacts & WA_ACT_LNK)
- printf("act_attach(thr_act %x(%d) thread %x(%d) mask %d)\n",
- thr_act, thr_act->ref_count, thread, thread->ref_count,
- init_alert_mask);
-#endif /* MACH_ASSERT */
-
- /*
- * Chain the thr_act onto the thread's thr_act stack.
- * Set mask and auto-propagate alerts from below.
- */
- thr_act->ref_count++;
- thr_act->thread = thread;
- thr_act->higher = THR_ACT_NULL; /*safety*/
- thr_act->alerts = 0;
- thr_act->alert_mask = init_alert_mask;
- lower = thr_act->lower = thread->top_act;
-
- if (lower != THR_ACT_NULL) {
- lower->higher = thr_act;
- thr_act->alerts = (lower->alerts & init_alert_mask);
- }
-
- thread->top_act = thr_act;
-}
-
-/*
- * act_detach
- *
- * Remove the current thr_act from the top of the current thread, i.e.
- * "pop the stack". Assumes already locked: thr_act plus "appropriate"
- * thread-related locks (see act_lock_thread).
- */
-void
-act_detach(
- thread_act_t cur_act)
-{
- thread_t cur_thread = cur_act->thread;
-
-#if MACH_ASSERT
- if (watchacts & (WA_EXIT|WA_ACT_LNK))
- printf("act_detach: thr_act %x(%d), thrd %x(%d) task=%x(%d)\n",
- cur_act, cur_act->ref_count,
- cur_thread, cur_thread->ref_count,
- cur_act->task,
- cur_act->task ? cur_act->task->ref_count : 0);
-#endif /* MACH_ASSERT */
-
- /* Unlink the thr_act from the thread's thr_act stack */
- cur_thread->top_act = cur_act->lower;
- cur_act->thread = 0;
- 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)
- cur_thread->top_act->higher = THR_ACT_NULL;
-#endif /* MACH_ASSERT */
-
- return;
-}
-
-
-/*
- * 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.
- */
-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().
- */
- 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();
- }
- return (thr_act->thread);
-}
-
-/*
- * Unsynchronize with RPC (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
- * activation). Called with nothing locked; returns with all
- * "appropriate" thread-related locks held (see act_lock_thread()).
- */
-thread_act_t
-thread_lock_act(
- thread_t 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;
- }
- break;
- }
- return (thr_act);
-}
-
-/*
- * 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.
- */
-void
-thread_unlock_act(
- thread_t thread)
-{
- 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);
-}
-
-/*
- * switch_act
- *
- * 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.
- */
-thread_act_t
-switch_act(
- thread_act_t act)
-{
- thread_t thread;
- thread_act_t old, new;
- unsigned cpu;
- spl_t spl;
-
-
- disable_preemption();
-
- cpu = cpu_number();
- thread = current_thread();
-
- /*
- * Find the old and new activation for switch.
- */
- old = thread->top_act;
-
- if (act) {
- new = act;
- new->thread = thread;
- }
- else {
- new = old->lower;
- }
-
- 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);
- active_kloaded[cpu] = (new->kernel_loaded) ? new : 0;
-
- /* This is where all the work happens */
- machine_switch_act(thread, old, new, cpu);
-
- /*
- * Push or pop an activation on the chain.
- */
- if (act) {
- act_attach(new, thread, 0);
- }
- else {
- act_detach(old);
- }
-
- enable_preemption();
-
- return(old);
-}
-
-/*
- * install_special_handler
- * Install the special returnhandler that handles suspension and
- * termination, if it hasn't been installed already.
- *
- * Already locked: RPC-related locks for thr_act, but not
- * scheduling lock (thread_lock()) of the associated thread.
- */
-void
-install_special_handler(
- thread_act_t thr_act)
-{
- spl_t spl;
- thread_t thread = thr_act->thread;
-
-#if MACH_ASSERT
- if (watchacts & WA_ACT_HDLR)
- printf("act_%x: install_special_hdlr(%x)\n",current_act(),thr_act);
-#endif /* MACH_ASSERT */
-
- spl = splsched();
- if (thread)