+boolean_t
+mutex_preblock_wait(
+ mutex_t *mutex,
+ thread_t thread,
+ thread_t holder)
+{
+ wait_result_t wresult;
+ integer_t priority;
+ wait_queue_t wq;
+
+ assert(holder == NULL || holder->thread == holder);
+
+ wq = wait_event_wait_queue((event_t)mutex);
+ if (!wait_queue_lock_try(wq))
+ return (FALSE);
+
+ if (holder != NULL && !thread_lock_try(holder)) {
+ wait_queue_unlock(wq);
+ return (FALSE);
+ }
+
+ wresult = wait_queue_assert_wait64_locked(wq, (uint32_t)mutex,
+ THREAD_UNINT, thread);
+ wait_queue_unlock(wq);
+ assert(wresult == THREAD_WAITING);
+
+ priority = thread->sched_pri;
+ if (priority < thread->priority)
+ priority = thread->priority;
+ if (priority > MINPRI_KERNEL)
+ priority = MINPRI_KERNEL;
+ else
+ if (priority < BASEPRI_DEFAULT)
+ priority = BASEPRI_DEFAULT;
+
+ if (holder != NULL) {
+ if (mutex->promoted_pri == 0)
+ holder->promotions++;
+ if (holder->priority < MINPRI_KERNEL) {
+ holder->sched_mode |= TH_MODE_PROMOTED;
+ if ( mutex->promoted_pri < priority &&
+ holder->sched_pri < priority ) {
+ KERNEL_DEBUG_CONSTANT(
+ MACHDBG_CODE(DBG_MACH_SCHED,MACH_PROMOTE) | DBG_FUNC_NONE,
+ holder->sched_pri, priority,
+ (int)holder, (int)mutex, 0);
+
+ set_sched_pri(holder, priority);
+ }
+ }
+ thread_unlock(holder);
+ }
+
+ if (mutex->promoted_pri < priority)
+ mutex->promoted_pri = priority;
+
+ if (thread->pending_promoter[thread->pending_promoter_index] == NULL) {
+ thread->pending_promoter[thread->pending_promoter_index] = mutex;
+ mutex->waiters++;
+ }
+ else
+ if (thread->pending_promoter[thread->pending_promoter_index] != mutex) {
+ thread->pending_promoter[++thread->pending_promoter_index] = mutex;
+ mutex->waiters++;
+ }
+
+ KERNEL_DEBUG_CONSTANT(
+ MACHDBG_CODE(DBG_MACH_SCHED,MACH_PREBLOCK_MUTEX) | DBG_FUNC_NONE,
+ (int)thread, thread->sched_pri, (int)mutex, 0, 0);
+
+ return (TRUE);
+}
+