diff options
author | Yabin Cui <yabinc@google.com> | 2015-04-02 17:47:48 -0700 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2015-04-03 19:01:17 -0700 |
commit | f796985923e2d8308e00ed9567f36546dafb98d7 (patch) | |
tree | 4fd9bbdae36ecfd15a4e08cdad3c7818995760ec /libc/bionic | |
parent | 06b6e3c51d38d70c5ca99f3a3f795697031ac27f (diff) | |
download | bionic-f796985923e2d8308e00ed9567f36546dafb98d7.zip bionic-f796985923e2d8308e00ed9567f36546dafb98d7.tar.gz bionic-f796985923e2d8308e00ed9567f36546dafb98d7.tar.bz2 |
Fix bug for recursive/errorcheck mutex on 32-bit devices.
Bug: 19216648
Change-Id: I3b43b2d18d25b9bde352da1e35f9568133dec7cf
Diffstat (limited to 'libc/bionic')
-rw-r--r-- | libc/bionic/pthread_mutex.cpp | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp index 5bdc5ed..4fec753 100644 --- a/libc/bionic/pthread_mutex.cpp +++ b/libc/bionic/pthread_mutex.cpp @@ -392,6 +392,30 @@ static inline __always_inline int __recursive_increment(pthread_mutex_internal_t return 0; } +static inline __always_inline int __recursive_or_errorcheck_mutex_wait( + pthread_mutex_internal_t* mutex, + uint16_t shared, + uint16_t old_state, + const timespec* rel_timeout) { +// __futex_wait always waits on a 32-bit value. But state is 16-bit. For a normal mutex, the owner_tid +// field in mutex is not used. On 64-bit devices, the __pad field in mutex is not used. +// But when a recursive or errorcheck mutex is used on 32-bit devices, we need to add the +// owner_tid value in the value argument for __futex_wait, otherwise we may always get EAGAIN error. + +#if defined(__LP64__) + return __futex_wait_ex(&mutex->state, shared, old_state, rel_timeout); + +#else + // This implementation works only when the layout of pthread_mutex_internal_t matches below expectation. + // And it is based on the assumption that Android is always in little-endian devices. + static_assert(offsetof(pthread_mutex_internal_t, state) == 0, ""); + static_assert(offsetof(pthread_mutex_internal_t, owner_tid) == 2, ""); + + uint32_t owner_tid = atomic_load_explicit(&mutex->owner_tid, memory_order_relaxed); + return __futex_wait_ex(&mutex->state, shared, (owner_tid << 16) | old_state, rel_timeout); +#endif +} + static int __pthread_mutex_lock_with_timeout(pthread_mutex_internal_t* mutex, const timespec* abs_timeout_or_null, clockid_t clock) { uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); @@ -469,7 +493,7 @@ static int __pthread_mutex_lock_with_timeout(pthread_mutex_internal_t* mutex, return ETIMEDOUT; } } - if (__futex_wait_ex(&mutex->state, shared, old_state, rel_timeout) == -ETIMEDOUT) { + if (__recursive_or_errorcheck_mutex_wait(mutex, shared, old_state, rel_timeout) == -ETIMEDOUT) { return ETIMEDOUT; } old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); |