Add _monotonic_np versions of timed wait functions
As a follow up to Ibba98f5d88be1c306d14e9b9366302ecbef6d534, where we
added a work around to convert the CLOCK_REALTIME timeouts to
CLOCK_MONOTONIC for pthread and semaphore timed wait functions, we're
introducing a set of _monotonic_np versions of each of these functions
that wait on CLOCK_MONOTONIC directly.
The primary motivation here is that while the above work around helps
for 3rd party code, it creates a dilemma when implementing new code
that would use these functions: either one implements code with these
functions knowing there is a race condition possible or one avoids
these functions and reinvent their own waiting/signaling mechanisms.
Neither are satisfactory, so we create a third option to use these
Android specific _monotonic_np functions that completely remove the
race condition while keeping the rest of the interface.
Specifically this adds the below functions:
pthread_mutex_timedlock_monotonic_np()
pthread_cond_timedwait_monotonic_np()
pthread_rwlock_timedrdlock_monotonic_np()
pthread_rwlock_timedwrlock_monotonic_np()
sem_timedwait_monotonic_np()
Note that pthread_cond_timedwait_monotonic_np() previously existed and
was removed since it's possible to initialize a condition variable to
use CLOCK_MONOTONIC. It is added back for a mix of reasons,
1) Symmetry with the rest of the functions we're adding
2) libc++ cannot easily take advantage of the new initializer, but
will be able to use this function in order to wait on
std::steady_clock
3) Frankly, it's a better API to specify the clock in the waiter function
than to specify the clock when the condition variable is
initialized.
Bug: 73951740
Test: new unit tests
Change-Id: I23aa5c204e36a194237d41e064c5c8ccaa4204e3
diff --git a/libc/bionic/pthread_cond.cpp b/libc/bionic/pthread_cond.cpp
index cbe67f9..a42506a 100644
--- a/libc/bionic/pthread_cond.cpp
+++ b/libc/bionic/pthread_cond.cpp
@@ -209,19 +209,18 @@
return __pthread_cond_timedwait(cond, mutex, cond->use_realtime_clock(), abstime);
}
+extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interface,
+ pthread_mutex_t* mutex,
+ const timespec* abs_timeout) {
+ return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout);
+}
+
#if !defined(__LP64__)
// TODO: this exists only for backward binary compatibility on 32 bit platforms.
extern "C" int pthread_cond_timedwait_monotonic(pthread_cond_t* cond_interface,
pthread_mutex_t* mutex,
const timespec* abs_timeout) {
-
- return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout);
-}
-
-extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interface,
- pthread_mutex_t* mutex,
- const timespec* abs_timeout) {
- return pthread_cond_timedwait_monotonic(cond_interface, mutex, abs_timeout);
+ return pthread_cond_timedwait_monotonic_np(cond_interface, mutex, abs_timeout);
}
// Force this function using CLOCK_MONOTONIC because it was always using
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index 9f9a0c2..7f48972 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -176,6 +176,7 @@
// Inlining this function in pthread_mutex_lock() adds the cost of stack frame instructions on
// ARM/ARM64, which increases at most 20 percent overhead. So make it noinline.
static int __attribute__((noinline)) PIMutexTimedLock(PIMutex& mutex,
+ bool use_realtime_clock,
const timespec* abs_timeout) {
int ret = PIMutexTryLock(mutex);
if (__predict_true(ret == 0)) {
@@ -183,7 +184,7 @@
}
if (ret == EBUSY) {
ScopedTrace trace("Contending for pthread mutex");
- ret = -__futex_pi_lock_ex(&mutex.owner_tid, mutex.shared, true, abs_timeout);
+ ret = -__futex_pi_lock_ex(&mutex.owner_tid, mutex.shared, use_realtime_clock, abs_timeout);
}
return ret;
}
@@ -820,7 +821,7 @@
if (__predict_true(PIMutexTryLock(m) == 0)) {
return 0;
}
- return PIMutexTimedLock(mutex->ToPIMutex(), nullptr);
+ return PIMutexTimedLock(mutex->ToPIMutex(), false, nullptr);
}
if (__predict_false(IsMutexDestroyed(old_state))) {
return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__);
@@ -948,7 +949,8 @@
}
#endif
-int pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, const timespec* abs_timeout) {
+static int __pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, bool use_realtime_clock,
+ const timespec* abs_timeout, const char* function) {
pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
uint16_t mtype = (old_state & MUTEX_TYPE_MASK);
@@ -960,12 +962,21 @@
}
}
if (old_state == PI_MUTEX_STATE) {
- return PIMutexTimedLock(mutex->ToPIMutex(), abs_timeout);
+ return PIMutexTimedLock(mutex->ToPIMutex(), use_realtime_clock, abs_timeout);
}
if (__predict_false(IsMutexDestroyed(old_state))) {
- return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__);
+ return HandleUsingDestroyedMutex(mutex_interface, function);
}
- return NonPI::MutexLockWithTimeout(mutex, true, abs_timeout);
+ return NonPI::MutexLockWithTimeout(mutex, use_realtime_clock, abs_timeout);
+}
+
+int pthread_mutex_timedlock(pthread_mutex_t* mutex_interface, const struct timespec* abs_timeout) {
+ return __pthread_mutex_timedlock(mutex_interface, true, abs_timeout, __FUNCTION__);
+}
+
+int pthread_mutex_timedlock_monotonic_np(pthread_mutex_t* mutex_interface,
+ const struct timespec* abs_timeout) {
+ return __pthread_mutex_timedlock(mutex_interface, false, abs_timeout, __FUNCTION__);
}
int pthread_mutex_destroy(pthread_mutex_t* mutex_interface) {
diff --git a/libc/bionic/pthread_rwlock.cpp b/libc/bionic/pthread_rwlock.cpp
index a065295..4f4c461 100644
--- a/libc/bionic/pthread_rwlock.cpp
+++ b/libc/bionic/pthread_rwlock.cpp
@@ -286,9 +286,8 @@
return EBUSY;
}
-static int __pthread_rwlock_timedrdlock(pthread_rwlock_internal_t* rwlock,
+static int __pthread_rwlock_timedrdlock(pthread_rwlock_internal_t* rwlock, bool use_realtime_clock,
const timespec* abs_timeout_or_null) {
-
if (atomic_load_explicit(&rwlock->writer_tid, memory_order_relaxed) == __get_thread()->tid) {
return EDEADLK;
}
@@ -324,7 +323,7 @@
int futex_result = 0;
if (!__can_acquire_read_lock(old_state, rwlock->writer_nonrecursive_preferred)) {
futex_result = __futex_wait_ex(&rwlock->pending_reader_wakeup_serial, rwlock->pshared,
- old_serial, true, abs_timeout_or_null);
+ old_serial, use_realtime_clock, abs_timeout_or_null);
}
rwlock->pending_lock.lock();
@@ -359,9 +358,8 @@
return EBUSY;
}
-static int __pthread_rwlock_timedwrlock(pthread_rwlock_internal_t* rwlock,
+static int __pthread_rwlock_timedwrlock(pthread_rwlock_internal_t* rwlock, bool use_realtime_clock,
const timespec* abs_timeout_or_null) {
-
if (atomic_load_explicit(&rwlock->writer_tid, memory_order_relaxed) == __get_thread()->tid) {
return EDEADLK;
}
@@ -392,7 +390,7 @@
int futex_result = 0;
if (!__can_acquire_write_lock(old_state)) {
futex_result = __futex_wait_ex(&rwlock->pending_writer_wakeup_serial, rwlock->pshared,
- old_serial, true, abs_timeout_or_null);
+ old_serial, use_realtime_clock, abs_timeout_or_null);
}
rwlock->pending_lock.lock();
@@ -415,13 +413,20 @@
if (__predict_true(__pthread_rwlock_tryrdlock(rwlock) == 0)) {
return 0;
}
- return __pthread_rwlock_timedrdlock(rwlock, nullptr);
+ return __pthread_rwlock_timedrdlock(rwlock, false, nullptr);
}
int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) {
pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
- return __pthread_rwlock_timedrdlock(rwlock, abs_timeout);
+ return __pthread_rwlock_timedrdlock(rwlock, true, abs_timeout);
+}
+
+int pthread_rwlock_timedrdlock_monotonic_np(pthread_rwlock_t* rwlock_interface,
+ const timespec* abs_timeout) {
+ pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
+
+ return __pthread_rwlock_timedrdlock(rwlock, false, abs_timeout);
}
int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock_interface) {
@@ -434,13 +439,20 @@
if (__predict_true(__pthread_rwlock_trywrlock(rwlock) == 0)) {
return 0;
}
- return __pthread_rwlock_timedwrlock(rwlock, nullptr);
+ return __pthread_rwlock_timedwrlock(rwlock, false, nullptr);
}
int pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock_interface, const timespec* abs_timeout) {
pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
- return __pthread_rwlock_timedwrlock(rwlock, abs_timeout);
+ return __pthread_rwlock_timedwrlock(rwlock, true, abs_timeout);
+}
+
+int pthread_rwlock_timedwrlock_monotonic_np(pthread_rwlock_t* rwlock_interface,
+ const timespec* abs_timeout) {
+ pthread_rwlock_internal_t* rwlock = __get_internal_rwlock(rwlock_interface);
+
+ return __pthread_rwlock_timedwrlock(rwlock, false, abs_timeout);
}
int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock_interface) {
diff --git a/libc/bionic/semaphore.cpp b/libc/bionic/semaphore.cpp
index 610a1b2..d401b66 100644
--- a/libc/bionic/semaphore.cpp
+++ b/libc/bionic/semaphore.cpp
@@ -231,7 +231,7 @@
}
}
-int sem_timedwait(sem_t* sem, const timespec* abs_timeout) {
+static int __sem_timedwait(sem_t* sem, const timespec* abs_timeout, bool use_realtime_clock) {
atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem);
// POSIX says we need to try to decrement the semaphore
@@ -257,7 +257,8 @@
}
// Contention detected. Wait for a wakeup event.
- int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE, true, abs_timeout);
+ int result = __futex_wait_ex(sem_count_ptr, shared, shared | SEMCOUNT_MINUS_ONE,
+ use_realtime_clock, abs_timeout);
// Return in case of timeout or interrupt.
if (result == -ETIMEDOUT || result == -EINTR) {
@@ -267,6 +268,14 @@
}
}
+int sem_timedwait(sem_t* sem, const timespec* abs_timeout) {
+ return __sem_timedwait(sem, abs_timeout, true);
+}
+
+int sem_timedwait_monotonic_np(sem_t* sem, const timespec* abs_timeout) {
+ return __sem_timedwait(sem, abs_timeout, false);
+}
+
int sem_post(sem_t* sem) {
atomic_uint* sem_count_ptr = SEM_TO_ATOMIC_POINTER(sem);
unsigned int shared = SEM_GET_SHARED(sem_count_ptr);
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 8d95a3b..5b0c3a2 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -122,6 +122,16 @@
int pthread_cond_init(pthread_cond_t* __cond, const pthread_condattr_t* __attr);
int pthread_cond_signal(pthread_cond_t* __cond);
int pthread_cond_timedwait(pthread_cond_t* __cond, pthread_mutex_t* __mutex, const struct timespec* __timeout);
+/*
+ * Condition variables use CLOCK_REALTIME by default for their timeouts, however that is
+ * typically inappropriate, since that clock can change dramatically, causing the timeout to
+ * either expire earlier or much later than intended.
+ * Condition variables have an initialization option to use CLOCK_MONOTONIC, and in addition,
+ * Android provides this API to use CLOCK_MONOTONIC on a condition variable for this single wait
+ * no matter how it was initialized.
+ */
+int pthread_cond_timedwait_monotonic_np(pthread_cond_t* __cond, pthread_mutex_t* __mutex,
+ const struct timespec* __timeout) __INTRODUCED_IN_64(28);
int pthread_cond_wait(pthread_cond_t* __cond, pthread_mutex_t* __mutex);
int pthread_create(pthread_t* __pthread_ptr, pthread_attr_t const* __attr, void* (*__start_routine)(void*), void*);
@@ -159,6 +169,16 @@
int pthread_mutex_lock(pthread_mutex_t* __mutex);
int pthread_mutex_timedlock(pthread_mutex_t* __mutex, const struct timespec* __timeout)
__INTRODUCED_IN(21);
+
+/*
+ * POSIX only supports using pthread_mutex_timedlock() with CLOCK_REALTIME, however that is
+ * typically inappropriate, since that clock can change dramatically, causing the timeout to
+ * either expire earlier or much later than intended.
+ * This function is added to use a timespec based on CLOCK_MONOTONIC that does not suffer
+ * from this issue.
+ */
+int pthread_mutex_timedlock_monotonic_np(pthread_mutex_t* __mutex, const struct timespec* __timeout)
+ __INTRODUCED_IN(28);
int pthread_mutex_trylock(pthread_mutex_t* __mutex);
int pthread_mutex_unlock(pthread_mutex_t* __mutex);
@@ -176,7 +196,6 @@
*/
int pthread_mutex_lock_timeout_np(pthread_mutex_t* __mutex, unsigned __timeout_ms);
int pthread_cond_timeout_np(pthread_cond_t* __cond, pthread_mutex_t* __mutex, unsigned __timeout_ms);
-int pthread_cond_timedwait_monotonic_np(pthread_cond_t* __cond, pthread_mutex_t* __mutex, const struct timespec* __timeout);
int pthread_cond_timedwait_relative_np(pthread_cond_t* __cond, pthread_mutex_t* __mutex, const struct timespec* __relative_timeout);
#endif
@@ -194,7 +213,13 @@
int pthread_rwlock_init(pthread_rwlock_t* __rwlock, const pthread_rwlockattr_t* __attr);
int pthread_rwlock_rdlock(pthread_rwlock_t* __rwlock);
int pthread_rwlock_timedrdlock(pthread_rwlock_t* __rwlock, const struct timespec* __timeout);
+/* See the comment on pthread_mutex_timedlock_monotonic_np for usage of this function. */
+int pthread_rwlock_timedrdlock_monotonic_np(pthread_rwlock_t* __rwlock,
+ const struct timespec* __timeout) __INTRODUCED_IN(28);
int pthread_rwlock_timedwrlock(pthread_rwlock_t* __rwlock, const struct timespec* __timeout);
+/* See the comment on pthread_mutex_timedlock_monotonic_np for usage of this function. */
+int pthread_rwlock_timedwrlock_monotonic_np(pthread_rwlock_t* __rwlock,
+ const struct timespec* __timeout) __INTRODUCED_IN(28);
int pthread_rwlock_tryrdlock(pthread_rwlock_t* __rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t* __rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t* __rwlock);
diff --git a/libc/include/semaphore.h b/libc/include/semaphore.h
index 7e3dc1c..01d685b 100644
--- a/libc/include/semaphore.h
+++ b/libc/include/semaphore.h
@@ -49,6 +49,13 @@
int sem_init(sem_t* __sem, int __shared, unsigned int __value);
int sem_post(sem_t* __sem);
int sem_timedwait(sem_t* __sem, const struct timespec* __ts);
+/*
+ * POSIX only supports using sem_timedwait() with CLOCK_REALTIME, however that is typically
+ * inappropriate, since that clock can change dramatically, causing the timeout to either
+ * expire earlier or much later than intended. This function is added to use a timespec based
+ * on CLOCK_MONOTONIC that does not suffer from this issue.
+ */
+int sem_timedwait_monotonic_np(sem_t* __sem, const struct timespec* __ts) __INTRODUCED_IN(28);
int sem_trywait(sem_t* __sem);
int sem_wait(sem_t* __sem);
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 19c80b7..b0f96a9 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -745,7 +745,7 @@
pthread_cond_signal;
pthread_cond_timedwait;
pthread_cond_timedwait_monotonic; # arm x86 mips
- pthread_cond_timedwait_monotonic_np; # arm x86 mips
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_timedwait_relative_np; # arm x86 mips
pthread_cond_timeout_np; # arm x86 mips
pthread_cond_wait;
@@ -1385,10 +1385,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index cab66e6..6b0e415 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -691,6 +691,7 @@
pthread_cond_init;
pthread_cond_signal;
pthread_cond_timedwait;
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_wait;
pthread_condattr_destroy;
pthread_condattr_getclock; # introduced=21
@@ -1305,10 +1306,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 65e4802..85c9a58 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -770,7 +770,7 @@
pthread_cond_signal;
pthread_cond_timedwait;
pthread_cond_timedwait_monotonic; # arm x86 mips
- pthread_cond_timedwait_monotonic_np; # arm x86 mips
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_timedwait_relative_np; # arm x86 mips
pthread_cond_timeout_np; # arm x86 mips
pthread_cond_wait;
@@ -1410,10 +1410,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 363a55a..9e760c2 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -743,7 +743,7 @@
pthread_cond_signal;
pthread_cond_timedwait;
pthread_cond_timedwait_monotonic; # arm x86 mips
- pthread_cond_timedwait_monotonic_np; # arm x86 mips
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_timedwait_relative_np; # arm x86 mips
pthread_cond_timeout_np; # arm x86 mips
pthread_cond_wait;
@@ -1369,10 +1369,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index cab66e6..6b0e415 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -691,6 +691,7 @@
pthread_cond_init;
pthread_cond_signal;
pthread_cond_timedwait;
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_wait;
pthread_condattr_destroy;
pthread_condattr_getclock; # introduced=21
@@ -1305,10 +1306,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index fc5e463..2855f9e 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -741,7 +741,7 @@
pthread_cond_signal;
pthread_cond_timedwait;
pthread_cond_timedwait_monotonic; # arm x86 mips
- pthread_cond_timedwait_monotonic_np; # arm x86 mips
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_timedwait_relative_np; # arm x86 mips
pthread_cond_timeout_np; # arm x86 mips
pthread_cond_wait;
@@ -1367,10 +1367,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index cab66e6..6b0e415 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -691,6 +691,7 @@
pthread_cond_init;
pthread_cond_signal;
pthread_cond_timedwait;
+ pthread_cond_timedwait_monotonic_np; # introduced-arm=16 introduced-x86=16 introduced-mips=16 introduced-arm64=28 introduced-x64_64=28 introduced-mips64=28
pthread_cond_wait;
pthread_condattr_destroy;
pthread_condattr_getclock; # introduced=21
@@ -1305,10 +1306,14 @@
pselect64;
pthread_attr_getinheritsched;
pthread_attr_setinheritsched;
+ pthread_mutex_timedlock_monotonic_np;
pthread_mutexattr_getprotocol;
pthread_mutexattr_setprotocol;
+ pthread_rwlock_timedrdlock_monotonic_np;
+ pthread_rwlock_timedwrlock_monotonic_np;
pthread_setschedprio;
pthread_sigmask64;
+ sem_timedwait_monotonic_np;
sethostent;
setnetent;
setprotoent;