base: Give lock parking its own Task link set
A task whose condition wait was cancelled resumes with its wait-node
edge links still in the condition's queue (the canceller deliberately
does not take waitee locks; stale entries are collected lazily). If the
condition lock is contended, reacquiring it parked the task through the
same folded wait node - 'val already in a list' thrown while holding
the lock's internal spinlock, corrupting the lock and deadlocking its
holder.
Both .NET and tokio structurally forbid this shape: no operation's
parking may depend on another operation's registration (.NET keeps the
lock's contention path registration-free; tokio gives every wait
operation its own pinned node). Adopt the same invariant with a third
Task link set: ReentrantLock's internal queue now links parked
acquirers through dedicated lock_next/lock_queue fields, disjoint from
both the scheduler links and the condition-wait node, so the reacquire
can always park. The reacquire in relockall is also no longer
cancellable: it is the cleanup half of a wait whose outcome was already
delivered, and a cancelled scope must not throw out of it without the
lock.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015KLwCBAR64r3cTdfaC5krU