diff options
-rw-r--r-- | absl/synchronization/mutex.cc | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index 27fd6a50..47032677 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -991,6 +991,24 @@ static PerThreadSynch* Enqueue(PerThreadSynch* head, SynchWaitParams* waitp, if (MuEquivalentWaiter(s, s->next)) { // s->may_skip is known to be true s->skip = s->next; // s may skip to its successor } + } else if ((flags & kMuHasBlocked) && + (s->priority >= head->next->priority) && + (!head->maybe_unlocking || + (waitp->how == kExclusive && + Condition::GuaranteedEqual(waitp->cond, nullptr)))) { + // This thread has already waited, then was woken, then failed to acquire + // the mutex and now tries to requeue. Try to requeue it at head, + // otherwise it can suffer bad latency (wait whole queue several times). + // However, we need to be conservative. First, we need to ensure that we + // respect priorities. Then, we need to be careful to not break wait + // queue invariants: we require either that unlocker is not scanning + // the queue or that the current thread is a writer with no condition + // (unlocker will recheck the queue for such waiters). + s->next = head->next; + head->next = s; + if (MuEquivalentWaiter(s, s->next)) { // s->may_skip is known to be true + s->skip = s->next; // s may skip to its successor + } } else { // enqueue not done any other way, so // we're inserting s at the back // s will become new head; copy data from head into it |