/* * Routine: wait_queue_assert_wait64_locked * Purpose: * Insert the current thread into the supplied wait queue * waiting for a particular event to be posted to that queue. * * Conditions: * The wait queue is assumed locked. * The waiting thread is assumed locked. * */ __private_extern__ wait_result_t wait_queue_assert_wait64_locked( wait_queue_t wq, event64_t event, wait_interrupt_t interruptible, thread_t thread) { wait_result_t wait_result; if (!wait_queue_assert_possible(thread)) panic("wait_queue_assert_wait64_locked"); if (wq->wq_type == _WAIT_QUEUE_SET_inited) { wait_queue_set_t wqs = (wait_queue_set_t)wq; if (wqs->wqs_isprepost && wqs->wqs_refcount > 0) return(THREAD_AWAKENED); } /* * This is the extent to which we currently take scheduling attributes * into account. If the thread is vm priviledged, we stick it at * the front of the queue. Later, these queues will honor the policy * value set at wait_queue_init time. */ wait_result = thread_mark_wait_locked(thread, interruptible); if (wait_result == THREAD_WAITING) { if (thread->vm_privilege) enqueue_head(&wq->wq_queue, (queue_entry_t) thread); else enqueue_tail(&wq->wq_queue, (queue_entry_t) thread); thread->wait_event = event; thread->wait_queue = wq; } return(wait_result); }
/* * thread_terminate_self: */ void thread_terminate_self(void) { thread_t thread = current_thread(); task_t task; spl_t s; int threadcnt; DTRACE_PROC(lwp__exit); thread_mtx_lock(thread); ulock_release_all(thread); ipc_thread_disable(thread); thread_mtx_unlock(thread); s = splsched(); thread_lock(thread); /* * Cancel priority depression, wait for concurrent expirations * on other processors. */ if (thread->sched_flags & TH_SFLAG_DEPRESSED_MASK) { thread->sched_flags &= ~TH_SFLAG_DEPRESSED_MASK; if (timer_call_cancel(&thread->depress_timer)) thread->depress_timer_active--; } while (thread->depress_timer_active > 0) { thread_unlock(thread); splx(s); delay(1); s = splsched(); thread_lock(thread); } thread_sched_call(thread, NULL); thread_unlock(thread); splx(s); thread_policy_reset(thread); #if CONFIG_EMBEDDED thead_remove_taskwatch(thread); #endif /* CONFIG_EMBEDDED */ task = thread->task; uthread_cleanup(task, thread->uthread, task->bsd_info); threadcnt = hw_atomic_sub(&task->active_thread_count, 1); /* * If we are the last thread to terminate and the task is * associated with a BSD process, perform BSD process exit. */ if (threadcnt == 0 && task->bsd_info != NULL) proc_exit(task->bsd_info); uthread_cred_free(thread->uthread); s = splsched(); thread_lock(thread); /* * Cancel wait timer, and wait for * concurrent expirations. */ if (thread->wait_timer_is_set) { thread->wait_timer_is_set = FALSE; if (timer_call_cancel(&thread->wait_timer)) thread->wait_timer_active--; } while (thread->wait_timer_active > 0) { thread_unlock(thread); splx(s); delay(1); s = splsched(); thread_lock(thread); } /* * If there is a reserved stack, release it. */ if (thread->reserved_stack != 0) { stack_free_reserved(thread); thread->reserved_stack = 0; } /* * Mark thread as terminating, and block. */ thread->state |= TH_TERMINATE; thread_mark_wait_locked(thread, THREAD_UNINT); thread_unlock(thread); /* splsched */ thread_block((thread_continue_t)thread_terminate_continue); /*NOTREACHED*/ }
/* * thread_terminate_self: */ void thread_terminate_self(void) { thread_t thread = current_thread(); task_t task; spl_t s; int lastthread = 0; thread_mtx_lock(thread); ulock_release_all(thread); ipc_thread_disable(thread); thread_mtx_unlock(thread); s = splsched(); thread_lock(thread); /* * Cancel priority depression, wait for concurrent expirations * on other processors. */ if (thread->sched_mode & TH_MODE_ISDEPRESSED) { thread->sched_mode &= ~TH_MODE_ISDEPRESSED; if (timer_call_cancel(&thread->depress_timer)) thread->depress_timer_active--; } while (thread->depress_timer_active > 0) { thread_unlock(thread); splx(s); delay(1); s = splsched(); thread_lock(thread); } thread_unlock(thread); splx(s); thread_policy_reset(thread); /* * If we are the last thread to terminate and the task is * associated with a BSD process, perform BSD process exit. */ task = thread->task; uthread_cleanup(task, thread->uthread, task->bsd_info); if (hw_atomic_sub(&task->active_thread_count, 1) == 0 && task->bsd_info != NULL) { lastthread = 1; } if (lastthread != 0) proc_exit(task->bsd_info); uthread_cred_free(thread->uthread); s = splsched(); thread_lock(thread); /* * Cancel wait timer, and wait for * concurrent expirations. */ if (thread->wait_timer_is_set) { thread->wait_timer_is_set = FALSE; if (timer_call_cancel(&thread->wait_timer)) thread->wait_timer_active--; } while (thread->wait_timer_active > 0) { thread_unlock(thread); splx(s); delay(1); s = splsched(); thread_lock(thread); } /* * If there is a reserved stack, release it. */ if (thread->reserved_stack != 0) { if (thread->reserved_stack != thread->kernel_stack) stack_free_stack(thread->reserved_stack); thread->reserved_stack = 0; } /* * Mark thread as terminating, and block. */ thread->state |= TH_TERMINATE; thread_mark_wait_locked(thread, THREAD_UNINT); assert(thread->promotions == 0); thread_unlock(thread); /* splsched */ thread_block((thread_continue_t)thread_terminate_continue); /*NOTREACHED*/ }
/* * Routine: wait_queue_assert_wait64_locked * Purpose: * Insert the current thread into the supplied wait queue * waiting for a particular event to be posted to that queue. * * Conditions: * The wait queue is assumed locked. * The waiting thread is assumed locked. * */ __private_extern__ wait_result_t wait_queue_assert_wait64_locked( wait_queue_t wq, event64_t event, wait_interrupt_t interruptible, uint64_t deadline, thread_t thread) { wait_result_t wait_result; boolean_t realtime; if (!wait_queue_assert_possible(thread)) panic("wait_queue_assert_wait64_locked"); if (wq->wq_type == _WAIT_QUEUE_SET_inited) { wait_queue_set_t wqs = (wait_queue_set_t)wq; if (event == NO_EVENT64 && wqs_is_preposted(wqs)) return(THREAD_AWAKENED); } /* * Realtime threads get priority for wait queue placements. * This allows wait_queue_wakeup_one to prefer a waiting * realtime thread, similar in principle to performing * a wait_queue_wakeup_all and allowing scheduler prioritization * to run the realtime thread, but without causing the * lock contention of that scenario. */ realtime = (thread->sched_pri >= BASEPRI_REALTIME); /* * This is the extent to which we currently take scheduling attributes * into account. If the thread is vm priviledged, we stick it at * the front of the queue. Later, these queues will honor the policy * value set at wait_queue_init time. */ wait_result = thread_mark_wait_locked(thread, interruptible); if (wait_result == THREAD_WAITING) { if (!wq->wq_fifo || (thread->options & TH_OPT_VMPRIV) || realtime) enqueue_head(&wq->wq_queue, (queue_entry_t) thread); else enqueue_tail(&wq->wq_queue, (queue_entry_t) thread); thread->wait_event = event; thread->wait_queue = wq; if (deadline != 0) { uint32_t flags; flags = realtime ? TIMER_CALL_CRITICAL : 0; if (!timer_call_enter(&thread->wait_timer, deadline, flags)) thread->wait_timer_active++; thread->wait_timer_is_set = TRUE; } } return(wait_result); }