Index: sys/kern/kern_umtx.c =================================================================== --- sys/kern/kern_umtx.c +++ sys/kern/kern_umtx.c @@ -279,7 +279,7 @@ static void umtx_pi_free(struct umtx_pi *pi); static int do_unlock_pp(struct thread *td, struct umutex *m, uint32_t flags, bool rb); -static void umtx_thread_cleanup(struct thread *td); +static void umtx_thread_cleanup(struct thread *td, bool proc_locked); static void umtx_exec_hook(void *arg __unused, struct proc *p __unused, struct image_params *imgp __unused); SYSINIT(umtx, SI_SUB_EVENTHANDLER+1, SI_ORDER_MIDDLE, umtxq_sysinit, NULL); @@ -4419,9 +4419,7 @@ KASSERT(td == curthread || ((td->td_flags & TDF_BOUNDARY) != 0 && TD_IS_SUSPENDED(td)), ("running thread %p %p", p, td)); - PROC_UNLOCK(p); - umtx_thread_cleanup(td); - PROC_LOCK(p); + umtx_thread_cleanup(td, true); td->td_rb_list = td->td_rbp_list = td->td_rb_inact = 0; } PROC_UNLOCK(p); @@ -4434,7 +4432,7 @@ umtx_thread_exit(struct thread *td) { - umtx_thread_cleanup(td); + umtx_thread_cleanup(td, false); } static int @@ -4530,29 +4528,42 @@ * Clean up umtx data. */ static void -umtx_thread_cleanup(struct thread *td) +umtx_thread_cleanup(struct thread *td, bool proc_locked) { struct umtx_q *uq; struct umtx_pi *pi; uintptr_t rb_inact; + if (proc_locked) + PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); /* * Disown pi mutexes. */ uq = td->td_umtxq; if (uq != NULL) { - mtx_lock(&umtx_lock); - uq->uq_inherited_pri = PRI_MAX; - while ((pi = TAILQ_FIRST(&uq->uq_pi_contested)) != NULL) { - pi->pi_owner = NULL; - TAILQ_REMOVE(&uq->uq_pi_contested, pi, pi_link); + if (uq->uq_inherited_pri != PRI_MAX || + !TAILQ_EMPTY(&uq->uq_pi_contested)) { + if (proc_locked) + PROC_UNLOCK(td->td_proc); + mtx_lock(&umtx_lock); + uq->uq_inherited_pri = PRI_MAX; + while ((pi = TAILQ_FIRST(&uq->uq_pi_contested)) != NULL) { + pi->pi_owner = NULL; + TAILQ_REMOVE(&uq->uq_pi_contested, pi, pi_link); + } + mtx_unlock(&umtx_lock); + if (proc_locked) + PROC_LOCK(td->td_proc); } - mtx_unlock(&umtx_lock); - thread_lock(td); - sched_lend_user_prio(td, PRI_MAX); - thread_unlock(td); + sched_lend_user_prio_cond(td, PRI_MAX); } + if (td->td_rb_inact == 0 && td->td_rb_list == 0 && td->td_rbp_list == 0) + return; + + if (proc_locked) + PROC_UNLOCK(td->td_proc); + /* * Handle terminated robust mutexes. Must be done after * robust pi disown, otherwise unlock could see unowned @@ -4565,4 +4576,7 @@ umtx_cleanup_rb_list(td, td->td_rbp_list, &rb_inact, "priv "); if (rb_inact != 0) (void)umtx_handle_rb(td, rb_inact, NULL, true); + + if (proc_locked) + PROC_LOCK(td->td_proc); } Index: sys/kern/sched_4bsd.c =================================================================== --- sys/kern/sched_4bsd.c +++ sys/kern/sched_4bsd.c @@ -930,6 +930,29 @@ td->td_flags |= TDF_NEEDRESCHED; } +/* + * Like the above but first check if there is anything to do. + */ +void +sched_lend_user_prio_cond(struct thread *td, u_char prio) +{ + u_char lower; + + if (td->td_lend_user_pri != prio) + goto lend; + lower = min(prio, td->td_base_user_pri); + if (td->td_user_pri != lower) + goto lend; + if (td->td_priority >= td->td_user_pri) + goto lend; + return; + +lend: + thread_lock(td); + sched_lend_user_prio(td, prio); + thread_unlock(td); +} + void sched_sleep(struct thread *td, int pri) { Index: sys/kern/sched_ule.c =================================================================== --- sys/kern/sched_ule.c +++ sys/kern/sched_ule.c @@ -1861,6 +1861,29 @@ td->td_flags |= TDF_NEEDRESCHED; } +/* + * Like the above but first check if there is anything to do. + */ +void +sched_lend_user_prio_cond(struct thread *td, u_char prio) +{ + u_char lower; + + if (td->td_lend_user_pri != prio) + goto lend; + lower = min(prio, td->td_base_user_pri); + if (td->td_user_pri != lower) + goto lend; + if (td->td_priority >= td->td_user_pri) + goto lend; + return; + +lend: + thread_lock(td); + sched_lend_user_prio(td, prio); + thread_unlock(td); +} + #ifdef SMP /* * This tdq is about to idle. Try to steal a thread from another CPU before Index: sys/sys/sched.h =================================================================== --- sys/sys/sched.h +++ sys/sys/sched.h @@ -96,6 +96,7 @@ void sched_fork_thread(struct thread *td, struct thread *child); void sched_lend_prio(struct thread *td, u_char prio); void sched_lend_user_prio(struct thread *td, u_char pri); +void sched_lend_user_prio_cond(struct thread *td, u_char pri); fixpt_t sched_pctcpu(struct thread *td); void sched_prio(struct thread *td, u_char prio); void sched_sleep(struct thread *td, int prio);