- * Called with activation locked.
- */
-#if MACH_ASSERT
-int dangerous_bzero = 1; /* paranoia & safety */
-#endif
-
-void
-act_free(thread_act_t thr_act)
-{
- task_t task;
- 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) %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->active ? " " : " !");
-#endif /* MACH_ASSERT */
-
- assert(!thr_act->active);
-
- task = thr_act->task;
- task_lock(task);
-
- task_proc = task->bsd_info;
- if (thr = thr_act->thread) {
- time_value_t user_time, system_time;
-
- thread_read_times(thr, &user_time, &system_time);
- time_value_add(&task->total_user_time, &user_time);
- time_value_add(&task->total_system_time, &system_time);
-
- /* Unlink the thr_act from the task's thr_act list,
- * so it doesn't appear in calls to task_threads and such.
- * The thr_act still keeps its ref on the task, however.
- */
- queue_remove(&task->thr_acts, thr_act, thread_act_t, thr_acts);
- thr_act->thr_acts.next = NULL;
- task->thr_act_count--;
- task->res_act_count--;
- task_unlock(task);
- task_deallocate(task);
- thread_deallocate(thr);
- act_machine_destroy(thr_act);
- } else {
- /*
- * Must have never really gotten started
- * no unlinking from the task and no need
- * to free the shuttle.
- */
- task_unlock(task);
- task_deallocate(task);
- }
-
- act_prof_deallocate(thr_act);
- ipc_thr_act_terminate(thr_act);
-
- /*
- * Drop the cached map reference.
- * Inline version of vm_map_deallocate() because we
- * don't want to decrement the map's residence count here.
- */
- map = thr_act->map;
- mutex_lock(&map->s_lock);
- ref = --map->ref_count;
- mutex_unlock(&map->s_lock);
- if (ref == 0)
- vm_map_destroy(map);
-
-#ifdef MACH_BSD
- {
- /*
- * Free uthread BEFORE the bzero.
- * Not doing so will result in a leak.
- */
- extern void uthread_free(task_t, void *, void *);
-
- void *ut = thr_act->uthread;
- thr_act->uthread = 0;
- uthread_free(task, ut, task_proc);
- }
-#endif /* MACH_BSD */
-
-#if MACH_ASSERT
- if (dangerous_bzero) /* dangerous if we're still using it! */
- bzero((char *)thr_act, sizeof(*thr_act));
-#endif /* MACH_ASSERT */
- /* Put the thr_act back on the thr_act zone */
- zfree(thr_act_zone, (vm_offset_t)thr_act);
-}
-
-
-/*
- * 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.
- *
- * 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);
-
-#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 migration.
- * Called with nothing locked.
- * Returns with thr_act locked.
- */
-thread_t
-act_lock_thread(
- thread_act_t thr_act)
-{
-
- /*
- * 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.
- */
- act_lock(thr_act);
- return (thr_act->thread);
-}
-
-/*
- * 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)
-{
- act_unlock(thr_act);
-}
-
-/*
- * 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
-thread_lock_act(
- thread_t thread)
-{
- thread_act_t thr_act;
-
- while (1) {
- thr_act = thread->top_act;
- if (!thr_act)
- break;
- if (!act_lock_try(thr_act)) {
- mutex_pause();
- continue;
- }
- break;
- }
- return (thr_act);
-}
-
-/*
- * Unsynchronize with an activation starting from a pointer to
- * a shuttle.
- */
-void
-thread_unlock_act(
- thread_t thread)
-{
- thread_act_t thr_act;
-
- if (thr_act = thread->top_act) {
- act_unlock(thr_act);
- }
-}
-
-/*
- * 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 migration 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);
- 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 */
- 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