Always use CLOCK_MONOTONIC for pthreads and semaphores
pthread's and semaphore's default behavior is to use CLOCK_REALTIME,
however this behavior is essentially never intended, as that clock is
prone to change discontinuously.
What users really intend is to use CLOCK_MONOTONIC, however only
pthread_cond_timedwait() provides this as an option and even there, a
large amount of existing code does not opt into CLOCK_MONOTONIC.
We have seen numerous bugs directly attributable to this difference.
Therefore, we provide this general workaround to always use
CLOCK_MONOTONIC for waiting, regardless of what the input timespec
is.
Specifically this impacts the below APIs:
pthread_mutex_timedlock()
pthread_cond_timedwait()
pthread_rwlock_timedrdlock()
pthread_rwlock_timedwrlock()
sem_timedwait()
Test: boot bullhead, boot sailfish
Test: bionic pthread/semaphore unit tests
Test: check that pthread_cond_timedwait() timeouts are uneffected by
CLOCK_REALTIME time changes
Bug: 64694413
Bug: 64623895
Bug: 35756266
Bug: 35678943
Change-Id: Ibba98f5d88be1c306d14e9b9366302ecbef6d534
diff --git a/libc/private/bionic_futex.h b/libc/private/bionic_futex.h
index 946d9dd..9b89131 100644
--- a/libc/private/bionic_futex.h
+++ b/libc/private/bionic_futex.h
@@ -36,13 +36,10 @@
#include <sys/syscall.h>
#include <unistd.h>
-__BEGIN_DECLS
-
struct timespec;
static inline __always_inline int __futex(volatile void* ftx, int op, int value,
- const struct timespec* timeout,
- int bitset) {
+ const timespec* timeout, int bitset) {
// Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
int saved_errno = errno;
int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);
@@ -61,17 +58,16 @@
return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL, 0);
}
-static inline int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
+static inline int __futex_wait(volatile void* ftx, int value, const timespec* timeout) {
return __futex(ftx, FUTEX_WAIT, value, timeout, 0);
}
-static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value,
- bool use_realtime_clock, const struct timespec* abs_timeout) {
- return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE) |
- (use_realtime_clock ? FUTEX_CLOCK_REALTIME : 0), value, abs_timeout,
+static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value) {
+ return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE), value, nullptr,
FUTEX_BITSET_MATCH_ANY);
}
-__END_DECLS
+__LIBC_HIDDEN__ int __futex_wait_ex(volatile void* ftx, bool shared, int value,
+ bool use_realtime_clock, const timespec* abs_timeout);
#endif /* _BIONIC_FUTEX_H */
diff --git a/libc/private/bionic_lock.h b/libc/private/bionic_lock.h
index 3dbafe0..b389247 100644
--- a/libc/private/bionic_lock.h
+++ b/libc/private/bionic_lock.h
@@ -64,7 +64,7 @@
}
while (atomic_exchange_explicit(&state, LockedWithWaiter, memory_order_acquire) != Unlocked) {
// TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
- __futex_wait_ex(&state, process_shared, LockedWithWaiter, false, nullptr);
+ __futex_wait_ex(&state, process_shared, LockedWithWaiter);
}
return;
}
diff --git a/libc/private/bionic_time_conversions.h b/libc/private/bionic_time_conversions.h
index b9eaad2..fb049f2 100644
--- a/libc/private/bionic_time_conversions.h
+++ b/libc/private/bionic_time_conversions.h
@@ -42,6 +42,9 @@
__LIBC_HIDDEN__ void timeval_from_timespec(timeval& tv, const timespec& ts);
+__LIBC_HIDDEN__ void monotonic_time_from_realtime_time(timespec& monotonic_time,
+ const timespec& realtime_time);
+
__END_DECLS
static inline int check_timespec(const timespec* ts, bool null_allowed) {