Ensure seq_cst memory ordering for num_contenders

Problem.
Mutexes and ReaderWriterMutexes can lose wakeups due to
weak memory ordering. An unlocking thread may overlook waiters.

Thread A
0. ExclusiveLock
1. increase num_contenders as default ordering.
  (fetch_add, std::memory_order_seq_cst)
2. futex waiting
...permently waiting
3. wakeup
4. decrease num_contenders
5. running

Thread B
0. Reset lock state to unlocked using seq_cst CAS.
1. load num_contenders with LoadRelaxed
   (std::memory_order_relaxed)
2. if num_contenders is bigger than 0, wakeup waiters.

Thread B's load of num_contenders may be reordered with the store
in the preceding CAS (step 0).

We can then get the following interleaving:
A.0 (fails: lock held.)
B.0a (CAS load acquire sees lock as held)
B.1 (sees num_contenders = 0)
A.1 num_contenders++;
A.2 futex starts waiting (state unchanged)
B.0b (CAS store release sets state to unlocked)
B.2 (does nothing since num_contenders was 0)

We observed this hang with state_ = 0,
exclusive_owner_ = 0, num_contenders_ = 1
Indeed, the preceding comment strongly suggests that the num_contenders
load should not be relaxed.

Test: test-art-host, test-art-target

Change-Id: I912bcd3a186d9c36fb3da8a41c1f9aa1f7b39be5
Signed-off-by: Hyangseok Chae <neo.chae@lge.com>
2 files changed