Merge "timer_create: use SIG_SETMASK restore the signal mask."
diff --git a/libc/Android.bp b/libc/Android.bp
index 20df52c..360aea3 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -285,7 +285,6 @@
 
     cflags: [
         "-Wno-sign-compare",
-        "-Wno-uninitialized",
         "-Wno-unused-parameter",
         "-include freebsd-compat.h",
     ],
@@ -368,7 +367,6 @@
     },
     cflags: [
         "-Wno-sign-compare",
-        "-Wno-uninitialized",
         "-Wno-unused-parameter",
         "-DPOSIX_MISTAKE",
         "-include netbsd-compat.h",
@@ -498,7 +496,6 @@
 
     cflags: [
         "-Wno-sign-compare",
-        "-Wno-uninitialized",
         "-Wno-unused-parameter",
         "-include openbsd-compat.h",
     ],
@@ -638,7 +635,6 @@
 
     cflags: [
         "-Wno-sign-compare",
-        "-Wno-uninitialized",
         "-Wno-unused-parameter",
         "-include openbsd-compat.h",
     ],
@@ -688,7 +684,6 @@
 
     cflags: [
         "-Wno-sign-compare",
-        "-Wno-uninitialized",
         "-include openbsd-compat.h",
     ],
 
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 f1f7294..7f48972 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -40,7 +40,9 @@
 #include "pthread_internal.h"
 
 #include "private/bionic_constants.h"
+#include "private/bionic_fortify.h"
 #include "private/bionic_futex.h"
+#include "private/bionic_sdk_version.h"
 #include "private/bionic_systrace.h"
 #include "private/bionic_time_conversions.h"
 #include "private/bionic_tls.h"
@@ -171,9 +173,10 @@
     return EBUSY;
 }
 
-// Inlining this function in pthread_mutex_lock() add the cost of stack frame instructions on
+// 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)) {
@@ -181,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;
 }
@@ -413,7 +416,7 @@
 #define  MUTEX_TYPE_BITS_RECURSIVE   MUTEX_TYPE_TO_BITS(PTHREAD_MUTEX_RECURSIVE)
 #define  MUTEX_TYPE_BITS_ERRORCHECK  MUTEX_TYPE_TO_BITS(PTHREAD_MUTEX_ERRORCHECK)
 // Use a special mutex type to mark priority inheritance mutexes.
-#define  MUTEX_TYPE_BITS_WITH_PI     MUTEX_TYPE_TO_BITS(3)
+#define  PI_MUTEX_STATE     MUTEX_TYPE_TO_BITS(3)
 
 // For a PI mutex, it includes below fields:
 //   Atomic(uint16_t) state;
@@ -423,6 +426,7 @@
 //
 //   bits:   name    description
 //   15-14   type    mutex type, should be 3
+//   13-0    padding should be 0
 //
 //   pi_mutex holds the state of a PI mutex.
 //   pi_mutex_id holds an integer to find the state of a PI mutex.
@@ -533,7 +537,7 @@
         }
         mutex->pi_mutex_id = id;
 #endif
-        atomic_init(&mutex->state, MUTEX_TYPE_BITS_WITH_PI);
+        atomic_init(&mutex->state, PI_MUTEX_STATE);
         PIMutex& pi_mutex = mutex->ToPIMutex();
         pi_mutex.type = *attr & MUTEXATTR_TYPE_MASK;
         pi_mutex.shared = (*attr & MUTEXATTR_SHARED_MASK) != 0;
@@ -777,6 +781,20 @@
 
 }  // namespace NonPI
 
+static inline __always_inline bool IsMutexDestroyed(uint16_t mutex_state) {
+    return mutex_state == 0xffff;
+}
+
+// Inlining this function in pthread_mutex_lock() adds the cost of stack frame instructions on
+// ARM64. So make it noinline.
+static int __attribute__((noinline)) HandleUsingDestroyedMutex(pthread_mutex_t* mutex,
+                                                               const char* function_name) {
+    if (bionic_get_application_target_sdk_version() >= __ANDROID_API_P__) {
+        __fortify_fatal("%s called on a destroyed mutex (%p)", function_name, mutex);
+    }
+    return EBUSY;
+}
+
 int pthread_mutex_lock(pthread_mutex_t* mutex_interface) {
 #if !defined(__LP64__)
     // Some apps depend on being able to pass NULL as a mutex and get EINVAL
@@ -788,7 +806,6 @@
 #endif
 
     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);
     // Avoid slowing down fast path of normal mutex lock operation.
@@ -797,13 +814,17 @@
         if (__predict_true(NonPI::NormalMutexTryLock(mutex, shared) == 0)) {
             return 0;
         }
-    } else if (mtype == MUTEX_TYPE_BITS_WITH_PI) {
+    }
+    if (old_state == PI_MUTEX_STATE) {
         PIMutex& m = mutex->ToPIMutex();
         // Handle common case first.
         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__);
     }
     return NonPI::MutexLockWithTimeout(mutex, false, nullptr);
 }
@@ -819,7 +840,6 @@
 #endif
 
     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);
     uint16_t shared = (old_state & MUTEX_SHARED_MASK);
@@ -829,9 +849,12 @@
         NonPI::NormalMutexUnlock(mutex, shared);
         return 0;
     }
-    if (mtype == MUTEX_TYPE_BITS_WITH_PI) {
+    if (old_state == PI_MUTEX_STATE) {
         return PIMutexUnlock(mutex->ToPIMutex());
     }
+    if (__predict_false(IsMutexDestroyed(old_state))) {
+        return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__);
+    }
 
     // Do we already own this recursive or error-check mutex?
     pid_t tid = __get_thread()->tid;
@@ -875,9 +898,12 @@
         uint16_t shared = (old_state & MUTEX_SHARED_MASK);
         return NonPI::NormalMutexTryLock(mutex, shared);
     }
-    if (mtype == MUTEX_TYPE_BITS_WITH_PI) {
+    if (old_state == PI_MUTEX_STATE) {
         return PIMutexTryLock(mutex->ToPIMutex());
     }
+    if (__predict_false(IsMutexDestroyed(old_state))) {
+        return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__);
+    }
 
     // Do we already own this recursive or error-check mutex?
     pid_t tid = __get_thread()->tid;
@@ -923,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);
@@ -934,21 +961,31 @@
             return 0;
         }
     }
-    if (mtype == MUTEX_TYPE_BITS_WITH_PI) {
-        return PIMutexTimedLock(mutex->ToPIMutex(), abs_timeout);
+    if (old_state == PI_MUTEX_STATE) {
+        return PIMutexTimedLock(mutex->ToPIMutex(), use_realtime_clock, abs_timeout);
     }
-    return NonPI::MutexLockWithTimeout(mutex, true, abs_timeout);
+    if (__predict_false(IsMutexDestroyed(old_state))) {
+        return HandleUsingDestroyedMutex(mutex_interface, function);
+    }
+    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) {
     pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
     uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
-    if (old_state == 0xffff) {
-        // The mutex has been destroyed.
-        return EBUSY;
+    if (__predict_false(IsMutexDestroyed(old_state))) {
+        return HandleUsingDestroyedMutex(mutex_interface, __FUNCTION__);
     }
-    uint16_t mtype  = (old_state & MUTEX_TYPE_MASK);
-    if (mtype == MUTEX_TYPE_BITS_WITH_PI) {
+    if (old_state == PI_MUTEX_STATE) {
         int result = PIMutexDestroy(mutex->ToPIMutex());
         if (result == 0) {
             mutex->FreePIMutex();
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/dns/resolv/res_init.c b/libc/dns/resolv/res_init.c
index 302a62b..2fb2a3d 100644
--- a/libc/dns/resolv/res_init.c
+++ b/libc/dns/resolv/res_init.c
@@ -774,6 +774,9 @@
 		statp->netid = netcontext->dns_netid;
 		statp->_mark = netcontext->dns_mark;
 		statp->qhook = netcontext->qhook;
+		if (netcontext->flags & NET_CONTEXT_FLAG_USE_EDNS) {
+			statp->options |= RES_USE_EDNS0 | RES_USE_DNSSEC;
+		}
 	}
 }
 
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;
diff --git a/libc/private/bionic_fortify.h b/libc/private/bionic_fortify.h
index 7f22963..3c3292e 100644
--- a/libc/private/bionic_fortify.h
+++ b/libc/private/bionic_fortify.h
@@ -52,7 +52,7 @@
     __fortify_fatal("%s: file descriptor %d < 0", fn, fd);
   }
   if (__predict_false(fd >= FD_SETSIZE)) {
-    __fortify_fatal("%s: file descriptor %d >= FD_SETSIZE %zu", fn, fd, set_size);
+    __fortify_fatal("%s: file descriptor %d >= FD_SETSIZE %zu", fn, fd, FD_SETSIZE);
   }
   if (__predict_false(set_size < sizeof(fd_set))) {
     __fortify_fatal("%s: set size %zu is too small to be an fd_set", fn, set_size);
diff --git a/libm/Android.bp b/libm/Android.bp
index 76a4699..9d318fa 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -515,12 +515,14 @@
         "-D_BSD_SOURCE",
         "-DFLT_EVAL_METHOD=0",
         "-include freebsd-compat.h",
+        "-Wall",
         "-Werror",
         "-Wno-missing-braces",
         "-Wno-parentheses",
         "-Wno-sign-compare",
-        "-Wno-uninitialized",
         "-Wno-unknown-pragmas",
+        "-Wno-unused-const-variable",
+        "-Wno-unused-variable",
     ],
 
     include_dirs: ["bionic/libc"],
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 523ed63..af682a9 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -893,6 +893,7 @@
   std::function<int (pthread_rwlock_t*)> trylock_function;
   std::function<int (pthread_rwlock_t*)> lock_function;
   std::function<int (pthread_rwlock_t*, const timespec*)> timed_lock_function;
+  clockid_t clock;
 };
 
 static void pthread_rwlock_wakeup_helper(RwlockWakeupHelperArg* arg) {
@@ -944,6 +945,19 @@
   });
 }
 
+TEST(pthread, pthread_rwlock_reader_wakeup_writer_timedwait_monotonic_np) {
+#if defined(__BIONIC__)
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+  ts.tv_sec += 1;
+  test_pthread_rwlock_reader_wakeup_writer(
+      [&](pthread_rwlock_t* lock) { return pthread_rwlock_timedwrlock_monotonic_np(lock, &ts); });
+#else   // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedwrlock_monotonic_np is "
+                      "only supported on bionic";
+#endif  // __BIONIC__
+}
+
 static void test_pthread_rwlock_writer_wakeup_reader(std::function<int (pthread_rwlock_t*)> lock_function) {
   RwlockWakeupHelperArg wakeup_arg;
   ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, NULL));
@@ -980,6 +994,19 @@
   });
 }
 
+TEST(pthread, pthread_rwlock_writer_wakeup_reader_timedwait_monotonic_np) {
+#if defined(__BIONIC__)
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+  ts.tv_sec += 1;
+  test_pthread_rwlock_writer_wakeup_reader(
+      [&](pthread_rwlock_t* lock) { return pthread_rwlock_timedrdlock_monotonic_np(lock, &ts); });
+#else   // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedrdlock_monotonic_np is "
+                      "only supported on bionic";
+#endif  // __BIONIC__
+}
+
 static void pthread_rwlock_wakeup_timeout_helper(RwlockWakeupHelperArg* arg) {
   arg->tid = gettid();
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
@@ -988,7 +1015,7 @@
   ASSERT_EQ(EBUSY, arg->trylock_function(&arg->lock));
 
   timespec ts;
-  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ASSERT_EQ(0, clock_gettime(arg->clock, &ts));
   ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
   ts.tv_nsec = -1;
   ASSERT_EQ(EINVAL, arg->timed_lock_function(&arg->lock, &ts));
@@ -997,21 +1024,60 @@
   ts.tv_nsec = NS_PER_S - 1;
   ts.tv_sec = -1;
   ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
-  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ASSERT_EQ(0, clock_gettime(arg->clock, &ts));
   ts.tv_sec += 1;
   ASSERT_EQ(ETIMEDOUT, arg->timed_lock_function(&arg->lock, &ts));
   ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, arg->progress);
   arg->progress = RwlockWakeupHelperArg::LOCK_TIMEDOUT;
 }
 
-TEST(pthread, pthread_rwlock_timedrdlock_timeout) {
+static void pthread_rwlock_timedrdlock_timeout_helper(
+    clockid_t clock, int (*lock_function)(pthread_rwlock_t* __rwlock, const timespec* __timeout)) {
   RwlockWakeupHelperArg wakeup_arg;
   ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
   ASSERT_EQ(0, pthread_rwlock_wrlock(&wakeup_arg.lock));
   wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
   wakeup_arg.tid = 0;
   wakeup_arg.trylock_function = &pthread_rwlock_tryrdlock;
-  wakeup_arg.timed_lock_function = &pthread_rwlock_timedrdlock;
+  wakeup_arg.timed_lock_function = lock_function;
+  wakeup_arg.clock = clock;
+
+  pthread_t thread;
+  ASSERT_EQ(0, pthread_create(&thread, nullptr,
+      reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_timeout_helper), &wakeup_arg));
+  WaitUntilThreadSleep(wakeup_arg.tid);
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
+
+  ASSERT_EQ(0, pthread_join(thread, nullptr));
+  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_TIMEDOUT, wakeup_arg.progress);
+  ASSERT_EQ(0, pthread_rwlock_unlock(&wakeup_arg.lock));
+  ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
+}
+
+TEST(pthread, pthread_rwlock_timedrdlock_timeout) {
+  pthread_rwlock_timedrdlock_timeout_helper(CLOCK_REALTIME, pthread_rwlock_timedrdlock);
+}
+
+TEST(pthread, pthread_rwlock_timedrdlock_monotonic_np_timeout) {
+#if defined(__BIONIC__)
+  pthread_rwlock_timedrdlock_timeout_helper(CLOCK_MONOTONIC,
+                                            pthread_rwlock_timedrdlock_monotonic_np);
+#else   // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedrdlock_monotonic_np is "
+                      "only supported on bionic";
+#endif  // __BIONIC__
+}
+
+static void pthread_rwlock_timedwrlock_timeout_helper(
+    clockid_t clock, int (*lock_function)(pthread_rwlock_t* __rwlock, const timespec* __timeout)) {
+  RwlockWakeupHelperArg wakeup_arg;
+  ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
+  ASSERT_EQ(0, pthread_rwlock_rdlock(&wakeup_arg.lock));
+  wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
+  wakeup_arg.tid = 0;
+  wakeup_arg.trylock_function = &pthread_rwlock_trywrlock;
+  wakeup_arg.timed_lock_function = lock_function;
+  wakeup_arg.clock = clock;
 
   pthread_t thread;
   ASSERT_EQ(0, pthread_create(&thread, nullptr,
@@ -1026,24 +1092,17 @@
 }
 
 TEST(pthread, pthread_rwlock_timedwrlock_timeout) {
-  RwlockWakeupHelperArg wakeup_arg;
-  ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
-  ASSERT_EQ(0, pthread_rwlock_rdlock(&wakeup_arg.lock));
-  wakeup_arg.progress = RwlockWakeupHelperArg::LOCK_INITIALIZED;
-  wakeup_arg.tid = 0;
-  wakeup_arg.trylock_function = &pthread_rwlock_trywrlock;
-  wakeup_arg.timed_lock_function = &pthread_rwlock_timedwrlock;
+  pthread_rwlock_timedwrlock_timeout_helper(CLOCK_REALTIME, pthread_rwlock_timedwrlock);
+}
 
-  pthread_t thread;
-  ASSERT_EQ(0, pthread_create(&thread, nullptr,
-      reinterpret_cast<void* (*)(void*)>(pthread_rwlock_wakeup_timeout_helper), &wakeup_arg));
-  WaitUntilThreadSleep(wakeup_arg.tid);
-  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_WAITING, wakeup_arg.progress);
-
-  ASSERT_EQ(0, pthread_join(thread, nullptr));
-  ASSERT_EQ(RwlockWakeupHelperArg::LOCK_TIMEDOUT, wakeup_arg.progress);
-  ASSERT_EQ(0, pthread_rwlock_unlock(&wakeup_arg.lock));
-  ASSERT_EQ(0, pthread_rwlock_destroy(&wakeup_arg.lock));
+TEST(pthread, pthread_rwlock_timedwrlock_monotonic_np_timeout) {
+#if defined(__BIONIC__)
+  pthread_rwlock_timedwrlock_timeout_helper(CLOCK_MONOTONIC,
+                                            pthread_rwlock_timedwrlock_monotonic_np);
+#else   // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing since pthread_rwlock_timedwrlock_monotonic_np is "
+                      "only supported on bionic";
+#endif  // __BIONIC__
 }
 
 class RwlockKindTestHelper {
@@ -1376,25 +1435,59 @@
   ASSERT_EQ(0, pthread_cond_signal(&cond));
 }
 
-TEST(pthread, pthread_cond_timedwait_timeout) {
+TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_MONOTONIC_np) {
+#if defined(__BIONIC__)
+  InitCond(CLOCK_REALTIME);
+  timespec ts;
+  ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+  ts.tv_sec += 1;
+  StartWaitingThread([&](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    return pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
+  });
+  progress = SIGNALED;
+  ASSERT_EQ(0, pthread_cond_signal(&cond));
+#else   // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing since pthread_cond_timedwait_monotonic_np is only "
+                      "supported on bionic";
+#endif  // __BIONIC__
+}
+
+static void pthread_cond_timedwait_timeout_helper(clockid_t clock,
+                                                  int (*wait_function)(pthread_cond_t* __cond,
+                                                                       pthread_mutex_t* __mutex,
+                                                                       const timespec* __timeout)) {
   pthread_mutex_t mutex;
   ASSERT_EQ(0, pthread_mutex_init(&mutex, nullptr));
   pthread_cond_t cond;
   ASSERT_EQ(0, pthread_cond_init(&cond, nullptr));
   ASSERT_EQ(0, pthread_mutex_lock(&mutex));
+
   timespec ts;
-  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
-  ASSERT_EQ(ETIMEDOUT, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ASSERT_EQ(0, clock_gettime(clock, &ts));
+  ASSERT_EQ(ETIMEDOUT, wait_function(&cond, &mutex, &ts));
   ts.tv_nsec = -1;
-  ASSERT_EQ(EINVAL, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ASSERT_EQ(EINVAL, wait_function(&cond, &mutex, &ts));
   ts.tv_nsec = NS_PER_S;
-  ASSERT_EQ(EINVAL, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ASSERT_EQ(EINVAL, wait_function(&cond, &mutex, &ts));
   ts.tv_nsec = NS_PER_S - 1;
   ts.tv_sec = -1;
-  ASSERT_EQ(ETIMEDOUT, pthread_cond_timedwait(&cond, &mutex, &ts));
+  ASSERT_EQ(ETIMEDOUT, wait_function(&cond, &mutex, &ts));
   ASSERT_EQ(0, pthread_mutex_unlock(&mutex));
 }
 
+TEST(pthread, pthread_cond_timedwait_timeout) {
+  pthread_cond_timedwait_timeout_helper(CLOCK_REALTIME, pthread_cond_timedwait);
+}
+
+TEST(pthread, pthread_cond_timedwait_monotonic_np_timeout) {
+#if defined(__BIONIC__)
+  pthread_cond_timedwait_timeout_helper(CLOCK_MONOTONIC, pthread_cond_timedwait_monotonic_np);
+#else   // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing since pthread_cond_timedwait_monotonic_np is only "
+                      "supported on bionic";
+#endif  // __BIONIC__
+}
+
 TEST(pthread, pthread_attr_getstack__main_thread) {
   // This test is only meaningful for the main thread, so make sure we're running on it!
   ASSERT_EQ(getpid(), syscall(__NR_gettid));
@@ -1718,7 +1811,6 @@
 
   void destroy() {
     ASSERT_EQ(0, pthread_mutex_destroy(&lock));
-    ASSERT_EQ(EBUSY, pthread_mutex_destroy(&lock));
   }
 
   DISALLOW_COPY_AND_ASSIGN(PthreadMutex);
@@ -2000,7 +2092,9 @@
 #endif
 }
 
-TEST(pthread, pthread_mutex_timedlock) {
+static void pthread_mutex_timedlock_helper(clockid_t clock,
+                                           int (*lock_function)(pthread_mutex_t* __mutex,
+                                                                const timespec* __timeout)) {
   pthread_mutex_t m;
   ASSERT_EQ(0, pthread_mutex_init(&m, nullptr));
 
@@ -2008,51 +2102,115 @@
   ASSERT_EQ(0, pthread_mutex_lock(&m));
 
   timespec ts;
-  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
-  ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+  ASSERT_EQ(0, clock_gettime(clock, &ts));
+  ASSERT_EQ(ETIMEDOUT, lock_function(&m, &ts));
   ts.tv_nsec = -1;
-  ASSERT_EQ(EINVAL, pthread_mutex_timedlock(&m, &ts));
+  ASSERT_EQ(EINVAL, lock_function(&m, &ts));
   ts.tv_nsec = NS_PER_S;
-  ASSERT_EQ(EINVAL, pthread_mutex_timedlock(&m, &ts));
+  ASSERT_EQ(EINVAL, lock_function(&m, &ts));
   ts.tv_nsec = NS_PER_S - 1;
   ts.tv_sec = -1;
-  ASSERT_EQ(ETIMEDOUT, pthread_mutex_timedlock(&m, &ts));
+  ASSERT_EQ(ETIMEDOUT, lock_function(&m, &ts));
 
   // If the mutex is unlocked, pthread_mutex_timedlock should succeed.
   ASSERT_EQ(0, pthread_mutex_unlock(&m));
 
-  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ASSERT_EQ(0, clock_gettime(clock, &ts));
   ts.tv_sec += 1;
-  ASSERT_EQ(0, pthread_mutex_timedlock(&m, &ts));
+  ASSERT_EQ(0, lock_function(&m, &ts));
 
   ASSERT_EQ(0, pthread_mutex_unlock(&m));
   ASSERT_EQ(0, pthread_mutex_destroy(&m));
 }
 
-TEST(pthread, pthread_mutex_timedlock_pi) {
+TEST(pthread, pthread_mutex_timedlock) {
+  pthread_mutex_timedlock_helper(CLOCK_REALTIME, pthread_mutex_timedlock);
+}
+
+TEST(pthread, pthread_mutex_timedlock_monotonic_np) {
+#if defined(__BIONIC__)
+  pthread_mutex_timedlock_helper(CLOCK_MONOTONIC, pthread_mutex_timedlock_monotonic_np);
+#else   // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing since pthread_mutex_timedlock_monotonic_np is only "
+                      "supported on bionic";
+#endif  // __BIONIC__
+}
+
+static void pthread_mutex_timedlock_pi_helper(clockid_t clock,
+                                              int (*lock_function)(pthread_mutex_t* __mutex,
+                                                                   const timespec* __timeout)) {
   PthreadMutex m(PTHREAD_MUTEX_NORMAL, PTHREAD_PRIO_INHERIT);
+
   timespec ts;
-  clock_gettime(CLOCK_REALTIME, &ts);
+  clock_gettime(clock, &ts);
   ts.tv_sec += 1;
-  ASSERT_EQ(0, pthread_mutex_timedlock(&m.lock, &ts));
+  ASSERT_EQ(0, lock_function(&m.lock, &ts));
+
+  struct ThreadArgs {
+    clockid_t clock;
+    int (*lock_function)(pthread_mutex_t* __mutex, const timespec* __timeout);
+    PthreadMutex& m;
+  };
+
+  ThreadArgs thread_args = {
+    .clock = clock,
+    .lock_function = lock_function,
+    .m = m,
+  };
 
   auto ThreadFn = [](void* arg) -> void* {
-    PthreadMutex& m = *static_cast<PthreadMutex*>(arg);
+    auto args = static_cast<ThreadArgs*>(arg);
     timespec ts;
-    clock_gettime(CLOCK_REALTIME, &ts);
+    clock_gettime(args->clock, &ts);
     ts.tv_sec += 1;
-    intptr_t result = pthread_mutex_timedlock(&m.lock, &ts);
+    intptr_t result = args->lock_function(&args->m.lock, &ts);
     return reinterpret_cast<void*>(result);
   };
 
   pthread_t thread;
-  ASSERT_EQ(0, pthread_create(&thread, NULL, ThreadFn, &m));
+  ASSERT_EQ(0, pthread_create(&thread, NULL, ThreadFn, &thread_args));
   void* result;
   ASSERT_EQ(0, pthread_join(thread, &result));
   ASSERT_EQ(ETIMEDOUT, reinterpret_cast<intptr_t>(result));
   ASSERT_EQ(0, pthread_mutex_unlock(&m.lock));
 }
 
+TEST(pthread, pthread_mutex_timedlock_pi) {
+  pthread_mutex_timedlock_pi_helper(CLOCK_REALTIME, pthread_mutex_timedlock);
+}
+
+TEST(pthread, pthread_mutex_timedlock_monotonic_np_pi) {
+#if defined(__BIONIC__)
+  pthread_mutex_timedlock_pi_helper(CLOCK_MONOTONIC, pthread_mutex_timedlock_monotonic_np);
+#else   // __BIONIC__
+  GTEST_LOG_(INFO) << "This test does nothing since pthread_mutex_timedlock_monotonic_np is only "
+                      "supported on bionic";
+#endif  // __BIONIC__
+}
+
+TEST(pthread, pthread_mutex_using_destroyed_mutex) {
+#if defined(__BIONIC__)
+  pthread_mutex_t m;
+  ASSERT_EQ(0, pthread_mutex_init(&m, nullptr));
+  ASSERT_EQ(0, pthread_mutex_destroy(&m));
+  ASSERT_EXIT(pthread_mutex_lock(&m), ::testing::KilledBySignal(SIGABRT),
+              "pthread_mutex_lock called on a destroyed mutex");
+  ASSERT_EXIT(pthread_mutex_unlock(&m), ::testing::KilledBySignal(SIGABRT),
+              "pthread_mutex_unlock called on a destroyed mutex");
+  ASSERT_EXIT(pthread_mutex_trylock(&m), ::testing::KilledBySignal(SIGABRT),
+              "pthread_mutex_trylock called on a destroyed mutex");
+  timespec ts;
+  ASSERT_EXIT(pthread_mutex_timedlock(&m, &ts), ::testing::KilledBySignal(SIGABRT),
+              "pthread_mutex_timedlock called on a destroyed mutex");
+  ASSERT_EXIT(pthread_mutex_timedlock_monotonic_np(&m, &ts), ::testing::KilledBySignal(SIGABRT),
+              "pthread_mutex_timedlock_monotonic_np called on a destroyed mutex");
+  ASSERT_EXIT(pthread_mutex_destroy(&m), ::testing::KilledBySignal(SIGABRT),
+              "pthread_mutex_destroy called on a destroyed mutex");
+#else
+  GTEST_LOG_(INFO) << "This test tests bionic pthread mutex implementation details.";
+#endif
+}
+
 class StrictAlignmentAllocator {
  public:
   void* allocate(size_t size, size_t alignment) {
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index b216ec9..607e37f 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -101,37 +101,51 @@
   }
 }
 
-TEST(semaphore, sem_timedwait) {
+static void sem_timedwait_helper(clockid_t clock,
+                                 int (*wait_function)(sem_t* __sem, const timespec* __ts)) {
   sem_t s;
   ASSERT_EQ(0, sem_init(&s, 0, 0));
 
   timespec ts;
-  ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+  ASSERT_EQ(0, clock_gettime(clock, &ts));
   timespec_add_ms(ts, 100);
 
   errno = 0;
-  ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+  ASSERT_EQ(-1, wait_function(&s, &ts));
   ASSERT_EQ(ETIMEDOUT, errno);
 
   // A negative timeout is an error.
   errno = 0;
   ts.tv_nsec = -1;
-  ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+  ASSERT_EQ(-1, wait_function(&s, &ts));
   ASSERT_EQ(EINVAL, errno);
   errno = 0;
   ts.tv_nsec = NS_PER_S;
-  ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+  ASSERT_EQ(-1, wait_function(&s, &ts));
   ASSERT_EQ(EINVAL, errno);
 
   errno = 0;
   ts.tv_nsec = NS_PER_S - 1;
   ts.tv_sec = -1;
-  ASSERT_EQ(-1, sem_timedwait(&s, &ts));
+  ASSERT_EQ(-1, wait_function(&s, &ts));
   ASSERT_EQ(ETIMEDOUT, errno);
 
   ASSERT_EQ(0, sem_destroy(&s));
 }
 
+TEST(semaphore, sem_timedwait) {
+  sem_timedwait_helper(CLOCK_REALTIME, sem_timedwait);
+}
+
+TEST(semaphore, sem_timedwait_monotonic_np) {
+#if defined(__BIONIC__)
+  sem_timedwait_helper(CLOCK_MONOTONIC, sem_timedwait_monotonic_np);
+#else   // __BIONIC__
+  GTEST_LOG_(INFO)
+      << "This test does nothing since sem_timedwait_monotonic_np is only supported on bionic";
+#endif  // __BIONIC__
+}
+
 TEST(semaphore_DeathTest, sem_timedwait_null_timeout) {
   sem_t s;
   ASSERT_EQ(0, sem_init(&s, 0, 0));