/* * Internal routine to mark a thread as waiting * right after it has been created. The caller * is responsible to call wakeup()/thread_wakeup() * or thread_terminate() to get it going. * * Always called with the thread mutex locked. * * Task and task_threads mutexes also held * (so nobody can set the thread running before * this point) * * Converts TH_UNINT wait to THREAD_INTERRUPTIBLE * to allow termination from this point forward. */ void thread_start_in_assert_wait( thread_t thread, event_t event, wait_interrupt_t interruptible) { struct waitq *waitq = assert_wait_queue(event); wait_result_t wait_result; spl_t spl; spl = splsched(); waitq_lock(waitq); /* clear out startup condition (safe because thread not started yet) */ thread_lock(thread); assert(!thread->started); assert((thread->state & (TH_WAIT | TH_UNINT)) == (TH_WAIT | TH_UNINT)); thread->state &= ~(TH_WAIT | TH_UNINT); thread_unlock(thread); /* assert wait interruptibly forever */ wait_result = waitq_assert_wait64_locked(waitq, CAST_EVENT64_T(event), interruptible, TIMEOUT_URGENCY_SYS_NORMAL, TIMEOUT_WAIT_FOREVER, TIMEOUT_NO_LEEWAY, thread); assert (wait_result == THREAD_WAITING); /* mark thread started while we still hold the waitq lock */ thread_lock(thread); thread->started = TRUE; thread_unlock(thread); waitq_unlock(waitq); splx(spl); }
/* * Routine: semaphore_wait_internal * * Decrements the semaphore count by one. If the count is * negative after the decrement, the calling thread blocks * (possibly at a continuation and/or with a timeout). * * Assumptions: * The reference * A reference is held on the signal semaphore. */ static kern_return_t semaphore_wait_internal( semaphore_t wait_semaphore, semaphore_t signal_semaphore, uint64_t deadline, int option, void (*caller_cont)(kern_return_t)) { int wait_result; spl_t spl_level; kern_return_t kr = KERN_ALREADY_WAITING; spl_level = splsched(); semaphore_lock(wait_semaphore); if (!wait_semaphore->active) { kr = KERN_TERMINATED; } else if (wait_semaphore->count > 0) { wait_semaphore->count--; kr = KERN_SUCCESS; } else if (option & SEMAPHORE_TIMEOUT_NOBLOCK) { kr = KERN_OPERATION_TIMED_OUT; } else { thread_t self = current_thread(); wait_semaphore->count = -1; /* we don't keep an actual count */ thread_lock(self); (void)waitq_assert_wait64_locked( &wait_semaphore->waitq, SEMAPHORE_EVENT, THREAD_ABORTSAFE, TIMEOUT_URGENCY_USER_NORMAL, deadline, TIMEOUT_NO_LEEWAY, self); thread_unlock(self); } semaphore_unlock(wait_semaphore); splx(spl_level); /* * wait_semaphore is unlocked so we are free to go ahead and * signal the signal_semaphore (if one was provided). */ if (signal_semaphore != SEMAPHORE_NULL) { kern_return_t signal_kr; /* * lock the signal semaphore reference we got and signal it. * This will NOT block (we cannot block after having asserted * our intention to wait above). */ signal_kr = semaphore_signal_internal(signal_semaphore, THREAD_NULL, SEMAPHORE_SIGNAL_PREPOST); if (signal_kr == KERN_NOT_WAITING) signal_kr = KERN_SUCCESS; else if (signal_kr == KERN_TERMINATED) { /* * Uh!Oh! The semaphore we were to signal died. * We have to get ourselves out of the wait in * case we get stuck here forever (it is assumed * that the semaphore we were posting is gating * the decision by someone else to post the * semaphore we are waiting on). People will * discover the other dead semaphore soon enough. * If we got out of the wait cleanly (someone * already posted a wakeup to us) then return that * (most important) result. Otherwise, * return the KERN_TERMINATED status. */ thread_t self = current_thread(); clear_wait(self, THREAD_INTERRUPTED); kr = semaphore_convert_wait_result(self->wait_result); if (kr == KERN_ABORTED) kr = KERN_TERMINATED; } } /* * If we had an error, or we didn't really need to wait we can * return now that we have signalled the signal semaphore. */ if (kr != KERN_ALREADY_WAITING) return kr; /* * Now, we can block. If the caller supplied a continuation * pointer of his own for after the block, block with the * appropriate semaphore continuation. Thiswill gather the * semaphore results, release references on the semaphore(s), * and then call the caller's continuation. */ if (caller_cont) { thread_t self = current_thread(); self->sth_continuation = caller_cont; self->sth_waitsemaphore = wait_semaphore; self->sth_signalsemaphore = signal_semaphore; wait_result = thread_block((thread_continue_t)semaphore_wait_continue); } else { wait_result = thread_block(THREAD_CONTINUE_NULL); } return (semaphore_convert_wait_result(wait_result)); }