Re: [RFC PATCH 04/16] sched/core: Activate blocked donor when no owner is found

From: John Stultz

Date: Tue Sep 15 2026 - 23:30:11 EST


On Tue, Aug 25, 2026 at 11:30 PM K Prateek Nayak <kprateek.nayak@xxxxxxx> wrote:
>
> mutex_unlock_slowpath() follows:
>
> if (owner & MUTEX_FLAG_HANDOFF)
> break /* ... and do __mutex_handoff() */
>
> if (atomic_long_try_cmpxchg_release(&lock->owner, &owner, __owner_flags(owner))) {
> if (owner & MUTEX_FLAG_WAITERS)
> break; /* ... and wake up the forst waiter. */
>
> MUTEX_FLAG_HANDOFF is only set by first-waiter after it has been woken
> up and in absence of MUTEX_FLAG_HANDOFF, the owner clears itself from
> the lock_word and wakes up the first waiter to try a
> __mutex_trylock_or_handoff().

We also set it when there is a blocked_donor, to ensure the task
donating its time to the owner gets the lock next.

> MUTEX_FLAG_HANDOFF exists to prevent new optimistic spinners from
> trying to hijack the lock from waiter all the time and potentially
> starving them but it is not necessary for MUTEX_FLAG_HANDOFF to be
> always set in presence of a waiter.
>
> If a blocked donor is deactivated when no owner is observed, it may not
> be woken up until it becomes the first waiter and is naturally woken up
> which breaks proxy in the interim.

Hrm. So in older versions of the proxy-migration/return-migration
logic, if the owner was NULL we'd clear the donor's blocked_on and
either run it or do return migration, which I guess wouldn't see this
issue.

I'm curious, is this behavior something you've observed directly or
did you just find it through code inspection?

I'm wondering as in playing with Suleiman's proxy-futex work I've seen
a few traces that had some unexpected behavior and I'm wondering if
this might be the cause.

> Wake up the blocked donor and allow it to grab the lock when no owner is
> observed. If the task manages to grab the lock, the block chain will
> follow at the next proxy migration. If the task fails to grab the lock,
> same situation is restored and everyone migrated to the CPU of new
> owner.

This seems reasonable to me. For the situation to occcur, we'd need
the task A to be deep on the waiter list, and be in blocked_on chain
from a selected donor, and the lock its blocked on to be unlocked and
ownerlist before the woken top waiter is able to take it.

If the task is important enough to be in a donor chain, then we might
as well wake it and let it try to steal the lock. That seems better
than deactivating it and the whole chain until it rises to the top of
the lock waiter-list. Especaially as if we came in a moment later and
found it owned, we'd be potentially migrating the whole chain to a
different runqueue just to boost it. So yeah, making the most of the
opportunity and trying to grab it makes sense to me.

>
> Fixes: f13beb010e4a ("sched: Have try_to_wake_up() handle return-migration for PROXY_WAKING case")
> Signed-off-by: K Prateek Nayak <kprateek.nayak@xxxxxxx>
> ---
> XXX: Is there a better way to handle this? If we can confirm a owner in
> find_proxy_task(), we don't need to do a spurious wakeup of every task
> observing !owner.

I guess I'd want to get some metrics to see how common spurious
wakeups are and how problematic they might be.

> proxy_resched_idle() until owner appears in an option but it will spin
> until next owner appears.

Eh, that feels wasteful (especially if the top waiter unlock woke up
ends up deep in the runqueue and doesn't run for awhile - I see Andrea
raised this point).

I've lightly tested with this and it seemed ok. Though I want to do
some more runs with it applied along with the proxy-futex code to
understand if it helps.

Acked-by: John Stultz <jstultz@xxxxxxxxxx>