[libc-commits] [libc] 2204247 - [libc] C11 threads: Add cnd_timedwait and mtx_trylock. (#195966)

via libc-commits libc-commits at lists.llvm.org
Mon May 11 10:50:38 PDT 2026


Author: Alexey Samsonov
Date: 2026-05-11T10:50:33-07:00
New Revision: 220424715083cb0ea31e2fb5403136fec4030152

URL: https://github.com/llvm/llvm-project/commit/220424715083cb0ea31e2fb5403136fec4030152
DIFF: https://github.com/llvm/llvm-project/commit/220424715083cb0ea31e2fb5403136fec4030152.diff

LOG: [libc] C11 threads: Add cnd_timedwait and mtx_trylock. (#195966)

Use recently added support for timed_wait in CndVar and try_lock in
Mutex to implement the C11 functions `cnd_timedwait` and `mtx_trylock`
(counterparts of `pthread_cond_timedwait` and `pthread_mutex_trylock`,
respectively).

Fixes a minor edge case in `ensure_monotonicity` conversion where the
converted timeout could fall before epoch - clamp it to be 0 / epoch in
that case.

Assisted by: Gemini

Added: 
    libc/src/threads/cnd_timedwait.h
    libc/src/threads/linux/cnd_timedwait.cpp
    libc/src/threads/mtx_trylock.cpp
    libc/src/threads/mtx_trylock.h

Modified: 
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/riscv/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/CMakeLists.txt
    libc/include/threads.yaml
    libc/src/__support/threads/mutex.h
    libc/src/__support/time/clock_conversion.h
    libc/src/__support/time/monotonicity.h
    libc/src/threads/CMakeLists.txt
    libc/src/threads/linux/CMakeLists.txt
    libc/test/integration/src/threads/CMakeLists.txt
    libc/test/integration/src/threads/cnd_test.cpp
    libc/test/integration/src/threads/mtx_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 9994a9294173d..0c8fb3c8dbc15 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1195,10 +1195,12 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.threads.cnd_destroy
     libc.src.threads.cnd_init
     libc.src.threads.cnd_signal
+    libc.src.threads.cnd_timedwait
     libc.src.threads.cnd_wait
     libc.src.threads.mtx_destroy
     libc.src.threads.mtx_init
     libc.src.threads.mtx_lock
+    libc.src.threads.mtx_trylock
     libc.src.threads.mtx_unlock
     libc.src.threads.thrd_create
     libc.src.threads.thrd_current

diff  --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 2748b2b8e6a5d..99a5c820159f8 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1318,10 +1318,12 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.threads.cnd_destroy
     libc.src.threads.cnd_init
     libc.src.threads.cnd_signal
+    libc.src.threads.cnd_timedwait
     libc.src.threads.cnd_wait
     libc.src.threads.mtx_destroy
     libc.src.threads.mtx_init
     libc.src.threads.mtx_lock
+    libc.src.threads.mtx_trylock
     libc.src.threads.mtx_unlock
     libc.src.threads.thrd_create
     libc.src.threads.thrd_current

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 4b551ced82138..45fdde6454880 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1392,10 +1392,12 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.threads.cnd_destroy
     libc.src.threads.cnd_init
     libc.src.threads.cnd_signal
+    libc.src.threads.cnd_timedwait
     libc.src.threads.cnd_wait
     libc.src.threads.mtx_destroy
     libc.src.threads.mtx_init
     libc.src.threads.mtx_lock
+    libc.src.threads.mtx_trylock
     libc.src.threads.mtx_unlock
     libc.src.threads.thrd_create
     libc.src.threads.thrd_current

diff  --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index e5f96ab19d9f1..b1b4a4fd20982 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -340,6 +340,7 @@ add_header_macro(
     .llvm-libc-types.thrd_start_t
     .llvm-libc-types.tss_t
     .llvm-libc-types.tss_dtor_t
+    .llvm-libc-types.struct_timespec
 )
 
 add_header_macro(

diff  --git a/libc/include/threads.yaml b/libc/include/threads.yaml
index 6f7796e090ab6..1e8e42c80587c 100644
--- a/libc/include/threads.yaml
+++ b/libc/include/threads.yaml
@@ -13,6 +13,7 @@ types:
   - type_name: thrd_t
   - type_name: tss_t
   - type_name: tss_dtor_t
+  - type_name: struct_timespec
 enums:
   - name: mtx_plain
     value: null
@@ -63,6 +64,14 @@ functions:
     return_type: int
     arguments:
       - type: cnd_t *
+  - name: cnd_timedwait
+    standards:
+      - stdc
+    return_type: int
+    arguments:
+      - type: cnd_t *__restrict
+      - type: mtx_t *__restrict
+      - type: const struct timespec *__restrict
   - name: cnd_wait
     standards:
       - stdc
@@ -89,6 +98,12 @@ functions:
     return_type: int
     arguments:
       - type: mtx_t *
+  - name: mtx_trylock
+    standards:
+      - stdc
+    return_type: int
+    arguments:
+      - type: mtx_t *
   - name: mtx_unlock
     standards:
       - stdc

diff  --git a/libc/src/__support/threads/mutex.h b/libc/src/__support/threads/mutex.h
index d4d13093a2ce7..b2e2bda66eb8c 100644
--- a/libc/src/__support/threads/mutex.h
+++ b/libc/src/__support/threads/mutex.h
@@ -21,7 +21,7 @@
 // Mutex with non-static methods having the following signature:
 //
 // MutexError lock();
-// MutexError trylock();
+// MutexError try_lock();
 // MutexError timed_lock(...);
 // MutexError unlock();
 // MutexError reset(); // Used to reset inconsistent robust mutexes.
@@ -61,7 +61,7 @@ struct Mutex {
   LIBC_INLINE MutexError lock() { return MutexError::NONE; }
   LIBC_INLINE MutexError unlock() { return MutexError::NONE; }
   LIBC_INLINE MutexError reset() { return MutexError::NONE; }
-  LIBC_INLINE MutexError trylock() { return MutexError::NONE; }
+  LIBC_INLINE MutexError try_lock() { return MutexError::NONE; }
   LIBC_INLINE bool is_robust() const { return false; }
 };
 

diff  --git a/libc/src/__support/time/clock_conversion.h b/libc/src/__support/time/clock_conversion.h
index 54ea4b6ca1430..658ff52f046e8 100644
--- a/libc/src/__support/time/clock_conversion.h
+++ b/libc/src/__support/time/clock_conversion.h
@@ -48,7 +48,7 @@ LIBC_INLINE timespec convert_clock(timespec input, clockid_t from,
   output.tv_sec = input.tv_sec - from_time.tv_sec + to_time.tv_sec;
   output.tv_nsec = input.tv_nsec - from_time.tv_nsec + to_time.tv_nsec;
 
-  if (output.tv_nsec > 1_s_ns) {
+  if (output.tv_nsec >= 1_s_ns) {
     output.tv_sec++;
     output.tv_nsec -= 1_s_ns;
   } else if (output.tv_nsec < 0) {

diff  --git a/libc/src/__support/time/monotonicity.h b/libc/src/__support/time/monotonicity.h
index a8c7a56f4c6cc..544f8c31db980 100644
--- a/libc/src/__support/time/monotonicity.h
+++ b/libc/src/__support/time/monotonicity.h
@@ -31,6 +31,10 @@ LIBC_INLINE void ensure_monotonicity(AbsTimeout &timeout) {
         convert_clock(timeout.get_timespec(), CLOCK_REALTIME, CLOCK_MONOTONIC),
         false);
 
+    // Clamp the timeout to epoch if becomes negative after the conversion.
+    if (!res.has_value() && res.error() == AbsTimeout::Error::BeforeEpoch)
+      res = AbsTimeout::from_timespec(timespec{0, 0}, false);
+
     LIBC_ASSERT(res.has_value());
     if (!res.has_value())
       __builtin_unreachable();

diff  --git a/libc/src/threads/CMakeLists.txt b/libc/src/threads/CMakeLists.txt
index 17dea3920a07a..db9ab33bbbf62 100644
--- a/libc/src/threads/CMakeLists.txt
+++ b/libc/src/threads/CMakeLists.txt
@@ -117,6 +117,17 @@ add_entrypoint_object(
     libc.src.__support.threads.mutex
 )
 
+add_entrypoint_object(
+  mtx_trylock
+  SRCS
+    mtx_trylock.cpp
+  HDRS
+    mtx_trylock.h
+  DEPENDS
+    libc.include.threads
+    libc.src.__support.threads.mutex
+)
+
 add_entrypoint_object(
   mtx_unlock
   SRCS
@@ -193,6 +204,13 @@ add_entrypoint_object(
     .${LIBC_TARGET_OS}.cnd_wait
 )
 
+add_entrypoint_object(
+  cnd_timedwait
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.cnd_timedwait
+)
+
 add_entrypoint_object(
   cnd_signal
   ALIAS

diff  --git a/libc/src/threads/cnd_timedwait.h b/libc/src/threads/cnd_timedwait.h
new file mode 100644
index 0000000000000..f15eb9f6d243e
--- /dev/null
+++ b/libc/src/threads/cnd_timedwait.h
@@ -0,0 +1,22 @@
+//===-- Internal header for cnd_timedwait -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_THREADS_CND_TIMEDWAIT_H
+#define LLVM_LIBC_SRC_THREADS_CND_TIMEDWAIT_H
+
+#include "src/__support/macros/config.h"
+#include <threads.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int cnd_timedwait(cnd_t *__restrict cond, mtx_t *__restrict mutex,
+                  const struct timespec *__restrict time_point);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_THREADS_CND_TIMEDWAIT_H

diff  --git a/libc/src/threads/linux/CMakeLists.txt b/libc/src/threads/linux/CMakeLists.txt
index c33c48919be2c..e4b38621bd699 100644
--- a/libc/src/threads/linux/CMakeLists.txt
+++ b/libc/src/threads/linux/CMakeLists.txt
@@ -48,6 +48,20 @@ add_entrypoint_object(
     libc.src.__support.threads.CndVar
 )
 
+add_entrypoint_object(
+  cnd_timedwait
+  SRCS
+    cnd_timedwait.cpp
+  HDRS
+    ../cnd_timedwait.h
+  DEPENDS
+    libc.include.threads
+    libc.src.__support.threads.mutex
+    libc.src.__support.threads.CndVar
+    libc.src.__support.time.abs_timeout
+    libc.src.__support.macros.null_check
+)
+
 add_entrypoint_object(
   cnd_signal
   SRCS

diff  --git a/libc/src/threads/linux/cnd_timedwait.cpp b/libc/src/threads/linux/cnd_timedwait.cpp
new file mode 100644
index 0000000000000..853abd07c4cc8
--- /dev/null
+++ b/libc/src/threads/linux/cnd_timedwait.cpp
@@ -0,0 +1,57 @@
+//===-- Linux implementation of the cnd_timedwait function ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/threads/cnd_timedwait.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+#include "src/__support/threads/CndVar.h"
+#include "src/__support/threads/mutex.h"
+#include "src/__support/time/abs_timeout.h"
+
+#include <threads.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(sizeof(CndVar) == sizeof(cnd_t));
+static_assert(sizeof(Mutex) == sizeof(mtx_t) &&
+              alignof(Mutex) == alignof(mtx_t));
+
+LLVM_LIBC_FUNCTION(int, cnd_timedwait,
+                   (cnd_t *__restrict cond, mtx_t *__restrict mtx,
+                    const struct timespec *__restrict time_point)) {
+  LIBC_CRASH_ON_NULLPTR(time_point);
+  CndVar *cndvar = reinterpret_cast<CndVar *>(cond);
+  Mutex *mutex = reinterpret_cast<Mutex *>(mtx);
+
+  // time_point is TIME_UTC-based, so we assume realtime clock here.
+  auto timeout =
+      internal::AbsTimeout::from_timespec(*time_point, /*realtime=*/true);
+
+  if (!timeout.has_value()) {
+    switch (timeout.error()) {
+    case internal::AbsTimeout::Error::BeforeEpoch:
+      return thrd_timedout;
+    case internal::AbsTimeout::Error::Invalid:
+      return thrd_error;
+    }
+    __builtin_unreachable();
+  }
+
+  switch (cndvar->wait(mutex, timeout.value())) {
+  case CndVarResult::Success:
+    return thrd_success;
+  case CndVarResult::Timeout:
+    return thrd_timedout;
+  case CndVarResult::MutexError:
+    return thrd_error;
+  }
+  __builtin_unreachable();
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/threads/mtx_trylock.cpp b/libc/src/threads/mtx_trylock.cpp
new file mode 100644
index 0000000000000..a3cde97ee2b30
--- /dev/null
+++ b/libc/src/threads/mtx_trylock.cpp
@@ -0,0 +1,27 @@
+//===-- Linux implementation of the mtx_trylock function ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/threads/mtx_trylock.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/mutex.h"
+
+#include <threads.h> // For mtx_t definition.
+
+namespace LIBC_NAMESPACE_DECL {
+
+// The implementation currently handles only plain mutexes.
+LLVM_LIBC_FUNCTION(int, mtx_trylock, (mtx_t * mutex)) {
+  auto *m = reinterpret_cast<Mutex *>(mutex);
+  auto err = m->try_lock();
+  if (err == MutexError::BUSY)
+    return thrd_busy;
+  return err == MutexError::NONE ? thrd_success : thrd_error;
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/threads/mtx_trylock.h b/libc/src/threads/mtx_trylock.h
new file mode 100644
index 0000000000000..d6ba640a9d20a
--- /dev/null
+++ b/libc/src/threads/mtx_trylock.h
@@ -0,0 +1,21 @@
+//===-- Internal header for mtx_trylock -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_THREADS_MTX_TRYLOCK_H
+#define LLVM_LIBC_SRC_THREADS_MTX_TRYLOCK_H
+
+#include "src/__support/macros/config.h"
+#include <threads.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int mtx_trylock(mtx_t *mutex);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_THREADS_MTX_TRYLOCK_H

diff  --git a/libc/test/integration/src/threads/CMakeLists.txt b/libc/test/integration/src/threads/CMakeLists.txt
index 68e346a26457a..3355a27a309cf 100644
--- a/libc/test/integration/src/threads/CMakeLists.txt
+++ b/libc/test/integration/src/threads/CMakeLists.txt
@@ -12,6 +12,7 @@ add_integration_test(
     libc.src.threads.mtx_destroy
     libc.src.threads.mtx_init
     libc.src.threads.mtx_lock
+    libc.src.threads.mtx_trylock
     libc.src.threads.mtx_unlock
     libc.src.threads.thrd_create
     libc.src.threads.thrd_join
@@ -104,12 +105,14 @@ add_integration_test(
     cnd_test.cpp
   DEPENDS
     libc.include.threads
+    libc.include.time
     libc.src.__support.CPP.atomic
     libc.src.threads.cnd_init
     libc.src.threads.cnd_broadcast
     libc.src.threads.cnd_signal
     libc.src.threads.cnd_destroy
     libc.src.threads.cnd_wait
+    libc.src.threads.cnd_timedwait
     libc.src.threads.mtx_destroy
     libc.src.threads.mtx_init
     libc.src.threads.mtx_lock
@@ -117,4 +120,5 @@ add_integration_test(
     libc.src.threads.thrd_create
     libc.src.threads.thrd_join
     libc.src.threads.linux.threads_utils
+    libc.src.time.timespec_get
 )

diff  --git a/libc/test/integration/src/threads/cnd_test.cpp b/libc/test/integration/src/threads/cnd_test.cpp
index 4eaab9ac08bc1..297d95e3149a2 100644
--- a/libc/test/integration/src/threads/cnd_test.cpp
+++ b/libc/test/integration/src/threads/cnd_test.cpp
@@ -11,6 +11,7 @@
 #include "src/threads/cnd_destroy.h"
 #include "src/threads/cnd_init.h"
 #include "src/threads/cnd_signal.h"
+#include "src/threads/cnd_timedwait.h"
 #include "src/threads/cnd_wait.h"
 #include "src/threads/mtx_destroy.h"
 #include "src/threads/mtx_init.h"
@@ -18,10 +19,20 @@
 #include "src/threads/mtx_unlock.h"
 #include "src/threads/thrd_create.h"
 #include "src/threads/thrd_join.h"
+#include "src/time/timespec_get.h"
 
 #include "test/IntegrationTest/test.h"
 
 #include <threads.h>
+#include <time.h> // for TIME_UTC
+
+static void add_ns(struct timespec &ts, long ns) {
+  ts.tv_nsec += ns;
+  if (ts.tv_nsec >= 1'000'000'000) {
+    ++ts.tv_sec;
+    ts.tv_nsec -= 1'000'000'000;
+  }
+}
 
 namespace wait_notify_broadcast_test {
 
@@ -100,6 +111,11 @@ namespace single_waiter_test {
 mtx_t waiter_mtx, main_thread_mtx;
 cnd_t waiter_cnd, main_thread_cnd;
 
+enum class WaitMode {
+  Default,
+  Timed,
+};
+
 int waiter_thread_func([[maybe_unused]] void *unused) {
   LIBC_NAMESPACE::mtx_lock(&waiter_mtx);
 
@@ -113,7 +129,7 @@ int waiter_thread_func([[maybe_unused]] void *unused) {
   return 0x600D;
 }
 
-void single_waiter_test() {
+void single_waiter_test(WaitMode wait_mode) {
   ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&waiter_mtx, mtx_plain),
             int(thrd_success));
   ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&main_thread_mtx, mtx_plain),
@@ -126,8 +142,18 @@ void single_waiter_test() {
   thrd_t waiter_thread;
   LIBC_NAMESPACE::thrd_create(&waiter_thread, waiter_thread_func, nullptr);
 
-  ASSERT_EQ(LIBC_NAMESPACE::cnd_wait(&main_thread_cnd, &main_thread_mtx),
-            int(thrd_success));
+  if (wait_mode == WaitMode::Default) {
+    ASSERT_EQ(LIBC_NAMESPACE::cnd_wait(&main_thread_cnd, &main_thread_mtx),
+              int(thrd_success));
+  } else {
+    ASSERT_EQ(wait_mode, WaitMode::Timed);
+    struct timespec ts;
+    ASSERT_EQ(LIBC_NAMESPACE::timespec_get(&ts, TIME_UTC), TIME_UTC);
+    add_ns(ts, 50'000);
+    int result =
+        LIBC_NAMESPACE::cnd_timedwait(&main_thread_cnd, &main_thread_mtx, &ts);
+    ASSERT_TRUE(result == int(thrd_success) || result == int(thrd_timedout));
+  }
   ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&main_thread_mtx), int(thrd_success));
 
   ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&waiter_mtx), int(thrd_success));
@@ -146,8 +172,53 @@ void single_waiter_test() {
 
 } // namespace single_waiter_test
 
+namespace timed_wait_test {
+
+void timeout_test() {
+  cnd_t cnd;
+  mtx_t mtx;
+  ASSERT_EQ(LIBC_NAMESPACE::cnd_init(&cnd), int(thrd_success));
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&mtx, mtx_plain), int(thrd_success));
+
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&mtx), int(thrd_success));
+
+  struct timespec ts;
+  ts.tv_sec = 0;
+  ts.tv_nsec = 0;
+  ASSERT_EQ(LIBC_NAMESPACE::cnd_timedwait(&cnd, &mtx, &ts), int(thrd_timedout));
+
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&mtx), int(thrd_success));
+
+  LIBC_NAMESPACE::cnd_destroy(&cnd);
+  LIBC_NAMESPACE::mtx_destroy(&mtx);
+}
+
+void future_timeout_test() {
+  cnd_t cnd;
+  mtx_t mtx;
+  ASSERT_EQ(LIBC_NAMESPACE::cnd_init(&cnd), int(thrd_success));
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&mtx, mtx_plain), int(thrd_success));
+
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&mtx), int(thrd_success));
+
+  struct timespec ts;
+  ASSERT_EQ(LIBC_NAMESPACE::timespec_get(&ts, TIME_UTC), TIME_UTC);
+  add_ns(ts, 50'000);
+  ASSERT_EQ(LIBC_NAMESPACE::cnd_timedwait(&cnd, &mtx, &ts), int(thrd_timedout));
+
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&mtx), int(thrd_success));
+
+  LIBC_NAMESPACE::cnd_destroy(&cnd);
+  LIBC_NAMESPACE::mtx_destroy(&mtx);
+}
+
+} // namespace timed_wait_test
+
 TEST_MAIN() {
   wait_notify_broadcast_test::wait_notify_broadcast_test();
-  single_waiter_test::single_waiter_test();
+  single_waiter_test::single_waiter_test(single_waiter_test::WaitMode::Default);
+  single_waiter_test::single_waiter_test(single_waiter_test::WaitMode::Timed);
+  timed_wait_test::timeout_test();
+  timed_wait_test::future_timeout_test();
   return 0;
 }

diff  --git a/libc/test/integration/src/threads/mtx_test.cpp b/libc/test/integration/src/threads/mtx_test.cpp
index 909c4f2c5c760..4609e97d25fa9 100644
--- a/libc/test/integration/src/threads/mtx_test.cpp
+++ b/libc/test/integration/src/threads/mtx_test.cpp
@@ -10,6 +10,7 @@
 #include "src/threads/mtx_destroy.h"
 #include "src/threads/mtx_init.h"
 #include "src/threads/mtx_lock.h"
+#include "src/threads/mtx_trylock.h"
 #include "src/threads/mtx_unlock.h"
 #include "src/threads/thrd_create.h"
 #include "src/threads/thrd_join.h"
@@ -230,10 +231,36 @@ void multiple_waiters() {
   LIBC_NAMESPACE::mtx_destroy(&counter_lock);
 }
 
+void trylock_test() {
+  mtx_t plain_mutex;
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&plain_mutex, mtx_plain),
+            int(thrd_success));
+
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_trylock(&plain_mutex), int(thrd_success));
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_trylock(&plain_mutex), int(thrd_busy));
+
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&plain_mutex), int(thrd_success));
+
+  LIBC_NAMESPACE::mtx_destroy(&plain_mutex);
+
+  mtx_t recursive_mutex;
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&recursive_mutex, mtx_recursive),
+            int(thrd_success));
+
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_trylock(&recursive_mutex), int(thrd_success));
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_trylock(&recursive_mutex), int(thrd_success));
+
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&recursive_mutex), int(thrd_success));
+  ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&recursive_mutex), int(thrd_success));
+
+  LIBC_NAMESPACE::mtx_destroy(&recursive_mutex);
+}
+
 TEST_MAIN() {
   relay_counter();
   wait_and_step();
   recursive_mutex_test();
   multiple_waiters();
+  trylock_test();
   return 0;
 }


        


More information about the libc-commits mailing list