This patch fixes PR52526, a lost wake-up in libitm (ie, one ore more
threads could hang and not get woken up anymore).
The problem was missing handling of one corner case in the futex-based
serial lock implementation (config/linux/rwlock.cc, read_lock()):
Multiple readers would set READERS to 1 and only call
futex_wait(&readers, 1) if there were any writers. Writers would set
READERS to 0 and then call futex_wake(&readers). That's fine, but
because there are multiple readers, it can happen that some would set
READERS to 1 after the writer's futex_wake() call, enabling the
futex_wait() in other readers (because READERS isn't 0 anymore). This
patch fixes this by having readers wake up all potentially waiting
readers when they set READERS to 1 without an existing writer (thus
taking over what the writer would do).
OK for trunk?
OK for 4.7 too? This is a showstopper if users hit it, so I'd prefer if
it could go into 4.7 as well.
Author: Torvald Riegel <trie...@redhat.com>
Date: Sat Mar 10 17:44:37 2012 +0100
libitm: Fix lost wake-up in serial lock.
* config/linux/rwlock.cc (GTM::gtm_rwlock::read_lock): Fix lost
diff --git a/libitm/config/linux/rwlock.cc b/libitm/config/linux/rwlock.cc
index ad1b042..cf1fdd5 100644
@@ -74,6 +74,32 @@ gtm_rwlock::read_lock (gtm_thread *tx)
if (writers.load (memory_order_relaxed))
+ // There is no writer, actually. However, we can have enabled
+ // a futex_wait in other readers by previously setting readers
+ // to 1, so we have to wake them up because there is no writer
+ // that will do that. We don't know whether the wake-up is
+ // really necessary, but we can get lost wake-up situations
+ // otherwise.
+ // No additional barrier nor a nonrelaxed load is required due
+ // to coherency constraints. write_unlock() checks readers to
+ // see if any wake-up is necessary, but it is not possible that
+ // a reader's store prevents a required later writer wake-up;
+ // If the waking reader's store (value 0) is in modification
+ // order after the waiting readers store (value 1), then the
+ // latter will have to read 0 in the futex due to coherency
+ // constraints and the happens-before enforced by the futex
+ // (paragraph 6.10 in the standard, 6.19.4 in the Batty et al
+ // TR); second, the writer will be forced to read in
+ // modification order too due to Dekker-style synchronization
+ // with the waiting reader (see write_unlock()).
+ // ??? Can we avoid the wake-up if readers is zero (like in
+ // write_unlock())? Anyway, this might happen too infrequently
+ // to improve performance significantly.
+ readers.store (0, memory_order_relaxed);
+ futex_wake(&readers, INT_MAX);
// And we try again to acquire a read lock.