summaryrefslogtreecommitdiffstats
path: root/libc/bionic
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2015-04-02 17:47:48 -0700
committerYabin Cui <yabinc@google.com>2015-04-03 19:01:17 -0700
commitf796985923e2d8308e00ed9567f36546dafb98d7 (patch)
tree4fd9bbdae36ecfd15a4e08cdad3c7818995760ec /libc/bionic
parent06b6e3c51d38d70c5ca99f3a3f795697031ac27f (diff)
downloadbionic-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.cpp26
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);