[libc-commits] [libc] [libc] add `pthread_cond_*` public interfaces (PR #193656)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Thu Apr 23 08:29:49 PDT 2026
https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/193656
>From a3b3eca52081ea7f3decf3c4c96dc451c27319d1 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Wed, 22 Apr 2026 23:56:49 -0400
Subject: [PATCH 1/7] [libc][WIP] add `pthread_cond_*` public interface
This patch adds pthread_cond_* entrypoints and related types.
Assisted-by: Codex with gpt-5.4 high fast
---
libc/config/linux/x86_64/entrypoints.txt | 2 +
libc/include/CMakeLists.txt | 2 +
.../include/llvm-libc-macros/pthread-macros.h | 6 +++
libc/include/llvm-libc-types/CMakeLists.txt | 1 +
libc/include/llvm-libc-types/pthread_cond_t.h | 26 ++++++++++
libc/include/pthread.yaml | 12 +++++
libc/include/sys/types.yaml | 1 +
libc/src/__support/threads/CndVar.h | 12 +++--
libc/src/pthread/CMakeLists.txt | 28 +++++++++++
libc/src/pthread/pthread_cond_destroy.cpp | 31 ++++++++++++
libc/src/pthread/pthread_cond_destroy.h | 21 ++++++++
libc/src/pthread/pthread_cond_init.cpp | 49 +++++++++++++++++++
libc/src/pthread/pthread_cond_init.h | 23 +++++++++
13 files changed, 211 insertions(+), 3 deletions(-)
create mode 100644 libc/include/llvm-libc-types/pthread_cond_t.h
create mode 100644 libc/src/pthread/pthread_cond_destroy.cpp
create mode 100644 libc/src/pthread/pthread_cond_destroy.h
create mode 100644 libc/src/pthread/pthread_cond_init.cpp
create mode 100644 libc/src/pthread/pthread_cond_init.h
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index f67d658d0b176..2ba35d84e603f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1190,6 +1190,8 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_condattr_init
libc.src.pthread.pthread_condattr_setclock
libc.src.pthread.pthread_condattr_setpshared
+ libc.src.pthread.pthread_cond_destroy
+ libc.src.pthread.pthread_cond_init
libc.src.pthread.pthread_create
libc.src.pthread.pthread_detach
libc.src.pthread.pthread_equal
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 67f8009d8b099..82a2b71d6311b 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -447,6 +447,7 @@ add_header_macro(
.llvm-libc-types.__pthread_start_t
.llvm-libc-types.__pthread_tss_dtor_t
.llvm-libc-types.pthread_attr_t
+ .llvm-libc-types.pthread_cond_t
.llvm-libc-types.pthread_condattr_t
.llvm-libc-types.pthread_key_t
.llvm-libc-types.pthread_barrier_t
@@ -789,6 +790,7 @@ add_header_macro(
.llvm-libc-types.off_t
.llvm-libc-types.pid_t
.llvm-libc-types.pthread_attr_t
+ .llvm-libc-types.pthread_cond_t
.llvm-libc-types.pthread_key_t
.llvm-libc-types.pthread_mutex_t
.llvm-libc-types.pthread_mutexattr_t
diff --git a/libc/include/llvm-libc-macros/pthread-macros.h b/libc/include/llvm-libc-macros/pthread-macros.h
index e6ade6507e070..34082bed32dff 100644
--- a/libc/include/llvm-libc-macros/pthread-macros.h
+++ b/libc/include/llvm-libc-macros/pthread-macros.h
@@ -45,6 +45,12 @@
}
#endif
+#define PTHREAD_COND_INITIALIZER \
+ { \
+ /* .__waiter_queue = */ {NULL, NULL}, /* .__futex = */ {0}, \
+ /* .__shared = */ {0}, /* .__padding = */ {0}, \
+ }
+
#define PTHREAD_RWLOCK_INITIALIZER \
{ \
/* .__raw = */ { \
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 6c2a001103250..4cd889e4789a2 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -72,6 +72,7 @@ add_header(posix_spawn_file_actions_t HDR posix_spawn_file_actions_t.h)
add_header(posix_spawnattr_t HDR posix_spawnattr_t.h)
add_header(posix_tnode HDR posix_tnode.h)
add_header(pthread_attr_t HDR pthread_attr_t.h DEPENDS .size_t)
+add_header(pthread_cond_t HDR pthread_cond_t.h DEPENDS .__futex_word .size_t)
add_header(pthread_condattr_t HDR pthread_condattr_t.h DEPENDS .clockid_t)
add_header(pthread_key_t HDR pthread_key_t.h)
add_header(pthread_mutex_t HDR pthread_mutex_t.h DEPENDS .__futex_word .__mutex_type)
diff --git a/libc/include/llvm-libc-types/pthread_cond_t.h b/libc/include/llvm-libc-types/pthread_cond_t.h
new file mode 100644
index 0000000000000..77785d325f113
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_cond_t.h
@@ -0,0 +1,26 @@
+//===-- Definition of pthread_cond_t type ---------------------------------===//
+//
+// 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_TYPES_PTHREAD_COND_T_H
+#define LLVM_LIBC_TYPES_PTHREAD_COND_T_H
+
+#include "__futex_word.h"
+#include "size_t.h"
+
+typedef struct {
+ union {
+ void *__waiter_queue[2];
+ size_t __waiter_size;
+ };
+ __futex_word __futex;
+ char __shared;
+ char __is_realtime;
+ char __padding[2];
+} pthread_cond_t;
+
+#endif // LLVM_LIBC_TYPES_PTHREAD_COND_T_H
diff --git a/libc/include/pthread.yaml b/libc/include/pthread.yaml
index 782a37c8ffad2..8b45c8431b2d0 100644
--- a/libc/include/pthread.yaml
+++ b/libc/include/pthread.yaml
@@ -30,6 +30,8 @@ macros:
macro_header: pthread-macros.h
- macro_name: "PTHREAD_MUTEX_INITIALIZER"
macro_header: pthread-macros.h
+ - macro_name: "PTHREAD_COND_INITIALIZER"
+ macro_header: pthread-macros.h
- macro_name: "PTHREAD_RWLOCK_INITIALIZER"
macro_header: pthread-macros.h
- macro_name: "PTHREAD_STACK_MIN"
@@ -56,6 +58,7 @@ types:
- type_name: pthread_barrier_t
- type_name: pthread_barrierattr_t
- type_name: pthread_key_t
+ - type_name: pthread_cond_t
- type_name: pthread_condattr_t
- type_name: pthread_rwlock_t
- type_name: pthread_rwlockattr_t
@@ -156,6 +159,15 @@ functions:
arguments:
- type: pthread_condattr_t *
- type: int
+ - name: pthread_cond_destroy
+ return_type: int
+ arguments:
+ - type: pthread_cond_t *
+ - name: pthread_cond_init
+ return_type: int
+ arguments:
+ - type: pthread_cond_t *__restrict
+ - type: const pthread_condattr_t *__restrict
- name: pthread_create
return_type: int
arguments:
diff --git a/libc/include/sys/types.yaml b/libc/include/sys/types.yaml
index 126c597b30353..cdc9602520a0b 100644
--- a/libc/include/sys/types.yaml
+++ b/libc/include/sys/types.yaml
@@ -14,6 +14,7 @@ types:
- type_name: off_t
- type_name: pid_t
- type_name: pthread_attr_t
+ - type_name: pthread_cond_t
- type_name: pthread_condattr_t
- type_name: pthread_key_t
- type_name: pthread_mutex_t
diff --git a/libc/src/__support/threads/CndVar.h b/libc/src/__support/threads/CndVar.h
index e1dd4db894632..09487c808e052 100644
--- a/libc/src/__support/threads/CndVar.h
+++ b/libc/src/__support/threads/CndVar.h
@@ -164,7 +164,8 @@ class CndVar {
Futex shared_futex;
};
- bool is_shared;
+ const bool is_shared;
+ const bool is_realtime;
LIBC_INLINE void notify(bool is_broadcast) {
if (LIBC_UNLIKELY(is_shared)) {
@@ -225,8 +226,9 @@ class CndVar {
}
public:
- LIBC_INLINE constexpr CndVar(bool is_shared)
- : waiter_queue{}, queue_lock{}, is_shared(is_shared) {
+ LIBC_INLINE constexpr CndVar(bool is_shared, bool is_realtime = false)
+ : waiter_queue{}, queue_lock{}, is_shared(is_shared),
+ is_realtime(is_realtime) {
if (is_shared) {
new (&shared_waiters) cpp::Atomic<size_t>(0);
new (&shared_futex) Futex(0);
@@ -244,6 +246,10 @@ class CndVar {
waiter_queue.next = nullptr;
}
+ // The is_realtime field is just a field we spared for pthread_cond_t
+ // It is not used in wait directly.
+ LIBC_INLINE bool default_clock_is_realtime() const { return is_realtime; }
+
// TODO: register callback for pthread cancellation
LIBC_INLINE CndVarResult wait(Mutex *mutex,
cpp::optional<Timeout> timeout = cpp::nullopt) {
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index 943b29d99f9ee..203420c1b058d 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -191,6 +191,34 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ pthread_cond_destroy
+ SRCS
+ pthread_cond_destroy.cpp
+ HDRS
+ pthread_cond_destroy.h
+ DEPENDS
+ libc.include.llvm-libc-types.pthread_cond_t
+ libc.src.__support.threads.CndVar
+)
+
+add_entrypoint_object(
+ pthread_cond_init
+ SRCS
+ pthread_cond_init.cpp
+ HDRS
+ pthread_cond_init.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.time_macros
+ libc.include.llvm-libc-macros.pthread_macros
+ libc.include.llvm-libc-types.pthread_cond_t
+ libc.include.llvm-libc-types.pthread_condattr_t
+ libc.src.__support.CPP.new
+ libc.src.__support.macros.null_check
+ libc.src.__support.threads.CndVar
+ )
+
add_header_library(
pthread_mutexattr
HDRS
diff --git a/libc/src/pthread/pthread_cond_destroy.cpp b/libc/src/pthread/pthread_cond_destroy.cpp
new file mode 100644
index 0000000000000..b35086e2bb096
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_destroy.cpp
@@ -0,0 +1,31 @@
+//===-- Implementation of the pthread_cond_destroy 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 "pthread_cond_destroy.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/CndVar.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(
+ sizeof(CndVar) == sizeof(pthread_cond_t) &&
+ alignof(CndVar) == alignof(pthread_cond_t),
+ "The public pthread_cond_t type must be of the same size and alignment "
+ "as the internal condition variable type.");
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_destroy, (pthread_cond_t * cond)) {
+ // TODO: use cpp:start_lifetime_as once
+ // https://github.com/llvm/llvm-project/pull/193326 is merged
+ auto *cndvar = reinterpret_cast<CndVar *>(cond);
+ cndvar->reset();
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_cond_destroy.h b/libc/src/pthread/pthread_cond_destroy.h
new file mode 100644
index 0000000000000..723f184faec05
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_destroy.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pthread_cond_destroy ---------*- 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_PTHREAD_PTHREAD_COND_DESTROY_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_DESTROY_H
+
+#include "include/llvm-libc-types/pthread_cond_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_cond_destroy(pthread_cond_t *cond);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_DESTROY_H
diff --git a/libc/src/pthread/pthread_cond_init.cpp b/libc/src/pthread/pthread_cond_init.cpp
new file mode 100644
index 0000000000000..62b050a6c8ce2
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_init.cpp
@@ -0,0 +1,49 @@
+//===-- Implementation of the pthread_cond_init 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 "pthread_cond_init.h"
+
+#include "include/llvm-libc-macros/pthread-macros.h"
+#include "src/__support/CPP/new.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 "hdr/errno_macros.h" // EINVAL
+#include "hdr/time_macros.h" // CLOCK_MONOTONIC, CLOCK_REALTIME
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(
+ sizeof(CndVar) == sizeof(pthread_cond_t) &&
+ alignof(CndVar) == alignof(pthread_cond_t),
+ "The public pthread_cond_t type must be of the same size and alignment "
+ "as the internal condition variable type.");
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_init,
+ (pthread_cond_t *__restrict cond,
+ const pthread_condattr_t *__restrict attr)) {
+ LIBC_CRASH_ON_NULLPTR(cond);
+ // POSIX.1 says that CLOCK_REALTIME shall be used if the clock is not
+ // monotonic explicitly.
+ pthread_condattr_t condattr{
+ /*clock=*/CLOCK_REALTIME,
+ /*pshared=*/PTHREAD_PROCESS_PRIVATE,
+ };
+ if (attr)
+ condattr = *attr;
+
+ // POSIX.1 does not specify behavior for invalid clock values.
+ bool is_shared = condattr.pshared == PTHREAD_PROCESS_SHARED;
+ bool is_realtime = condattr.clock == CLOCK_REALTIME;
+ new (cond) CndVar(is_shared, is_realtime);
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_cond_init.h b/libc/src/pthread/pthread_cond_init.h
new file mode 100644
index 0000000000000..4c334fdfd66b6
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_init.h
@@ -0,0 +1,23 @@
+//===-- Implementation header for pthread_cond_init -------------*- 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_PTHREAD_PTHREAD_COND_INIT_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_INIT_H
+
+#include "include/llvm-libc-types/pthread_cond_t.h"
+#include "include/llvm-libc-types/pthread_condattr_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_cond_init(pthread_cond_t *__restrict cond,
+ const pthread_condattr_t *__restrict attr);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_INIT_H
>From 9b01c6db0905ff9cb08c7ad70c1328910bf30a11 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 00:00:48 -0400
Subject: [PATCH 2/7] correct initializer
---
libc/include/llvm-libc-macros/pthread-macros.h | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/libc/include/llvm-libc-macros/pthread-macros.h b/libc/include/llvm-libc-macros/pthread-macros.h
index 34082bed32dff..6565048e26423 100644
--- a/libc/include/llvm-libc-macros/pthread-macros.h
+++ b/libc/include/llvm-libc-macros/pthread-macros.h
@@ -47,8 +47,11 @@
#define PTHREAD_COND_INITIALIZER \
{ \
- /* .__waiter_queue = */ {NULL, NULL}, /* .__futex = */ {0}, \
- /* .__shared = */ {0}, /* .__padding = */ {0}, \
+ /* .__waiter_queue = */ {NULL, NULL}, \
+ /* .__futex = */ {0}, \
+ /* .__shared = */ 0, \
+ /*__is_realtime = */ 1, \
+ /* .__padding = */ {0}, \
}
#define PTHREAD_RWLOCK_INITIALIZER \
>From 72d123741855608c5a2afcf4def1020cc25ec114 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 00:21:17 -0400
Subject: [PATCH 3/7] add all entrypoints
---
libc/config/linux/x86_64/entrypoints.txt | 5 +
libc/docs/dev/undefined_behavior.rst | 10 ++
libc/include/CMakeLists.txt | 4 +-
libc/include/pthread.yaml | 26 +++++
libc/src/__support/threads/mutex.h | 1 +
libc/src/__support/threads/unix_mutex.h | 2 +
libc/src/pthread/CMakeLists.txt | 108 +++++++++++++++++---
libc/src/pthread/pthread_cond_broadcast.cpp | 33 ++++++
libc/src/pthread/pthread_cond_broadcast.h | 21 ++++
libc/src/pthread/pthread_cond_clockwait.cpp | 31 ++++++
libc/src/pthread/pthread_cond_clockwait.h | 27 +++++
libc/src/pthread/pthread_cond_init.cpp | 27 ++++-
libc/src/pthread/pthread_cond_signal.cpp | 33 ++++++
libc/src/pthread/pthread_cond_signal.h | 21 ++++
libc/src/pthread/pthread_cond_timedwait.cpp | 28 +++++
libc/src/pthread/pthread_cond_timedwait.h | 25 +++++
libc/src/pthread/pthread_cond_utils.h | 95 +++++++++++++++++
libc/src/pthread/pthread_cond_wait.cpp | 27 +++++
libc/src/pthread/pthread_cond_wait.h | 23 +++++
19 files changed, 531 insertions(+), 16 deletions(-)
create mode 100644 libc/src/pthread/pthread_cond_broadcast.cpp
create mode 100644 libc/src/pthread/pthread_cond_broadcast.h
create mode 100644 libc/src/pthread/pthread_cond_clockwait.cpp
create mode 100644 libc/src/pthread/pthread_cond_clockwait.h
create mode 100644 libc/src/pthread/pthread_cond_signal.cpp
create mode 100644 libc/src/pthread/pthread_cond_signal.h
create mode 100644 libc/src/pthread/pthread_cond_timedwait.cpp
create mode 100644 libc/src/pthread/pthread_cond_timedwait.h
create mode 100644 libc/src/pthread/pthread_cond_utils.h
create mode 100644 libc/src/pthread/pthread_cond_wait.cpp
create mode 100644 libc/src/pthread/pthread_cond_wait.h
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 2ba35d84e603f..27569f0fae82b 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1190,8 +1190,13 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_condattr_init
libc.src.pthread.pthread_condattr_setclock
libc.src.pthread.pthread_condattr_setpshared
+ libc.src.pthread.pthread_cond_broadcast
+ libc.src.pthread.pthread_cond_clockwait
libc.src.pthread.pthread_cond_destroy
libc.src.pthread.pthread_cond_init
+ libc.src.pthread.pthread_cond_signal
+ libc.src.pthread.pthread_cond_timedwait
+ libc.src.pthread.pthread_cond_wait
libc.src.pthread.pthread_create
libc.src.pthread.pthread_detach
libc.src.pthread.pthread_equal
diff --git a/libc/docs/dev/undefined_behavior.rst b/libc/docs/dev/undefined_behavior.rst
index a09088407e304..59eafa4d86ffb 100644
--- a/libc/docs/dev/undefined_behavior.rst
+++ b/libc/docs/dev/undefined_behavior.rst
@@ -96,6 +96,16 @@ Unrecognized ``clockid_t`` values for ``pthread_rwlock_clock*`` APIs
POSIX.1-2024 only demands support for ``CLOCK_REALTIME`` and ``CLOCK_MONOTONIC``. Currently,
as in LLVM libc, if other clock ids are used, they will be treated as monotonic clocks.
+Invalid condition variable attributes for ``pthread_cond_init``
+---------------------------------------------------------------
+POSIX.1-2024 specifies that ``pthread_cond_init`` returns an error number on
+failure, but it does not specify the behavior when the provided
+``pthread_condattr_t`` contains an unsupported clock value or an unrecognized
+process-shared flag. LLVM's libc returns ``EINVAL`` for unsupported clock values
+and for process-shared flags other than ``PTHREAD_PROCESS_PRIVATE`` and
+``PTHREAD_PROCESS_SHARED``. This returns the error number directly and does not
+set ``errno``.
+
PThread SpinLock Destroy
------------------------
POSIX.1 Issue 7 updates the spinlock destroy behavior description such that the return code for
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 82a2b71d6311b..575e5e11f92d8 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -446,6 +446,7 @@ add_header_macro(
.llvm-libc-types.__pthread_once_func_t
.llvm-libc-types.__pthread_start_t
.llvm-libc-types.__pthread_tss_dtor_t
+ .llvm-libc-types.clockid_t
.llvm-libc-types.pthread_attr_t
.llvm-libc-types.pthread_cond_t
.llvm-libc-types.pthread_condattr_t
@@ -459,8 +460,9 @@ add_header_macro(
.llvm-libc-types.pthread_rwlockattr_t
.llvm-libc-types.pthread_spinlock_t
.llvm-libc-types.pthread_t
+ .llvm-libc-types.struct_timespec
.llvm_libc_common_h
-)
+ )
if(LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64")
add_header_macro(
diff --git a/libc/include/pthread.yaml b/libc/include/pthread.yaml
index 8b45c8431b2d0..bb735780ab555 100644
--- a/libc/include/pthread.yaml
+++ b/libc/include/pthread.yaml
@@ -159,6 +159,17 @@ functions:
arguments:
- type: pthread_condattr_t *
- type: int
+ - name: pthread_cond_broadcast
+ return_type: int
+ arguments:
+ - type: pthread_cond_t *
+ - name: pthread_cond_clockwait
+ return_type: int
+ arguments:
+ - type: pthread_cond_t *__restrict
+ - type: pthread_mutex_t *__restrict
+ - type: clockid_t
+ - type: const struct timespec *__restrict
- name: pthread_cond_destroy
return_type: int
arguments:
@@ -168,6 +179,21 @@ functions:
arguments:
- type: pthread_cond_t *__restrict
- type: const pthread_condattr_t *__restrict
+ - name: pthread_cond_signal
+ return_type: int
+ arguments:
+ - type: pthread_cond_t *
+ - name: pthread_cond_timedwait
+ return_type: int
+ arguments:
+ - type: pthread_cond_t *__restrict
+ - type: pthread_mutex_t *__restrict
+ - type: const struct timespec *__restrict
+ - name: pthread_cond_wait
+ return_type: int
+ arguments:
+ - type: pthread_cond_t *__restrict
+ - type: pthread_mutex_t *__restrict
- name: pthread_create
return_type: int
arguments:
diff --git a/libc/src/__support/threads/mutex.h b/libc/src/__support/threads/mutex.h
index 76a656729eef7..d4d13093a2ce7 100644
--- a/libc/src/__support/threads/mutex.h
+++ b/libc/src/__support/threads/mutex.h
@@ -62,6 +62,7 @@ struct Mutex {
LIBC_INLINE MutexError unlock() { return MutexError::NONE; }
LIBC_INLINE MutexError reset() { return MutexError::NONE; }
LIBC_INLINE MutexError trylock() { return MutexError::NONE; }
+ LIBC_INLINE bool is_robust() const { return false; }
};
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/threads/unix_mutex.h b/libc/src/__support/threads/unix_mutex.h
index e56c296feb162..ac05e2528ddca 100644
--- a/libc/src/__support/threads/unix_mutex.h
+++ b/libc/src/__support/threads/unix_mutex.h
@@ -89,6 +89,8 @@ class Mutex final : private RawMutex {
LIBC_INLINE bool can_be_requeued() const {
return !this->pshared && !this->robust;
}
+
+ LIBC_INLINE bool is_robust() const { return this->robust; }
};
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index 203420c1b058d..2031bb1f14a0f 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -191,6 +191,52 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_header_library(
+ pthread_cond_utils
+ HDRS
+ pthread_cond_utils.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.time_macros
+ libc.include.llvm-libc-types.clockid_t
+ libc.include.llvm-libc-types.pthread_cond_t
+ libc.include.llvm-libc-types.pthread_mutex_t
+ libc.include.llvm-libc-types.struct_timespec
+ libc.src.__support.CPP.optional
+ libc.src.__support.macros.null_check
+ libc.src.__support.macros.optimization
+ libc.src.__support.threads.CndVar
+ libc.src.__support.threads.mutex
+ libc.src.__support.time.abs_timeout
+)
+
+add_entrypoint_object(
+ pthread_cond_broadcast
+ SRCS
+ pthread_cond_broadcast.cpp
+ HDRS
+ pthread_cond_broadcast.h
+ DEPENDS
+ libc.include.llvm-libc-types.pthread_cond_t
+ libc.src.__support.macros.null_check
+ libc.src.__support.threads.CndVar
+)
+
+add_entrypoint_object(
+ pthread_cond_clockwait
+ SRCS
+ pthread_cond_clockwait.cpp
+ HDRS
+ pthread_cond_clockwait.h
+ DEPENDS
+ .pthread_cond_utils
+ libc.hdr.errno_macros
+ libc.include.llvm-libc-types.clockid_t
+ libc.include.llvm-libc-types.pthread_cond_t
+ libc.include.llvm-libc-types.pthread_mutex_t
+ libc.include.llvm-libc-types.struct_timespec
+)
+
add_entrypoint_object(
pthread_cond_destroy
SRCS
@@ -206,18 +252,56 @@ add_entrypoint_object(
pthread_cond_init
SRCS
pthread_cond_init.cpp
- HDRS
- pthread_cond_init.h
- DEPENDS
- libc.hdr.errno_macros
- libc.hdr.time_macros
- libc.include.llvm-libc-macros.pthread_macros
- libc.include.llvm-libc-types.pthread_cond_t
- libc.include.llvm-libc-types.pthread_condattr_t
- libc.src.__support.CPP.new
- libc.src.__support.macros.null_check
- libc.src.__support.threads.CndVar
- )
+ HDRS
+ pthread_cond_init.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.time_macros
+ libc.include.llvm-libc-macros.pthread_macros
+ libc.include.llvm-libc-types.pthread_cond_t
+ libc.include.llvm-libc-types.pthread_condattr_t
+ libc.src.__support.CPP.new
+ libc.src.__support.macros.null_check
+ libc.src.__support.threads.CndVar
+)
+
+add_entrypoint_object(
+ pthread_cond_signal
+ SRCS
+ pthread_cond_signal.cpp
+ HDRS
+ pthread_cond_signal.h
+ DEPENDS
+ libc.include.llvm-libc-types.pthread_cond_t
+ libc.src.__support.macros.null_check
+ libc.src.__support.threads.CndVar
+)
+
+add_entrypoint_object(
+ pthread_cond_timedwait
+ SRCS
+ pthread_cond_timedwait.cpp
+ HDRS
+ pthread_cond_timedwait.h
+ DEPENDS
+ .pthread_cond_utils
+ libc.include.llvm-libc-types.pthread_cond_t
+ libc.include.llvm-libc-types.pthread_mutex_t
+ libc.include.llvm-libc-types.struct_timespec
+)
+
+add_entrypoint_object(
+ pthread_cond_wait
+ SRCS
+ pthread_cond_wait.cpp
+ HDRS
+ pthread_cond_wait.h
+ DEPENDS
+ .pthread_cond_utils
+ libc.src.__support.CPP.optional
+ libc.include.llvm-libc-types.pthread_cond_t
+ libc.include.llvm-libc-types.pthread_mutex_t
+)
add_header_library(
pthread_mutexattr
diff --git a/libc/src/pthread/pthread_cond_broadcast.cpp b/libc/src/pthread/pthread_cond_broadcast.cpp
new file mode 100644
index 0000000000000..7e56c43242fe2
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_broadcast.cpp
@@ -0,0 +1,33 @@
+//===-- Implementation of pthread_cond_broadcast --------------------------===//
+//
+// 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 "pthread_cond_broadcast.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"
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(
+ sizeof(CndVar) == sizeof(pthread_cond_t) &&
+ alignof(CndVar) == alignof(pthread_cond_t),
+ "The public pthread_cond_t type must be of the same size and alignment "
+ "as the internal condition variable type.");
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_broadcast, (pthread_cond_t * cond)) {
+ LIBC_CRASH_ON_NULLPTR(cond);
+ // TODO: use cpp:start_lifetime_as once
+ // https://github.com/llvm/llvm-project/pull/193326 is merged
+ auto *cndvar = reinterpret_cast<CndVar *>(cond);
+ cndvar->broadcast();
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_cond_broadcast.h b/libc/src/pthread/pthread_cond_broadcast.h
new file mode 100644
index 0000000000000..d0f8f495d9009
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_broadcast.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pthread_cond_broadcast ------*- 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_PTHREAD_PTHREAD_COND_BROADCAST_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_BROADCAST_H
+
+#include "include/llvm-libc-types/pthread_cond_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_cond_broadcast(pthread_cond_t *cond);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_BROADCAST_H
diff --git a/libc/src/pthread/pthread_cond_clockwait.cpp b/libc/src/pthread/pthread_cond_clockwait.cpp
new file mode 100644
index 0000000000000..564f9341ffc9c
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_clockwait.cpp
@@ -0,0 +1,31 @@
+//===-- Implementation of pthread_cond_clockwait --------------------------===//
+//
+// 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 "pthread_cond_clockwait.h"
+
+#include "pthread_cond_utils.h"
+
+#include "hdr/errno_macros.h" // EINVAL
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_clockwait,
+ (pthread_cond_t *__restrict cond,
+ pthread_mutex_t *__restrict mutex, clockid_t clock_id,
+ const struct timespec *__restrict abstime)) {
+ CndVar *cndvar = pthread_cond_utils::to_cndvar(cond);
+ Mutex *m = pthread_cond_utils::to_mutex(mutex);
+ if (!pthread_cond_utils::is_supported_clock(clock_id))
+ return EINVAL;
+ return pthread_cond_utils::timed_wait(
+ cndvar, m, abstime, pthread_cond_utils::is_realtime_clock(clock_id));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_cond_clockwait.h b/libc/src/pthread/pthread_cond_clockwait.h
new file mode 100644
index 0000000000000..8d2d3279f3078
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_clockwait.h
@@ -0,0 +1,27 @@
+//===-- Implementation header for pthread_cond_clockwait -------*- 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_PTHREAD_PTHREAD_COND_CLOCKWAIT_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_CLOCKWAIT_H
+
+#include "include/llvm-libc-types/clockid_t.h"
+#include "include/llvm-libc-types/pthread_cond_t.h"
+#include "include/llvm-libc-types/pthread_mutex_t.h"
+#include "include/llvm-libc-types/struct_timespec.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_cond_clockwait(pthread_cond_t *__restrict cond,
+ pthread_mutex_t *__restrict mutex,
+ clockid_t clock_id,
+ const struct timespec *__restrict abstime);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_CLOCKWAIT_H
diff --git a/libc/src/pthread/pthread_cond_init.cpp b/libc/src/pthread/pthread_cond_init.cpp
index 62b050a6c8ce2..eac2ea505a935 100644
--- a/libc/src/pthread/pthread_cond_init.cpp
+++ b/libc/src/pthread/pthread_cond_init.cpp
@@ -39,9 +39,30 @@ LLVM_LIBC_FUNCTION(int, pthread_cond_init,
if (attr)
condattr = *attr;
- // POSIX.1 does not specify behavior for invalid clock values.
- bool is_shared = condattr.pshared == PTHREAD_PROCESS_SHARED;
- bool is_realtime = condattr.clock == CLOCK_REALTIME;
+ bool is_shared;
+ switch (condattr.pshared) {
+ case PTHREAD_PROCESS_PRIVATE:
+ is_shared = false;
+ break;
+ case PTHREAD_PROCESS_SHARED:
+ is_shared = true;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ bool is_realtime;
+ switch (condattr.clock) {
+ case CLOCK_MONOTONIC:
+ is_realtime = false;
+ break;
+ case CLOCK_REALTIME:
+ is_realtime = true;
+ break;
+ default:
+ return EINVAL;
+ }
+
new (cond) CndVar(is_shared, is_realtime);
return 0;
}
diff --git a/libc/src/pthread/pthread_cond_signal.cpp b/libc/src/pthread/pthread_cond_signal.cpp
new file mode 100644
index 0000000000000..9244e85c48d5b
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_signal.cpp
@@ -0,0 +1,33 @@
+//===-- Implementation of pthread_cond_signal -----------------------------===//
+//
+// 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 "pthread_cond_signal.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"
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(
+ sizeof(CndVar) == sizeof(pthread_cond_t) &&
+ alignof(CndVar) == alignof(pthread_cond_t),
+ "The public pthread_cond_t type must be of the same size and alignment "
+ "as the internal condition variable type.");
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_signal, (pthread_cond_t * cond)) {
+ LIBC_CRASH_ON_NULLPTR(cond);
+ // TODO: use cpp:start_lifetime_as once
+ // https://github.com/llvm/llvm-project/pull/193326 is merged
+ auto *cndvar = reinterpret_cast<CndVar *>(cond);
+ cndvar->notify_one();
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_cond_signal.h b/libc/src/pthread/pthread_cond_signal.h
new file mode 100644
index 0000000000000..c0a682b4673ce
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_signal.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pthread_cond_signal ---------*- 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_PTHREAD_PTHREAD_COND_SIGNAL_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_SIGNAL_H
+
+#include "include/llvm-libc-types/pthread_cond_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_cond_signal(pthread_cond_t *cond);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_SIGNAL_H
diff --git a/libc/src/pthread/pthread_cond_timedwait.cpp b/libc/src/pthread/pthread_cond_timedwait.cpp
new file mode 100644
index 0000000000000..72947b0543913
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_timedwait.cpp
@@ -0,0 +1,28 @@
+//===-- Implementation of pthread_cond_timedwait --------------------------===//
+//
+// 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 "pthread_cond_timedwait.h"
+
+#include "pthread_cond_utils.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_timedwait,
+ (pthread_cond_t *__restrict cond,
+ pthread_mutex_t *__restrict mutex,
+ const struct timespec *__restrict abstime)) {
+ CndVar *cndvar = pthread_cond_utils::to_cndvar(cond);
+ return pthread_cond_utils::timed_wait(
+ cndvar, pthread_cond_utils::to_mutex(mutex), abstime,
+ cndvar->default_clock_is_realtime());
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_cond_timedwait.h b/libc/src/pthread/pthread_cond_timedwait.h
new file mode 100644
index 0000000000000..efb6296b8a494
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_timedwait.h
@@ -0,0 +1,25 @@
+//===-- Implementation header for pthread_cond_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_PTHREAD_PTHREAD_COND_TIMEDWAIT_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_TIMEDWAIT_H
+
+#include "include/llvm-libc-types/pthread_cond_t.h"
+#include "include/llvm-libc-types/pthread_mutex_t.h"
+#include "include/llvm-libc-types/struct_timespec.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_cond_timedwait(pthread_cond_t *__restrict cond,
+ pthread_mutex_t *__restrict mutex,
+ const struct timespec *__restrict abstime);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_TIMEDWAIT_H
diff --git a/libc/src/pthread/pthread_cond_utils.h b/libc/src/pthread/pthread_cond_utils.h
new file mode 100644
index 0000000000000..a066f1cdd7ba6
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_utils.h
@@ -0,0 +1,95 @@
+//===-- Shared pthread condition variable helpers ---------------*- 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_PTHREAD_PTHREAD_COND_UTILS_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_UTILS_H
+
+#include "hdr/errno_macros.h" // EINVAL, ETIMEDOUT
+#include "hdr/time_macros.h" // CLOCK_MONOTONIC, CLOCK_REALTIME
+#include "include/llvm-libc-types/clockid_t.h"
+#include "include/llvm-libc-types/pthread_cond_t.h"
+#include "include/llvm-libc-types/pthread_mutex_t.h"
+#include "include/llvm-libc-types/struct_timespec.h"
+#include "src/__support/CPP/optional.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/threads/CndVar.h"
+#include "src/__support/threads/mutex.h"
+#include "src/__support/time/abs_timeout.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace pthread_cond_utils {
+
+static_assert(
+ sizeof(CndVar) == sizeof(pthread_cond_t) &&
+ alignof(CndVar) == alignof(pthread_cond_t),
+ "The public pthread_cond_t type must be of the same size and alignment "
+ "as the internal condition variable type.");
+
+LIBC_INLINE CndVar *to_cndvar(pthread_cond_t *cond) {
+ LIBC_CRASH_ON_NULLPTR(cond);
+ // TODO: use cpp:start_lifetime_as once
+ // https://github.com/llvm/llvm-project/pull/193326 is merged
+ return reinterpret_cast<CndVar *>(cond);
+}
+
+LIBC_INLINE Mutex *to_mutex(pthread_mutex_t *mutex) {
+ LIBC_CRASH_ON_NULLPTR(mutex);
+ // TODO: use cpp:start_lifetime_as once
+ // https://github.com/llvm/llvm-project/pull/193326 is merged
+ Mutex *m = reinterpret_cast<Mutex *>(mutex);
+ // TODO: support robust mutex.
+ if (m->is_robust())
+ __builtin_trap();
+ return m;
+}
+
+LIBC_INLINE bool is_supported_clock(clockid_t clock_id) {
+ return clock_id == CLOCK_MONOTONIC || clock_id == CLOCK_REALTIME;
+}
+
+LIBC_INLINE bool is_realtime_clock(clockid_t clock_id) {
+ return clock_id == CLOCK_REALTIME;
+}
+
+LIBC_INLINE int wait(CndVar *cond, Mutex *mutex,
+ cpp::optional<CndVar::Timeout> timeout) {
+ switch (cond->wait(mutex, timeout)) {
+ case CndVarResult::Success:
+ return 0;
+ case CndVarResult::Timeout:
+ return ETIMEDOUT;
+ case CndVarResult::MutexError:
+ return EINVAL;
+ }
+ __builtin_unreachable();
+}
+
+LIBC_INLINE int timed_wait(CndVar *cond, Mutex *mutex,
+ const struct timespec *abstime, bool is_realtime) {
+ LIBC_CRASH_ON_NULLPTR(abstime);
+ auto timeout =
+ internal::AbsTimeout::from_timespec(*abstime, /*realtime=*/is_realtime);
+ if (LIBC_LIKELY(timeout.has_value()))
+ return wait(cond, mutex, timeout.value());
+
+ switch (timeout.error()) {
+ case internal::AbsTimeout::Error::Invalid:
+ return EINVAL;
+ case internal::AbsTimeout::Error::BeforeEpoch:
+ return ETIMEDOUT;
+ }
+ __builtin_unreachable();
+}
+
+} // namespace pthread_cond_utils
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_UTILS_H
diff --git a/libc/src/pthread/pthread_cond_wait.cpp b/libc/src/pthread/pthread_cond_wait.cpp
new file mode 100644
index 0000000000000..a6d00cafe47fb
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_wait.cpp
@@ -0,0 +1,27 @@
+//===-- Implementation of pthread_cond_wait -------------------------------===//
+//
+// 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 "pthread_cond_wait.h"
+
+#include "pthread_cond_utils.h"
+
+#include "src/__support/CPP/optional.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_wait,
+ (pthread_cond_t *__restrict cond,
+ pthread_mutex_t *__restrict mutex)) {
+ return pthread_cond_utils::wait(pthread_cond_utils::to_cndvar(cond),
+ pthread_cond_utils::to_mutex(mutex),
+ cpp::nullopt);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_cond_wait.h b/libc/src/pthread/pthread_cond_wait.h
new file mode 100644
index 0000000000000..1b0b87eb42d4f
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_wait.h
@@ -0,0 +1,23 @@
+//===-- Implementation header for pthread_cond_wait ------------*- 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_PTHREAD_PTHREAD_COND_WAIT_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_WAIT_H
+
+#include "include/llvm-libc-types/pthread_cond_t.h"
+#include "include/llvm-libc-types/pthread_mutex_t.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_cond_wait(pthread_cond_t *__restrict cond,
+ pthread_mutex_t *__restrict mutex);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_WAIT_H
>From 3116dd208724c40162923d2bd5ca182f249ef8d8 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 00:35:27 -0400
Subject: [PATCH 4/7] fix shared and add tests
---
libc/src/__support/threads/CndVar.h | 4 +-
.../integration/src/pthread/CMakeLists.txt | 33 +++
.../src/pthread/pthread_cond_test.cpp | 226 ++++++++++++++++++
3 files changed, 261 insertions(+), 2 deletions(-)
create mode 100644 libc/test/integration/src/pthread/pthread_cond_test.cpp
diff --git a/libc/src/__support/threads/CndVar.h b/libc/src/__support/threads/CndVar.h
index 09487c808e052..f779ecfc7693d 100644
--- a/libc/src/__support/threads/CndVar.h
+++ b/libc/src/__support/threads/CndVar.h
@@ -174,9 +174,9 @@ class CndVar {
// increase the sequence number
shared_futex.fetch_add(1);
if (is_broadcast)
- shared_futex.notify_all();
+ shared_futex.notify_all(/*is_shared=*/true);
else
- shared_futex.notify_one();
+ shared_futex.notify_one(/*is_shared=*/true);
return;
}
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index eaef5013d3c94..71cb039f7761e 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -81,6 +81,39 @@ add_integration_test(
libc.src.__support.threads.sleep
)
+add_integration_test(
+ pthread_cond_test
+ SUITE
+ libc-pthread-integration-tests
+ SRCS
+ pthread_cond_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.time_macros
+ libc.include.pthread
+ libc.src.__support.CPP.atomic
+ libc.src.pthread.pthread_cond_broadcast
+ libc.src.pthread.pthread_cond_clockwait
+ libc.src.pthread.pthread_cond_destroy
+ libc.src.pthread.pthread_cond_init
+ libc.src.pthread.pthread_cond_signal
+ libc.src.pthread.pthread_cond_timedwait
+ libc.src.pthread.pthread_cond_wait
+ libc.src.pthread.pthread_condattr_destroy
+ libc.src.pthread.pthread_condattr_init
+ libc.src.pthread.pthread_condattr_setpshared
+ libc.src.pthread.pthread_create
+ libc.src.pthread.pthread_join
+ libc.src.pthread.pthread_mutex_destroy
+ libc.src.pthread.pthread_mutex_init
+ libc.src.pthread.pthread_mutex_lock
+ libc.src.pthread.pthread_mutex_unlock
+ libc.src.pthread.pthread_mutexattr_destroy
+ libc.src.pthread.pthread_mutexattr_init
+ libc.src.pthread.pthread_mutexattr_setpshared
+ libc.src.time.clock_gettime
+)
+
add_integration_test(
pthread_spinlock_test
SUITE
diff --git a/libc/test/integration/src/pthread/pthread_cond_test.cpp b/libc/test/integration/src/pthread/pthread_cond_test.cpp
new file mode 100644
index 0000000000000..dec9b89c907d5
--- /dev/null
+++ b/libc/test/integration/src/pthread/pthread_cond_test.cpp
@@ -0,0 +1,226 @@
+//===-- Integration test for pthread condition variables ------------------===//
+//
+// 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 "hdr/errno_macros.h"
+#include "hdr/time_macros.h"
+#include "src/__support/CPP/atomic.h"
+#include "src/pthread/pthread_cond_broadcast.h"
+#include "src/pthread/pthread_cond_clockwait.h"
+#include "src/pthread/pthread_cond_destroy.h"
+#include "src/pthread/pthread_cond_init.h"
+#include "src/pthread/pthread_cond_signal.h"
+#include "src/pthread/pthread_cond_timedwait.h"
+#include "src/pthread/pthread_cond_wait.h"
+#include "src/pthread/pthread_condattr_destroy.h"
+#include "src/pthread/pthread_condattr_init.h"
+#include "src/pthread/pthread_condattr_setpshared.h"
+#include "src/pthread/pthread_create.h"
+#include "src/pthread/pthread_join.h"
+#include "src/pthread/pthread_mutex_destroy.h"
+#include "src/pthread/pthread_mutex_init.h"
+#include "src/pthread/pthread_mutex_lock.h"
+#include "src/pthread/pthread_mutex_unlock.h"
+#include "src/pthread/pthread_mutexattr_destroy.h"
+#include "src/pthread/pthread_mutexattr_init.h"
+#include "src/pthread/pthread_mutexattr_setpshared.h"
+#include "src/time/clock_gettime.h"
+#include "test/IntegrationTest/test.h"
+
+#include <pthread.h>
+
+namespace {
+
+constexpr size_t PRODUCER_COUNT = 10;
+constexpr size_t CONSUMER_COUNT = 10;
+constexpr size_t ITEMS_PER_PRODUCER = 80;
+constexpr int NUM_ITERATIONS = 10;
+
+enum class TimeoutMode {
+ Disabled,
+ Default,
+ Realtime,
+ Monotonic,
+};
+
+template <bool UseBroadcast, bool IsShared, TimeoutMode Timeout>
+struct TestConfig {
+ LIBC_INLINE_VAR static constexpr bool USE_BROADCAST = UseBroadcast;
+ LIBC_INLINE_VAR static constexpr bool IS_SHARED = IsShared;
+ LIBC_INLINE_VAR static constexpr TimeoutMode TIMEOUT = Timeout;
+};
+
+struct QueueState {
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+ size_t consumed;
+ size_t produced;
+ LIBC_NAMESPACE::cpp::Atomic<size_t> exited_consumers;
+};
+
+static void add_ns(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;
+ }
+}
+
+template <typename Config> static timespec deadline() {
+ static_assert(Config::TIMEOUT != TimeoutMode::Disabled);
+
+ constexpr clockid_t CLOCK_ID = Config::TIMEOUT == TimeoutMode::Monotonic
+ ? CLOCK_MONOTONIC
+ : CLOCK_REALTIME;
+ timespec ts{};
+ ASSERT_EQ(LIBC_NAMESPACE::clock_gettime(CLOCK_ID, &ts), 0);
+ add_ns(ts, 1000);
+ return ts;
+}
+
+template <typename Config>
+static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
+ if constexpr (Config::TIMEOUT == TimeoutMode::Disabled) {
+ return LIBC_NAMESPACE::pthread_cond_wait(cond, mutex);
+ } else if constexpr (Config::TIMEOUT == TimeoutMode::Default) {
+ timespec ts = deadline<Config>();
+ return LIBC_NAMESPACE::pthread_cond_timedwait(cond, mutex, &ts);
+ } else {
+ constexpr clockid_t CLOCK_ID = Config::TIMEOUT == TimeoutMode::Monotonic
+ ? CLOCK_MONOTONIC
+ : CLOCK_REALTIME;
+ timespec ts = deadline<Config>();
+ return LIBC_NAMESPACE::pthread_cond_clockwait(cond, mutex, CLOCK_ID, &ts);
+ }
+}
+
+template <typename Config> static void *consumer(void *arg) {
+ auto *state = static_cast<QueueState *>(arg);
+ constexpr size_t TOTAL_ITEMS = PRODUCER_COUNT * ITEMS_PER_PRODUCER;
+
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&state->mutex), 0);
+ while (state->consumed != TOTAL_ITEMS) {
+ int wait_result = cond_wait<Config>(&state->cond, &state->mutex);
+ if constexpr (Config::TIMEOUT == TimeoutMode::Disabled) {
+ ASSERT_EQ(wait_result, 0);
+ } else {
+ ASSERT_TRUE(wait_result == 0 || wait_result == ETIMEDOUT);
+ }
+
+ if (state->produced == 0)
+ continue;
+
+ --state->produced;
+ ++state->consumed;
+ }
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&state->mutex), 0);
+ state->exited_consumers.fetch_add(1);
+ return nullptr;
+}
+
+template <typename Config> static void *producer(void *arg) {
+ auto *state = static_cast<QueueState *>(arg);
+ for (size_t i = 0; i < ITEMS_PER_PRODUCER; ++i) {
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&state->mutex), 0);
+ ++state->produced;
+ if constexpr (Config::USE_BROADCAST) {
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_broadcast(&state->cond), 0);
+ } else {
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_signal(&state->cond), 0);
+ }
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&state->mutex), 0);
+ }
+ return nullptr;
+}
+
+template <typename Config> static void init_state(QueueState &state) {
+ state.consumed = 0;
+ state.produced = 0;
+ state.exited_consumers = 0;
+
+ pthread_condattr_t cond_attr;
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_condattr_init(&cond_attr), 0);
+ pthread_mutexattr_t mutex_attr;
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutexattr_init(&mutex_attr), 0);
+
+ if constexpr (Config::IS_SHARED) {
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_condattr_setpshared(
+ &cond_attr, PTHREAD_PROCESS_SHARED),
+ 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutexattr_setpshared(
+ &mutex_attr, PTHREAD_PROCESS_SHARED),
+ 0);
+ }
+
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_init(&state.cond, &cond_attr), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&state.mutex, &mutex_attr), 0);
+
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_condattr_destroy(&cond_attr), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutexattr_destroy(&mutex_attr), 0);
+}
+
+static void notify(QueueState &state, bool use_broadcast) {
+ if (use_broadcast) {
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_broadcast(&state.cond), 0);
+ } else {
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_signal(&state.cond), 0);
+ }
+}
+
+template <typename Config> static void stress_test() {
+ for (int iter = 0; iter < NUM_ITERATIONS; ++iter) {
+ QueueState state{};
+ init_state<Config>(state);
+
+ pthread_t producer_threads[PRODUCER_COUNT];
+ pthread_t consumer_threads[CONSUMER_COUNT];
+
+ for (size_t i = 0; i < CONSUMER_COUNT; ++i)
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&consumer_threads[i], nullptr,
+ consumer<Config>, &state),
+ 0);
+
+ for (size_t i = 0; i < PRODUCER_COUNT; ++i)
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&producer_threads[i], nullptr,
+ producer<Config>, &state),
+ 0);
+
+ for (size_t i = 0; i < PRODUCER_COUNT; ++i)
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_join(producer_threads[i], nullptr), 0);
+
+ while (state.exited_consumers != CONSUMER_COUNT)
+ notify(state, Config::USE_BROADCAST);
+
+ for (size_t i = 0; i < CONSUMER_COUNT; ++i)
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_join(consumer_threads[i], nullptr), 0);
+
+ ASSERT_EQ(state.consumed, PRODUCER_COUNT * ITEMS_PER_PRODUCER);
+ ASSERT_EQ(state.produced, size_t(0));
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_destroy(&state.cond), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_destroy(&state.mutex), 0);
+ }
+}
+
+template <bool UseBroadcast, bool IsShared> static void run_timeout_modes() {
+ stress_test<TestConfig<UseBroadcast, IsShared, TimeoutMode::Disabled>>();
+ stress_test<TestConfig<UseBroadcast, IsShared, TimeoutMode::Default>>();
+ stress_test<TestConfig<UseBroadcast, IsShared, TimeoutMode::Realtime>>();
+ stress_test<TestConfig<UseBroadcast, IsShared, TimeoutMode::Monotonic>>();
+}
+
+template <bool UseBroadcast> static void run_shared_modes() {
+ run_timeout_modes<UseBroadcast, false>();
+ run_timeout_modes<UseBroadcast, true>();
+}
+
+} // namespace
+
+TEST_MAIN() {
+ run_shared_modes<false>();
+ run_shared_modes<true>();
+ return 0;
+}
>From 319cf742d53cedd9c2d65ada7bd12b250be805e2 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 23 Apr 2026 10:26:54 -0400
Subject: [PATCH 5/7] address reviews
---
libc/include/llvm-libc-macros/pthread-macros.h | 4 ++--
libc/include/llvm-libc-types/pthread_cond_t.h | 2 +-
libc/src/pthread/CMakeLists.txt | 11 +++--------
libc/src/pthread/pthread_cond_broadcast.cpp | 16 +++-------------
libc/src/pthread/pthread_cond_destroy.cpp | 14 +++-----------
libc/src/pthread/pthread_cond_init.cpp | 6 ------
libc/src/pthread/pthread_cond_signal.cpp | 16 +++-------------
libc/src/pthread/pthread_cond_utils.h | 4 +---
8 files changed, 16 insertions(+), 57 deletions(-)
diff --git a/libc/include/llvm-libc-macros/pthread-macros.h b/libc/include/llvm-libc-macros/pthread-macros.h
index 6565048e26423..5ac95be66310d 100644
--- a/libc/include/llvm-libc-macros/pthread-macros.h
+++ b/libc/include/llvm-libc-macros/pthread-macros.h
@@ -49,8 +49,8 @@
{ \
/* .__waiter_queue = */ {NULL, NULL}, \
/* .__futex = */ {0}, \
- /* .__shared = */ 0, \
- /*__is_realtime = */ 1, \
+ /* .__is_shared = */ 0, \
+ /* .__is_realtime = */ 1, \
/* .__padding = */ {0}, \
}
diff --git a/libc/include/llvm-libc-types/pthread_cond_t.h b/libc/include/llvm-libc-types/pthread_cond_t.h
index 77785d325f113..1466cac2e8303 100644
--- a/libc/include/llvm-libc-types/pthread_cond_t.h
+++ b/libc/include/llvm-libc-types/pthread_cond_t.h
@@ -18,7 +18,7 @@ typedef struct {
size_t __waiter_size;
};
__futex_word __futex;
- char __shared;
+ char __is_shared;
char __is_realtime;
char __padding[2];
} pthread_cond_t;
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index 2031bb1f14a0f..9b08c4c7394ff 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -217,9 +217,7 @@ add_entrypoint_object(
HDRS
pthread_cond_broadcast.h
DEPENDS
- libc.include.llvm-libc-types.pthread_cond_t
- libc.src.__support.macros.null_check
- libc.src.__support.threads.CndVar
+ .pthread_cond_utils
)
add_entrypoint_object(
@@ -244,8 +242,7 @@ add_entrypoint_object(
HDRS
pthread_cond_destroy.h
DEPENDS
- libc.include.llvm-libc-types.pthread_cond_t
- libc.src.__support.threads.CndVar
+ .pthread_cond_utils
)
add_entrypoint_object(
@@ -272,9 +269,7 @@ add_entrypoint_object(
HDRS
pthread_cond_signal.h
DEPENDS
- libc.include.llvm-libc-types.pthread_cond_t
- libc.src.__support.macros.null_check
- libc.src.__support.threads.CndVar
+ .pthread_cond_utils
)
add_entrypoint_object(
diff --git a/libc/src/pthread/pthread_cond_broadcast.cpp b/libc/src/pthread/pthread_cond_broadcast.cpp
index 7e56c43242fe2..f361c939a3b83 100644
--- a/libc/src/pthread/pthread_cond_broadcast.cpp
+++ b/libc/src/pthread/pthread_cond_broadcast.cpp
@@ -8,25 +8,15 @@
#include "pthread_cond_broadcast.h"
+#include "pthread_cond_utils.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"
namespace LIBC_NAMESPACE_DECL {
-static_assert(
- sizeof(CndVar) == sizeof(pthread_cond_t) &&
- alignof(CndVar) == alignof(pthread_cond_t),
- "The public pthread_cond_t type must be of the same size and alignment "
- "as the internal condition variable type.");
-
LLVM_LIBC_FUNCTION(int, pthread_cond_broadcast, (pthread_cond_t * cond)) {
- LIBC_CRASH_ON_NULLPTR(cond);
- // TODO: use cpp:start_lifetime_as once
- // https://github.com/llvm/llvm-project/pull/193326 is merged
- auto *cndvar = reinterpret_cast<CndVar *>(cond);
- cndvar->broadcast();
+ pthread_cond_utils::to_cndvar(cond)->broadcast();
return 0;
}
diff --git a/libc/src/pthread/pthread_cond_destroy.cpp b/libc/src/pthread/pthread_cond_destroy.cpp
index b35086e2bb096..98c35544572ce 100644
--- a/libc/src/pthread/pthread_cond_destroy.cpp
+++ b/libc/src/pthread/pthread_cond_destroy.cpp
@@ -8,23 +8,15 @@
#include "pthread_cond_destroy.h"
+#include "pthread_cond_utils.h"
+
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
-#include "src/__support/threads/CndVar.h"
namespace LIBC_NAMESPACE_DECL {
-static_assert(
- sizeof(CndVar) == sizeof(pthread_cond_t) &&
- alignof(CndVar) == alignof(pthread_cond_t),
- "The public pthread_cond_t type must be of the same size and alignment "
- "as the internal condition variable type.");
-
LLVM_LIBC_FUNCTION(int, pthread_cond_destroy, (pthread_cond_t * cond)) {
- // TODO: use cpp:start_lifetime_as once
- // https://github.com/llvm/llvm-project/pull/193326 is merged
- auto *cndvar = reinterpret_cast<CndVar *>(cond);
- cndvar->reset();
+ pthread_cond_utils::to_cndvar(cond)->reset();
return 0;
}
diff --git a/libc/src/pthread/pthread_cond_init.cpp b/libc/src/pthread/pthread_cond_init.cpp
index eac2ea505a935..2f0a4d13b5661 100644
--- a/libc/src/pthread/pthread_cond_init.cpp
+++ b/libc/src/pthread/pthread_cond_init.cpp
@@ -20,12 +20,6 @@
namespace LIBC_NAMESPACE_DECL {
-static_assert(
- sizeof(CndVar) == sizeof(pthread_cond_t) &&
- alignof(CndVar) == alignof(pthread_cond_t),
- "The public pthread_cond_t type must be of the same size and alignment "
- "as the internal condition variable type.");
-
LLVM_LIBC_FUNCTION(int, pthread_cond_init,
(pthread_cond_t *__restrict cond,
const pthread_condattr_t *__restrict attr)) {
diff --git a/libc/src/pthread/pthread_cond_signal.cpp b/libc/src/pthread/pthread_cond_signal.cpp
index 9244e85c48d5b..4e6a5a3e2b60f 100644
--- a/libc/src/pthread/pthread_cond_signal.cpp
+++ b/libc/src/pthread/pthread_cond_signal.cpp
@@ -8,25 +8,15 @@
#include "pthread_cond_signal.h"
+#include "pthread_cond_utils.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"
namespace LIBC_NAMESPACE_DECL {
-static_assert(
- sizeof(CndVar) == sizeof(pthread_cond_t) &&
- alignof(CndVar) == alignof(pthread_cond_t),
- "The public pthread_cond_t type must be of the same size and alignment "
- "as the internal condition variable type.");
-
LLVM_LIBC_FUNCTION(int, pthread_cond_signal, (pthread_cond_t * cond)) {
- LIBC_CRASH_ON_NULLPTR(cond);
- // TODO: use cpp:start_lifetime_as once
- // https://github.com/llvm/llvm-project/pull/193326 is merged
- auto *cndvar = reinterpret_cast<CndVar *>(cond);
- cndvar->notify_one();
+ pthread_cond_utils::to_cndvar(cond)->notify_one();
return 0;
}
diff --git a/libc/src/pthread/pthread_cond_utils.h b/libc/src/pthread/pthread_cond_utils.h
index a066f1cdd7ba6..1750f822d7312 100644
--- a/libc/src/pthread/pthread_cond_utils.h
+++ b/libc/src/pthread/pthread_cond_utils.h
@@ -45,9 +45,7 @@ LIBC_INLINE Mutex *to_mutex(pthread_mutex_t *mutex) {
// TODO: use cpp:start_lifetime_as once
// https://github.com/llvm/llvm-project/pull/193326 is merged
Mutex *m = reinterpret_cast<Mutex *>(mutex);
- // TODO: support robust mutex.
- if (m->is_robust())
- __builtin_trap();
+ LIBC_ASSERT(!m->is_robust() && "Robust mutex not supported yet");
return m;
}
>From 6fa4c42eb362f1aac9c096ac5b6f8d7cb7ce6b8d Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 23 Apr 2026 11:24:26 -0400
Subject: [PATCH 6/7] address reviews
---
libc/include/CMakeLists.txt | 2 +-
.../src/pthread/pthread_cond_test.cpp | 32 +++++++++++++++++++
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 575e5e11f92d8..1302c22f13fbf 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -462,7 +462,7 @@ add_header_macro(
.llvm-libc-types.pthread_t
.llvm-libc-types.struct_timespec
.llvm_libc_common_h
- )
+)
if(LIBC_TARGET_ARCHITECTURE STREQUAL "x86_64")
add_header_macro(
diff --git a/libc/test/integration/src/pthread/pthread_cond_test.cpp b/libc/test/integration/src/pthread/pthread_cond_test.cpp
index dec9b89c907d5..081b576f0a725 100644
--- a/libc/test/integration/src/pthread/pthread_cond_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_cond_test.cpp
@@ -217,10 +217,42 @@ template <bool UseBroadcast> static void run_shared_modes() {
run_timeout_modes<UseBroadcast, true>();
}
+void clockwait_returns_einval_for_invalid_clockid() {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&mutex, nullptr), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_init(&cond, nullptr), 0);
+
+ timespec ts{};
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_clockwait(&cond, &mutex, -1, &ts),
+ EINVAL);
+
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_destroy(&mutex), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_destroy(&cond), 0);
+}
+
+void initializer_act_the_same_as_null_attr() {
+ constexpr size_t EFFECTIVE_BYTES = sizeof(pthread_cond_t) - 2;
+ union {
+ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+ char cond_bytes[EFFECTIVE_BYTES];
+ };
+ union {
+ pthread_cond_t cond_from_init;
+ char cond_from_init_bytes[EFFECTIVE_BYTES];
+ };
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_init(&cond_from_init, nullptr), 0);
+ // Read as bytes is a defined behavior for trivial types.
+ for (size_t i = 0; i < EFFECTIVE_BYTES; ++i)
+ ASSERT_EQ(cond_bytes[i], cond_from_init_bytes[i]);
+}
+
} // namespace
TEST_MAIN() {
run_shared_modes<false>();
run_shared_modes<true>();
+ initializer_act_the_same_as_null_attr();
+ clockwait_returns_einval_for_invalid_clockid();
return 0;
}
>From 7d47550c6209a2ff1b02cfe270bab7c439c40b29 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 23 Apr 2026 11:29:33 -0400
Subject: [PATCH 7/7] fix braced initialization warning
---
libc/include/llvm-libc-macros/pthread-macros.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/include/llvm-libc-macros/pthread-macros.h b/libc/include/llvm-libc-macros/pthread-macros.h
index 5ac95be66310d..f513ef6f0ed50 100644
--- a/libc/include/llvm-libc-macros/pthread-macros.h
+++ b/libc/include/llvm-libc-macros/pthread-macros.h
@@ -48,7 +48,7 @@
#define PTHREAD_COND_INITIALIZER \
{ \
/* .__waiter_queue = */ {NULL, NULL}, \
- /* .__futex = */ {0}, \
+ /* .__futex = */ 0, \
/* .__is_shared = */ 0, \
/* .__is_realtime = */ 1, \
/* .__padding = */ {0}, \
More information about the libc-commits
mailing list