[libc-commits] [libc] [libcxx] [llvm] libcxx build test (PR #193840)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Thu Apr 23 20:54:17 PDT 2026


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/193840

>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 01/22] [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 02/22] 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 03/22] 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 04/22] 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 05/22] 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 06/22] 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 07/22] 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},                                                  \

>From 23737e3152b7dacd21c31ee8e22fa08a9cb5251a Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Thu, 23 Apr 2026 11:31:02 -0400
Subject: [PATCH 08/22] fix braced initialization warning (clang Wextra)

---
 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 f513ef6f0ed50..f2fa2e1e799e9 100644
--- a/libc/include/llvm-libc-macros/pthread-macros.h
+++ b/libc/include/llvm-libc-macros/pthread-macros.h
@@ -47,7 +47,7 @@
 
 #define PTHREAD_COND_INITIALIZER                                               \
   {                                                                            \
-      /* .__waiter_queue = */ {NULL, NULL},                                    \
+      /* .__waiter_queue = */ {{NULL, NULL}},                                  \
       /* .__futex = */ 0,                                                      \
       /* .__is_shared = */ 0,                                                  \
       /* .__is_realtime = */ 1,                                                \

>From 278778bc255fc833fe6d1b0d2525f952e9519bec Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 13:35:53 -0400
Subject: [PATCH 09/22] add entrypoints to aarch64 and riscv

---
 libc/config/linux/aarch64/entrypoints.txt | 7 +++++++
 libc/config/linux/riscv/entrypoints.txt   | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index a6c485f4473eb..b15edc5e3e102 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1001,6 +1001,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/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 3ceb5a6cf2d0e..6478aed3b0391 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1134,6 +1134,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

>From fb311b0fa201f98ddef3124f9208c77a9d371f6a Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 17:28:43 -0400
Subject: [PATCH 10/22] additional fix

---
 libc/config/linux/aarch64/entrypoints.txt     |   3 +
 libc/config/linux/x86_64/entrypoints.txt      |   3 +
 libc/src/link/CMakeLists.txt                  |   1 +
 libc/src/link/dl_iterate_phdr.cpp             | 131 +++++++++++++++++-
 libcxx/include/__cxx03/__thread/id.h          |  14 +-
 .../__cxx03/__thread/support/pthread.h        |  14 +-
 libcxx/include/__cxx03/__thread/thread.h      |   4 +-
 libcxx/include/__mbstate_t.h                  |   2 +
 libcxx/include/__thread/formatter.h           |   5 +-
 libcxx/include/__thread/id.h                  |  14 +-
 libcxx/include/__thread/support/pthread.h     |  14 +-
 libcxx/include/__thread/thread.h              |   2 +-
 runtimes/CMakeLists.txt                       |   9 ++
 13 files changed, 187 insertions(+), 29 deletions(-)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index b15edc5e3e102..79073faf08c40 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -108,6 +108,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.inttypes.strtoimax
     libc.src.inttypes.strtoumax
 
+    # link.h entrypoints
+    libc.src.link.dl_iterate_phdr
+
     # stdbit.h entrypoints
     libc.src.stdbit.stdc_bit_ceil_uc
     libc.src.stdbit.stdc_bit_ceil_ui
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 27569f0fae82b..cc2e74240dbe5 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -110,6 +110,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.inttypes.strtoimax
     libc.src.inttypes.strtoumax
 
+    # link.h entrypoints
+    libc.src.link.dl_iterate_phdr
+
     # stdbit.h entrypoints
     libc.src.stdbit.stdc_bit_ceil_uc
     libc.src.stdbit.stdc_bit_ceil_ui
diff --git a/libc/src/link/CMakeLists.txt b/libc/src/link/CMakeLists.txt
index 55f5edfab7d93..35fe9e87c74f2 100644
--- a/libc/src/link/CMakeLists.txt
+++ b/libc/src/link/CMakeLists.txt
@@ -5,5 +5,6 @@ add_entrypoint_object(
   HDRS
     dl_iterate_phdr.h
   DEPENDS
+    libc.src.__support.OSUtil.linux.auxv
     libc.hdr.stdint_proxy
 )
diff --git a/libc/src/link/dl_iterate_phdr.cpp b/libc/src/link/dl_iterate_phdr.cpp
index 7964411598d4a..7aa2be4f497f6 100644
--- a/libc/src/link/dl_iterate_phdr.cpp
+++ b/libc/src/link/dl_iterate_phdr.cpp
@@ -8,18 +8,141 @@
 
 #include "dl_iterate_phdr.h"
 
+#include "hdr/sys_auxv_macros.h"
+#include "src/__support/OSUtil/linux/auxv.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
 
+#include <elf.h>
+
+extern "C" {
+[[gnu::weak]] extern const char __ehdr_start;
+[[gnu::weak]] extern const char __executable_start;
+}
+
 namespace LIBC_NAMESPACE_DECL {
 
+namespace {
+
+LIBC_INLINE bool is_valid_elf(const ElfW(Ehdr) *ehdr) {
+  if (ehdr == nullptr)
+    return false;
+
+  return ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
+         ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
+         ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
+         ehdr->e_ident[EI_MAG3] == ELFMAG3;
+}
+
+LIBC_INLINE const ElfW(Ehdr) *get_executable_ehdr() {
+  const ElfW(Ehdr) *ehdr = nullptr;
+
+  if (&__ehdr_start != nullptr)
+    ehdr = reinterpret_cast<const ElfW(Ehdr) *>(&__ehdr_start);
+  else if (&__executable_start != nullptr)
+    ehdr = reinterpret_cast<const ElfW(Ehdr) *>(&__executable_start);
+
+  return is_valid_elf(ehdr) ? ehdr : nullptr;
+}
+
+LIBC_INLINE ElfW(Addr) get_executable_load_bias(const ElfW(Ehdr) *ehdr,
+                                                const ElfW(Phdr) *phdr_table,
+                                                ElfW(Half) phnum) {
+  if (phdr_table != nullptr) {
+    const uintptr_t runtime_phdr = reinterpret_cast<uintptr_t>(phdr_table);
+    for (ElfW(Half) i = 0; i < phnum; ++i) {
+      if (phdr_table[i].p_type == PT_PHDR)
+        return static_cast<ElfW(Addr)>(runtime_phdr - phdr_table[i].p_vaddr);
+    }
+  }
+
+  // For PIE binaries the ELF header is mapped at the load bias. ET_EXEC uses
+  // absolute virtual addresses, so report zero there.
+  if (ehdr != nullptr && ehdr->e_type == ET_DYN)
+    return reinterpret_cast<ElfW(Addr)>(ehdr);
+
+  return 0;
+}
+
+LIBC_INLINE int call_with_executable(__dl_iterate_phdr_callback_t callback,
+                                     void *arg) {
+  const ElfW(Ehdr) *ehdr = get_executable_ehdr();
+  if (ehdr == nullptr)
+    return -1;
+
+  cpp::optional<unsigned long> aux_phdr_val = auxv::get(AT_PHDR);
+  cpp::optional<unsigned long> aux_phnum_val = auxv::get(AT_PHNUM);
+  auto *aux_phdr = reinterpret_cast<const ElfW(Phdr) *>(
+      aux_phdr_val ? *aux_phdr_val : 0);
+  const auto aux_phnum = static_cast<ElfW(Half)>(aux_phnum_val ? *aux_phnum_val
+                                                               : 0);
+
+  const ElfW(Phdr) *phdr =
+      aux_phdr != nullptr ? aux_phdr
+                          : reinterpret_cast<const ElfW(Phdr) *>(
+                                reinterpret_cast<uintptr_t>(ehdr) + ehdr->e_phoff);
+  const ElfW(Half) phnum = aux_phnum != 0 ? aux_phnum : ehdr->e_phnum;
+
+  dl_phdr_info exe_info = {};
+  exe_info.dlpi_addr = get_executable_load_bias(ehdr, phdr, phnum);
+  exe_info.dlpi_name = nullptr;
+  exe_info.dlpi_phdr = phdr;
+  exe_info.dlpi_phnum = phnum;
+  exe_info.dlpi_adds = 0;
+  exe_info.dlpi_subs = 0;
+  exe_info.dlpi_tls_modid = 0;
+  exe_info.dlpi_tls_data = nullptr;
+  return callback(&exe_info, sizeof(exe_info), arg);
+}
+
+LIBC_INLINE int call_with_vdso(__dl_iterate_phdr_callback_t callback,
+                               void *arg) {
+  cpp::optional<unsigned long> aux_vdso = auxv::get(AT_SYSINFO_EHDR);
+  auto *ehdr_vdso =
+      reinterpret_cast<const ElfW(Ehdr) *>(aux_vdso ? *aux_vdso : 0);
+  if (!is_valid_elf(ehdr_vdso))
+    return 0;
+
+  auto *phdr = reinterpret_cast<const ElfW(Phdr) *>(
+      reinterpret_cast<uintptr_t>(ehdr_vdso) + ehdr_vdso->e_phoff);
+
+  dl_phdr_info vdso_info = {};
+  vdso_info.dlpi_name = nullptr;
+  vdso_info.dlpi_phdr = phdr;
+  vdso_info.dlpi_phnum = ehdr_vdso->e_phnum;
+  vdso_info.dlpi_adds = 0;
+  vdso_info.dlpi_subs = 0;
+  vdso_info.dlpi_tls_modid = 0;
+  vdso_info.dlpi_tls_data = nullptr;
+
+  for (ElfW(Half) i = 0; i < ehdr_vdso->e_phnum; ++i) {
+    if (phdr[i].p_type == PT_LOAD) {
+      vdso_info.dlpi_addr = reinterpret_cast<ElfW(Addr)>(ehdr_vdso) -
+                            static_cast<ElfW(Addr)>(phdr[i].p_vaddr);
+      break;
+    }
+  }
+
+  return callback(&vdso_info, sizeof(vdso_info), arg);
+}
+
+} // namespace
+
 LLVM_LIBC_FUNCTION(int, dl_iterate_phdr,
                    (__dl_iterate_phdr_callback_t callback, void *arg)) {
-  // FIXME: For pure static linking, this can report just the executable with
-  // info from __ehdr_start or AT_{PHDR,PHNUM} decoding, and its PT_TLS; and it
-  // could report the vDSO.
-  (void)callback, (void)arg;
+#if defined(LIBC_TARGET_ARCH_IS_X86_64) || defined(LIBC_TARGET_ARCH_IS_AARCH64)
+  if (callback == nullptr)
+    return -1;
+
+  int rc = call_with_executable(callback, arg);
+  if (rc != 0)
+    return rc;
+  return call_with_vdso(callback, arg);
+#else
+  (void)callback;
+  (void)arg;
   return 0;
+#endif
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libcxx/include/__cxx03/__thread/id.h b/libcxx/include/__cxx03/__thread/id.h
index 66b54c55d3146..44f926120b9bf 100644
--- a/libcxx/include/__cxx03/__thread/id.h
+++ b/libcxx/include/__cxx03/__thread/id.h
@@ -41,9 +41,9 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
 
   static _LIBCPP_HIDE_FROM_ABI bool
   __lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT { // id==0 is always less than any other thread_id
-    if (__x.__id_ == 0)
-      return __y.__id_ != 0;
-    if (__y.__id_ == 0)
+    if (__libcpp_thread_isnull(&__x.__id_))
+      return !__libcpp_thread_isnull(&__y.__id_);
+    if (__libcpp_thread_isnull(&__y.__id_))
       return false;
     return __libcpp_thread_id_less(__x.__id_, __y.__id_);
   }
@@ -51,7 +51,7 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
 public:
   _LIBCPP_HIDE_FROM_ABI __thread_id() _NOEXCEPT : __id_(0) {}
 
-  _LIBCPP_HIDE_FROM_ABI void __reset() { __id_ = 0; }
+  _LIBCPP_HIDE_FROM_ABI void __reset() { std::memset(&__id_, 0, sizeof(__libcpp_thread_id)); }
 
   friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT;
   friend _LIBCPP_HIDE_FROM_ABI bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT;
@@ -72,9 +72,9 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
 
 inline _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
   // Don't pass id==0 to underlying routines
-  if (__x.__id_ == 0)
-    return __y.__id_ == 0;
-  if (__y.__id_ == 0)
+  if (__libcpp_thread_isnull(&__x.__id_))
+    return __libcpp_thread_isnull(&__y.__id_);
+  if (__libcpp_thread_isnull(&__y.__id_))
     return false;
   return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
 }
diff --git a/libcxx/include/__cxx03/__thread/support/pthread.h b/libcxx/include/__cxx03/__thread/support/pthread.h
index 4ec5531003e02..b94b21c37a23e 100644
--- a/libcxx/include/__cxx03/__thread/support/pthread.h
+++ b/libcxx/include/__cxx03/__thread/support/pthread.h
@@ -152,12 +152,12 @@ typedef pthread_t __libcpp_thread_id;
 
 // Returns non-zero if the thread ids are equal, otherwise 0
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
-  return __t1 == __t2;
+  return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) == 0;
 }
 
 // Returns non-zero if t1 < t2, otherwise 0
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
-  return __t1 < __t2;
+  return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) < 0;
 }
 
 //
@@ -175,7 +175,15 @@ inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_id(const __l
 }
 
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) {
-  return __libcpp_thread_get_id(__t) == 0;
+  union {
+    char bytes[sizeof(__libcpp_thread_id)];
+    __libcpp_thread_id __id;
+  } u;
+  u.__id = __libcpp_thread_get_id(__t);
+  for (size_t i = 0; i < sizeof(__libcpp_thread_id); ++i)
+    if (u.bytes[i] != 0)
+      return false;
+  return true;
 }
 
 inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
diff --git a/libcxx/include/__cxx03/__thread/thread.h b/libcxx/include/__cxx03/__thread/thread.h
index f9a5ed45aea99..f88dd42af22f6 100644
--- a/libcxx/include/__cxx03/__thread/thread.h
+++ b/libcxx/include/__cxx03/__thread/thread.h
@@ -110,9 +110,9 @@ void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
 }
 
 template <>
-struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> : public __unary_function<__thread_id, size_t> {
+struct hash<__thread_id> : public __unary_function<__thread_id, size_t> {
   _LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT {
-    return hash<__libcpp_thread_id>()(__v.__id_);
+    return hash<__INTPTR_TYPE__>()(__builtin_bit_cast(__INTPTR_TYPE__, __v.__id_));
   }
 };
 
diff --git a/libcxx/include/__mbstate_t.h b/libcxx/include/__mbstate_t.h
index d331ba622d37f..d7ff5b8dd4adc 100644
--- a/libcxx/include/__mbstate_t.h
+++ b/libcxx/include/__mbstate_t.h
@@ -39,6 +39,8 @@
 #  define __NEED_mbstate_t
 #  include <bits/alltypes.h>
 #  undef __NEED_mbstate_t
+#elif __has_include(<llvm-libc-types/mbstate_t.h>)
+#  include <llvm-libc-types/mbstate_t.h>
 #elif __has_include(<bits/types/mbstate_t.h>)
 #  include <bits/types/mbstate_t.h> // works on most Unixes
 #elif __has_include(<sys/_types/_mbstate_t.h>)
diff --git a/libcxx/include/__thread/formatter.h b/libcxx/include/__thread/formatter.h
index 826607d47b469..1d35dfd7e80cf 100644
--- a/libcxx/include/__thread/formatter.h
+++ b/libcxx/include/__thread/formatter.h
@@ -58,14 +58,15 @@ struct formatter<__thread_id, _CharT> {
 
     using _Tp = decltype(__get_underlying_id(__id));
     using _Cp = conditional_t<integral<_Tp>, _Tp, conditional_t<is_pointer_v<_Tp>, uintptr_t, void>>;
-    static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
+    // static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
 
     __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
     if constexpr (is_pointer_v<_Tp>) {
       __specs.__std_.__alternate_form_ = true;
       __specs.__std_.__type_           = __format_spec::__type::__hexadecimal_lower_case;
     }
-    return __formatter::__format_integer(reinterpret_cast<_Cp>(__get_underlying_id(__id)), __ctx, __specs);
+    return __formatter::__format_integer(
+        __builtin_bit_cast(__INTPTR_TYPE__, __get_underlying_id(__id)), __ctx, __specs);
   }
 
   __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right};
diff --git a/libcxx/include/__thread/id.h b/libcxx/include/__thread/id.h
index 14a51fc9ee880..e04d2016670ef 100644
--- a/libcxx/include/__thread/id.h
+++ b/libcxx/include/__thread/id.h
@@ -42,9 +42,9 @@ class __thread_id {
 
   static _LIBCPP_HIDE_FROM_ABI bool
   __lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT { // id==0 is always less than any other thread_id
-    if (__x.__id_ == 0)
-      return __y.__id_ != 0;
-    if (__y.__id_ == 0)
+    if (__libcpp_thread_isnull(&__x.__id_))
+      return !__libcpp_thread_isnull(&__y.__id_);
+    if (__libcpp_thread_isnull(&__y.__id_))
       return false;
     return __libcpp_thread_id_less(__x.__id_, __y.__id_);
   }
@@ -52,7 +52,7 @@ class __thread_id {
 public:
   _LIBCPP_HIDE_FROM_ABI __thread_id() _NOEXCEPT : __id_(0) {}
 
-  _LIBCPP_HIDE_FROM_ABI void __reset() { __id_ = 0; }
+  _LIBCPP_HIDE_FROM_ABI void __reset() { std::memset(&__id_, 0, sizeof(__libcpp_thread_id)); }
 
   friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT;
 #  if _LIBCPP_STD_VER <= 17
@@ -77,9 +77,9 @@ class __thread_id {
 
 inline _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
   // Don't pass id==0 to underlying routines
-  if (__x.__id_ == 0)
-    return __y.__id_ == 0;
-  if (__y.__id_ == 0)
+  if (__libcpp_thread_isnull(&__x.__id_))
+    return __libcpp_thread_isnull(&__y.__id_);
+  if (__libcpp_thread_isnull(&__y.__id_))
     return false;
   return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
 }
diff --git a/libcxx/include/__thread/support/pthread.h b/libcxx/include/__thread/support/pthread.h
index 4cf5c0342467b..7478793a61a31 100644
--- a/libcxx/include/__thread/support/pthread.h
+++ b/libcxx/include/__thread/support/pthread.h
@@ -152,12 +152,12 @@ typedef pthread_t __libcpp_thread_id;
 
 // Returns non-zero if the thread ids are equal, otherwise 0
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
-  return __t1 == __t2;
+  return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) == 0;
 }
 
 // Returns non-zero if t1 < t2, otherwise 0
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
-  return __t1 < __t2;
+  return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) < 0;
 }
 
 //
@@ -175,7 +175,15 @@ inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_id(const __l
 }
 
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) {
-  return __libcpp_thread_get_id(__t) == 0;
+  union {
+    char bytes[sizeof(__libcpp_thread_id)];
+    __libcpp_thread_id __id;
+  } u;
+  u.__id = __libcpp_thread_get_id(__t);
+  for (size_t i = 0; i < sizeof(__libcpp_thread_id); ++i)
+    if (u.bytes[i] != 0)
+      return false;
+  return true;
 }
 
 inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
index b2f51aa816c10..efa99ddfcc0a8 100644
--- a/libcxx/include/__thread/thread.h
+++ b/libcxx/include/__thread/thread.h
@@ -123,7 +123,7 @@ void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
 template <>
 struct hash<__thread_id> : public __unary_function<__thread_id, size_t> {
   _LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT {
-    return hash<__libcpp_thread_id>()(__v.__id_);
+    return hash<__INTPTR_TYPE__>()(__builtin_bit_cast(__INTPTR_TYPE__, __v.__id_));
   }
 };
 
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 75551ba0c651a..61a43356694f3 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -59,6 +59,15 @@ foreach(proj ${LLVM_ENABLE_RUNTIMES})
   endif()
 endforeach()
 
+# The in-tree LLVM libc only provides a complete public C header set in
+# full-build mode. Consumers like libc++, libc++abi, and libunwind need those
+# headers to avoid falling back to the host libc in overlay mode.
+if(DEFINED RUNTIMES_USE_LIBC AND RUNTIMES_USE_LIBC STREQUAL "llvm-libc")
+  message(STATUS "Enabling LLVM_LIBC_FULL_BUILD because RUNTIMES_USE_LIBC=llvm-libc")
+  set(LLVM_LIBC_FULL_BUILD ON CACHE BOOL
+      "Build and test LLVM libc as if it is the full libc" FORCE)
+endif()
+
 function(runtime_register_component name)
   set_property(GLOBAL APPEND PROPERTY SUB_COMPONENTS ${name})
 endfunction()

>From 3f71821f529e1bbbbeed6d16d7eb7add1d43094a Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 17:53:13 -0400
Subject: [PATCH 11/22] more fixes

---
 libc/include/llvm-libc-types/__thread_type.h  |  4 +--
 libc/src/pthread/pthread_self.cpp             |  3 +-
 libc/src/threads/thrd_current.cpp             |  3 +-
 libcxx/include/__cxx03/__thread/id.h          | 14 ++++----
 .../__cxx03/__thread/support/pthread.h        | 14 ++------
 libcxx/include/__cxx03/__thread/thread.h      |  4 +--
 libcxx/include/__thread/formatter.h           |  5 ++-
 libcxx/include/__thread/id.h                  | 14 ++++----
 libcxx/include/__thread/support/pthread.h     | 14 ++------
 libcxx/include/__thread/thread.h              |  2 +-
 run.sh                                        | 33 +++++++++++++++++++
 11 files changed, 61 insertions(+), 49 deletions(-)
 create mode 100755 run.sh

diff --git a/libc/include/llvm-libc-types/__thread_type.h b/libc/include/llvm-libc-types/__thread_type.h
index 645573f544a99..e2f4829e9fd7f 100644
--- a/libc/include/llvm-libc-types/__thread_type.h
+++ b/libc/include/llvm-libc-types/__thread_type.h
@@ -9,8 +9,6 @@
 #ifndef LLVM_LIBC_TYPES___THREAD_TYPE_H
 #define LLVM_LIBC_TYPES___THREAD_TYPE_H
 
-typedef struct {
-  void *__attrib;
-} __thread_type;
+typedef void *__thread_type;
 
 #endif // LLVM_LIBC_TYPES___THREAD_TYPE_H
diff --git a/libc/src/pthread/pthread_self.cpp b/libc/src/pthread/pthread_self.cpp
index c3169ec1ca5c4..e810b033170cb 100644
--- a/libc/src/pthread/pthread_self.cpp
+++ b/libc/src/pthread/pthread_self.cpp
@@ -20,8 +20,7 @@ static_assert(sizeof(pthread_t) == sizeof(LIBC_NAMESPACE::Thread),
               "Mismatch between pthread_t and internal Thread.");
 
 LLVM_LIBC_FUNCTION(pthread_t, pthread_self, ()) {
-  pthread_t th;
-  th.__attrib = self.attrib;
+  pthread_t th = self.attrib;
   return th;
 }
 
diff --git a/libc/src/threads/thrd_current.cpp b/libc/src/threads/thrd_current.cpp
index 634159712b629..29a0de13ef85e 100644
--- a/libc/src/threads/thrd_current.cpp
+++ b/libc/src/threads/thrd_current.cpp
@@ -19,8 +19,7 @@ static_assert(sizeof(thrd_t) == sizeof(LIBC_NAMESPACE::Thread),
               "Mismatch between thrd_t and internal Thread.");
 
 LLVM_LIBC_FUNCTION(thrd_t, thrd_current, ()) {
-  thrd_t th;
-  th.__attrib = self.attrib;
+  thrd_t th = self.attrib;
   return th;
 }
 
diff --git a/libcxx/include/__cxx03/__thread/id.h b/libcxx/include/__cxx03/__thread/id.h
index 44f926120b9bf..66b54c55d3146 100644
--- a/libcxx/include/__cxx03/__thread/id.h
+++ b/libcxx/include/__cxx03/__thread/id.h
@@ -41,9 +41,9 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
 
   static _LIBCPP_HIDE_FROM_ABI bool
   __lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT { // id==0 is always less than any other thread_id
-    if (__libcpp_thread_isnull(&__x.__id_))
-      return !__libcpp_thread_isnull(&__y.__id_);
-    if (__libcpp_thread_isnull(&__y.__id_))
+    if (__x.__id_ == 0)
+      return __y.__id_ != 0;
+    if (__y.__id_ == 0)
       return false;
     return __libcpp_thread_id_less(__x.__id_, __y.__id_);
   }
@@ -51,7 +51,7 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
 public:
   _LIBCPP_HIDE_FROM_ABI __thread_id() _NOEXCEPT : __id_(0) {}
 
-  _LIBCPP_HIDE_FROM_ABI void __reset() { std::memset(&__id_, 0, sizeof(__libcpp_thread_id)); }
+  _LIBCPP_HIDE_FROM_ABI void __reset() { __id_ = 0; }
 
   friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT;
   friend _LIBCPP_HIDE_FROM_ABI bool operator<(__thread_id __x, __thread_id __y) _NOEXCEPT;
@@ -72,9 +72,9 @@ class _LIBCPP_TEMPLATE_VIS __thread_id {
 
 inline _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
   // Don't pass id==0 to underlying routines
-  if (__libcpp_thread_isnull(&__x.__id_))
-    return __libcpp_thread_isnull(&__y.__id_);
-  if (__libcpp_thread_isnull(&__y.__id_))
+  if (__x.__id_ == 0)
+    return __y.__id_ == 0;
+  if (__y.__id_ == 0)
     return false;
   return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
 }
diff --git a/libcxx/include/__cxx03/__thread/support/pthread.h b/libcxx/include/__cxx03/__thread/support/pthread.h
index b94b21c37a23e..4ec5531003e02 100644
--- a/libcxx/include/__cxx03/__thread/support/pthread.h
+++ b/libcxx/include/__cxx03/__thread/support/pthread.h
@@ -152,12 +152,12 @@ typedef pthread_t __libcpp_thread_id;
 
 // Returns non-zero if the thread ids are equal, otherwise 0
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
-  return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) == 0;
+  return __t1 == __t2;
 }
 
 // Returns non-zero if t1 < t2, otherwise 0
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
-  return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) < 0;
+  return __t1 < __t2;
 }
 
 //
@@ -175,15 +175,7 @@ inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_id(const __l
 }
 
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) {
-  union {
-    char bytes[sizeof(__libcpp_thread_id)];
-    __libcpp_thread_id __id;
-  } u;
-  u.__id = __libcpp_thread_get_id(__t);
-  for (size_t i = 0; i < sizeof(__libcpp_thread_id); ++i)
-    if (u.bytes[i] != 0)
-      return false;
-  return true;
+  return __libcpp_thread_get_id(__t) == 0;
 }
 
 inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
diff --git a/libcxx/include/__cxx03/__thread/thread.h b/libcxx/include/__cxx03/__thread/thread.h
index f88dd42af22f6..f9a5ed45aea99 100644
--- a/libcxx/include/__cxx03/__thread/thread.h
+++ b/libcxx/include/__cxx03/__thread/thread.h
@@ -110,9 +110,9 @@ void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
 }
 
 template <>
-struct hash<__thread_id> : public __unary_function<__thread_id, size_t> {
+struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> : public __unary_function<__thread_id, size_t> {
   _LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT {
-    return hash<__INTPTR_TYPE__>()(__builtin_bit_cast(__INTPTR_TYPE__, __v.__id_));
+    return hash<__libcpp_thread_id>()(__v.__id_);
   }
 };
 
diff --git a/libcxx/include/__thread/formatter.h b/libcxx/include/__thread/formatter.h
index 1d35dfd7e80cf..826607d47b469 100644
--- a/libcxx/include/__thread/formatter.h
+++ b/libcxx/include/__thread/formatter.h
@@ -58,15 +58,14 @@ struct formatter<__thread_id, _CharT> {
 
     using _Tp = decltype(__get_underlying_id(__id));
     using _Cp = conditional_t<integral<_Tp>, _Tp, conditional_t<is_pointer_v<_Tp>, uintptr_t, void>>;
-    // static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
+    static_assert(!is_same_v<_Cp, void>, "unsupported thread::id type, please file a bug report");
 
     __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx);
     if constexpr (is_pointer_v<_Tp>) {
       __specs.__std_.__alternate_form_ = true;
       __specs.__std_.__type_           = __format_spec::__type::__hexadecimal_lower_case;
     }
-    return __formatter::__format_integer(
-        __builtin_bit_cast(__INTPTR_TYPE__, __get_underlying_id(__id)), __ctx, __specs);
+    return __formatter::__format_integer(reinterpret_cast<_Cp>(__get_underlying_id(__id)), __ctx, __specs);
   }
 
   __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__right};
diff --git a/libcxx/include/__thread/id.h b/libcxx/include/__thread/id.h
index e04d2016670ef..14a51fc9ee880 100644
--- a/libcxx/include/__thread/id.h
+++ b/libcxx/include/__thread/id.h
@@ -42,9 +42,9 @@ class __thread_id {
 
   static _LIBCPP_HIDE_FROM_ABI bool
   __lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT { // id==0 is always less than any other thread_id
-    if (__libcpp_thread_isnull(&__x.__id_))
-      return !__libcpp_thread_isnull(&__y.__id_);
-    if (__libcpp_thread_isnull(&__y.__id_))
+    if (__x.__id_ == 0)
+      return __y.__id_ != 0;
+    if (__y.__id_ == 0)
       return false;
     return __libcpp_thread_id_less(__x.__id_, __y.__id_);
   }
@@ -52,7 +52,7 @@ class __thread_id {
 public:
   _LIBCPP_HIDE_FROM_ABI __thread_id() _NOEXCEPT : __id_(0) {}
 
-  _LIBCPP_HIDE_FROM_ABI void __reset() { std::memset(&__id_, 0, sizeof(__libcpp_thread_id)); }
+  _LIBCPP_HIDE_FROM_ABI void __reset() { __id_ = 0; }
 
   friend _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT;
 #  if _LIBCPP_STD_VER <= 17
@@ -77,9 +77,9 @@ class __thread_id {
 
 inline _LIBCPP_HIDE_FROM_ABI bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT {
   // Don't pass id==0 to underlying routines
-  if (__libcpp_thread_isnull(&__x.__id_))
-    return __libcpp_thread_isnull(&__y.__id_);
-  if (__libcpp_thread_isnull(&__y.__id_))
+  if (__x.__id_ == 0)
+    return __y.__id_ == 0;
+  if (__y.__id_ == 0)
     return false;
   return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
 }
diff --git a/libcxx/include/__thread/support/pthread.h b/libcxx/include/__thread/support/pthread.h
index 7478793a61a31..4cf5c0342467b 100644
--- a/libcxx/include/__thread/support/pthread.h
+++ b/libcxx/include/__thread/support/pthread.h
@@ -152,12 +152,12 @@ typedef pthread_t __libcpp_thread_id;
 
 // Returns non-zero if the thread ids are equal, otherwise 0
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_equal(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
-  return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) == 0;
+  return __t1 == __t2;
 }
 
 // Returns non-zero if t1 < t2, otherwise 0
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_id_less(__libcpp_thread_id __t1, __libcpp_thread_id __t2) {
-  return std::memcmp(&__t1, &__t2, sizeof(__libcpp_thread_id)) < 0;
+  return __t1 < __t2;
 }
 
 //
@@ -175,15 +175,7 @@ inline _LIBCPP_HIDE_FROM_ABI __libcpp_thread_id __libcpp_thread_get_id(const __l
 }
 
 inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_isnull(const __libcpp_thread_t* __t) {
-  union {
-    char bytes[sizeof(__libcpp_thread_id)];
-    __libcpp_thread_id __id;
-  } u;
-  u.__id = __libcpp_thread_get_id(__t);
-  for (size_t i = 0; i < sizeof(__libcpp_thread_id); ++i)
-    if (u.bytes[i] != 0)
-      return false;
-  return true;
+  return __libcpp_thread_get_id(__t) == 0;
 }
 
 inline _LIBCPP_HIDE_FROM_ABI int __libcpp_thread_create(__libcpp_thread_t* __t, void* (*__func)(void*), void* __arg) {
diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h
index efa99ddfcc0a8..b2f51aa816c10 100644
--- a/libcxx/include/__thread/thread.h
+++ b/libcxx/include/__thread/thread.h
@@ -123,7 +123,7 @@ void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) {
 template <>
 struct hash<__thread_id> : public __unary_function<__thread_id, size_t> {
   _LIBCPP_HIDE_FROM_ABI size_t operator()(__thread_id __v) const _NOEXCEPT {
-    return hash<__INTPTR_TYPE__>()(__builtin_bit_cast(__INTPTR_TYPE__, __v.__id_));
+    return hash<__libcpp_thread_id>()(__v.__id_);
   }
 };
 
diff --git a/run.sh b/run.sh
new file mode 100755
index 0000000000000..c61b75a141388
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+cd /home/schrodingerzy/Documents/llvm-project
+ninja -C build-libcxx-llvm libc/include/generate-libc-headers cxx-test-depends
+
+root="$(mktemp -d)"
+cleanup() {
+  rm -rf "$root"
+}
+trap cleanup EXIT
+
+mkdir -p "$root/usr/include" "$root/usr/local/include"
+
+# Preserve Linux UAPI headers without pulling in the full host C library headers.
+cp -a /usr/include/linux "$root/usr/include/"
+cp -a /usr/include/asm "$root/usr/include/"
+cp -a /usr/include/asm-generic "$root/usr/include/"
+
+# Overlay local libc and install headers so they win over the host copies.
+cp -a build-libcxx-llvm/libc/include/. "$root/usr/include/"
+cp -a build-libcxx-llvm/libcxx/test-suite-install/include/. "$root/usr/include/"
+
+bwrap \
+  --ro-bind / / \
+  --bind /home/schrodingerzy/Documents/llvm-project /home/schrodingerzy/Documents/llvm-project \
+  --dev-bind /dev /dev \
+  --proc /proc \
+  --tmpfs /tmp \
+  --chdir /home/schrodingerzy/Documents/llvm-project \
+  --ro-bind "$root/usr/local/include" /usr/local/include \
+  --ro-bind "$root/usr/include" /usr/include \
+  build-libcxx-llvm/bin/llvm-lit -sv -j8 build-libcxx-llvm/libcxx/test

>From 5b938c33098d669eab9b40a3229dec038e25c59c Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 20:54:29 -0400
Subject: [PATCH 12/22] update

---
 run.sh | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 186 insertions(+), 16 deletions(-)

diff --git a/run.sh b/run.sh
index c61b75a141388..ba6af7d55d7aa 100755
--- a/run.sh
+++ b/run.sh
@@ -1,33 +1,203 @@
 #!/usr/bin/env bash
 set -euo pipefail
 
-cd /home/schrodingerzy/Documents/llvm-project
-ninja -C build-libcxx-llvm libc/include/generate-libc-headers cxx-test-depends
+repo=/home/schrodingerzy/Documents/llvm-project
+build="$repo/build-libcxx-llvm"
+base_compiler=/usr/bin/clang++
+lit_jobs="${LIT_JOBS:-4}"
+
+cd "$repo"
+
+root="$(mktemp -d "$build/run-sandbox.XXXXXX")"
+launcher_shims="$root/shims"
+sysroot="$root/sysroot"
+wrapper="$root/clang++-llvm-libc"
+lit_wrapper="$root/llvm-lit-fork"
+empty_include="$root/empty-usr-local-include"
+fortify_shim_c="$root/fortify-shim.c"
+fortify_shim_o="$root/fortify-shim.o"
 
-root="$(mktemp -d)"
 cleanup() {
   rm -rf "$root"
 }
 trap cleanup EXIT
 
-mkdir -p "$root/usr/include" "$root/usr/local/include"
+mkdir -p "$launcher_shims"
+cat > "$launcher_shims/sccache" <<'EOF'
+#!/usr/bin/env bash
+exec "$@"
+EOF
+chmod +x "$launcher_shims/sccache"
+export PATH="$launcher_shims:$PATH"
+
+if (($# == 0)); then
+  targets=("$build/libcxx/test")
+else
+  targets=("$@")
+fi
+
+ninja -C "$build" \
+  libc/include/generate-libc-headers \
+  crt1.o \
+  libc.a \
+  libm.a \
+  lib/libunwind.a \
+  clang_rt.builtins-x86_64 \
+  cxx-test-depends
+
+mkdir -p "$sysroot/usr/include" "$empty_include"
+
+# Preserve Linux UAPI headers, but do not copy libc++ into /usr/include.
+cp -a /usr/include/linux "$sysroot/usr/include/"
+cp -a /usr/include/asm "$sysroot/usr/include/"
+cp -a /usr/include/asm-generic "$sysroot/usr/include/"
+cp -a "$build/libc/include/." "$sysroot/usr/include/"
+
+crtbegin="$("$base_compiler" --print-file-name=crtbeginT.o)"
+crtend="$("$base_compiler" --print-file-name=crtend.o)"
+builtins="$build/compiler-rt/lib/linux/libclang_rt.builtins-x86_64.a"
+
+cat > "$fortify_shim_c" <<'EOF'
+typedef __SIZE_TYPE__ size_t;
+
+__attribute__((noreturn)) static void __llvm_libcxx_test_chk_fail(void) {
+  __builtin_trap();
+}
+
+static void *__llvm_libcxx_test_memcpy(void *dst, const void *src, size_t len) {
+  unsigned char *out = (unsigned char *)dst;
+  const unsigned char *in = (const unsigned char *)src;
+  for (size_t i = 0; i < len; ++i)
+    out[i] = in[i];
+  return dst;
+}
+
+static void *__llvm_libcxx_test_memmove(void *dst, const void *src, size_t len) {
+  unsigned char *out = (unsigned char *)dst;
+  const unsigned char *in = (const unsigned char *)src;
+  if (out == in || len == 0)
+    return dst;
+  if (out < in || out >= in + len) {
+    for (size_t i = 0; i < len; ++i)
+      out[i] = in[i];
+  } else {
+    for (size_t i = len; i != 0; --i)
+      out[i - 1] = in[i - 1];
+  }
+  return dst;
+}
+
+static void *__llvm_libcxx_test_memset(void *dst, int value, size_t len) {
+  unsigned char *out = (unsigned char *)dst;
+  unsigned char byte = (unsigned char)value;
+  for (size_t i = 0; i < len; ++i)
+    out[i] = byte;
+  return dst;
+}
+
+void *__memcpy_chk(void *dst, const void *src, size_t len, size_t dstlen) {
+  if (len > dstlen)
+    __llvm_libcxx_test_chk_fail();
+  return __llvm_libcxx_test_memcpy(dst, src, len);
+}
+
+void *__memmove_chk(void *dst, const void *src, size_t len, size_t dstlen) {
+  if (len > dstlen)
+    __llvm_libcxx_test_chk_fail();
+  return __llvm_libcxx_test_memmove(dst, src, len);
+}
+
+void *__memset_chk(void *dst, int value, size_t len, size_t dstlen) {
+  if (len > dstlen)
+    __llvm_libcxx_test_chk_fail();
+  return __llvm_libcxx_test_memset(dst, value, len);
+}
+EOF
+
+"$base_compiler" \
+  -c \
+  -x c \
+  -fno-stack-protector \
+  -ffreestanding \
+  "$fortify_shim_c" \
+  -o "$fortify_shim_o"
+
+cat > "$wrapper" <<EOF
+#!/usr/bin/env bash
+set -euo pipefail
+
+base_compiler=$base_compiler
+sysroot=$sysroot
+repo=$repo
+build=$build
+crtbegin=$crtbegin
+crtend=$crtend
+builtins=$builtins
+fortify_shim_o=$fortify_shim_o
+
+linking=1
+for arg in "\$@"; do
+  case "\$arg" in
+    -c|-E|-S|-fsyntax-only|-emit-ast)
+      linking=0
+      ;;
+  esac
+done
+
+common_args=(
+  -nostdlibinc
+  -isystem "\$sysroot/usr/include"
+  -fno-stack-protector
+  -Wno-missing-braces
+)
+
+if (( linking )); then
+  exec "\$base_compiler" \
+    "\$@" \
+    "\${common_args[@]}" \
+    -nodefaultlibs \
+    -nostartfiles \
+    -static \
+    "$build/libc/startup/linux/crt1.o" \
+    "\$crtbegin" \
+    -L "$build/libc/lib" \
+    -lunwind \
+    -lc \
+    -lm \
+    "\$fortify_shim_o" \
+    "\$builtins" \
+    "\$crtend"
+else
+  exec "\$base_compiler" "\$@" "\${common_args[@]}"
+fi
+EOF
+
+chmod +x "$wrapper"
+
+cat > "$lit_wrapper" <<EOF
+#!/usr/bin/env python3
+import multiprocessing as mp
+import runpy
+import sys
 
-# Preserve Linux UAPI headers without pulling in the full host C library headers.
-cp -a /usr/include/linux "$root/usr/include/"
-cp -a /usr/include/asm "$root/usr/include/"
-cp -a /usr/include/asm-generic "$root/usr/include/"
+mp.set_start_method("fork")
+sys.argv[0] = "$build/bin/llvm-lit"
+runpy.run_path("$build/bin/llvm-lit", run_name="__main__")
+EOF
 
-# Overlay local libc and install headers so they win over the host copies.
-cp -a build-libcxx-llvm/libc/include/. "$root/usr/include/"
-cp -a build-libcxx-llvm/libcxx/test-suite-install/include/. "$root/usr/include/"
+chmod +x "$lit_wrapper"
 
 bwrap \
   --ro-bind / / \
-  --bind /home/schrodingerzy/Documents/llvm-project /home/schrodingerzy/Documents/llvm-project \
+  --bind "$repo" "$repo" \
   --dev-bind /dev /dev \
   --proc /proc \
   --tmpfs /tmp \
-  --chdir /home/schrodingerzy/Documents/llvm-project \
-  --ro-bind "$root/usr/local/include" /usr/local/include \
-  --ro-bind "$root/usr/include" /usr/include \
-  build-libcxx-llvm/bin/llvm-lit -sv -j8 build-libcxx-llvm/libcxx/test
+  --chdir "$repo" \
+  --ro-bind "$sysroot/usr/include" /usr/include \
+  --ro-bind "$empty_include" /usr/local/include \
+  "$lit_wrapper" \
+  -sv \
+  "-j$lit_jobs" \
+  --param "compiler=$wrapper" \
+  "${targets[@]}"

>From 5e97cfb9eeb5424b3160b2ac6b5aa6aef2116bb1 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:31:26 -0400
Subject: [PATCH 13/22] update

---
 run.sh | 30 +++++++++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/run.sh b/run.sh
index ba6af7d55d7aa..1d72520f4d2ee 100755
--- a/run.sh
+++ b/run.sh
@@ -1,13 +1,37 @@
 #!/usr/bin/env bash
 set -euo pipefail
 
-repo=/home/schrodingerzy/Documents/llvm-project
-build="$repo/build-libcxx-llvm"
-base_compiler=/usr/bin/clang++
+repo="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
+build="${BUILD_DIR:-$repo/build-libcxx-llvm}"
+base_c_compiler="${CC:-/usr/bin/clang}"
+base_compiler="${CXX:-/usr/bin/clang++}"
 lit_jobs="${LIT_JOBS:-4}"
 
 cd "$repo"
 
+if [[ ! -f "$build/CMakeCache.txt" ]]; then
+  mkdir -p "$build"
+  cmake \
+    -S "$repo/runtimes" \
+    -B "$build" \
+    -G Ninja \
+    -DCMAKE_BUILD_TYPE=Release \
+    -DCMAKE_C_COMPILER="$base_c_compiler" \
+    -DCMAKE_CXX_COMPILER="$base_compiler" \
+    -DCMAKE_C_COMPILER_LAUNCHER= \
+    -DCMAKE_CXX_COMPILER_LAUNCHER= \
+    -DLIBCXX_ENABLE_FILESYSTEM=OFF \
+    -DLIBCXX_ENABLE_WIDE_CHARACTERS=OFF \
+    -DLLVM_LIBC_INCLUDE_SCUDO=ON \
+    -DCOMPILER_RT_BUILD_SCUDO_STANDALONE_WITH_LLVM_LIBC=ON \
+    -DCOMPILER_RT_BUILD_GWP_ASAN=OFF \
+    -DCOMPILER_RT_SCUDO_STANDALONE_BUILD_SHARED=OFF \
+    -DRUNTIMES_USE_LIBC=llvm-libc \
+    -DLLVM_ENABLE_RUNTIMES="libc;compiler-rt;libunwind;libcxxabi;libcxx" \
+    -DLIBCXX_INCLUDE_TESTS=ON \
+    -DLIBCXX_INCLUDE_BENCHMARKS=OFF
+fi
+
 root="$(mktemp -d "$build/run-sandbox.XXXXXX")"
 launcher_shims="$root/shims"
 sysroot="$root/sysroot"

>From 6e4a1ef74f826410a99481e26a6f138b772e7bc5 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:37:27 -0400
Subject: [PATCH 14/22] update

---
 run.sh | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/run.sh b/run.sh
index 1d72520f4d2ee..81fbc98195c60 100755
--- a/run.sh
+++ b/run.sh
@@ -6,6 +6,19 @@ build="${BUILD_DIR:-$repo/build-libcxx-llvm}"
 base_c_compiler="${CC:-/usr/bin/clang}"
 base_compiler="${CXX:-/usr/bin/clang++}"
 lit_jobs="${LIT_JOBS:-4}"
+host_arch="$(uname -m)"
+
+case "$host_arch" in
+  x86_64)
+    compiler_rt_arch=x86_64
+    ;;
+  aarch64|arm64)
+    compiler_rt_arch=aarch64
+    ;;
+  *)
+    compiler_rt_arch="$host_arch"
+    ;;
+esac
 
 cd "$repo"
 
@@ -32,6 +45,21 @@ if [[ ! -f "$build/CMakeCache.txt" ]]; then
     -DLIBCXX_INCLUDE_BENCHMARKS=OFF
 fi
 
+builtins_target="clang_rt.builtins-$compiler_rt_arch"
+builtins="$build/compiler-rt/lib/linux/libclang_rt.builtins-$compiler_rt_arch.a"
+if [[ ! -f "$builtins" ]]; then
+  builtins="$(find "$build/compiler-rt/lib" -name "libclang_rt.builtins-$compiler_rt_arch.a" -print -quit)"
+fi
+if [[ -z "${builtins:-}" || ! -f "$builtins" ]]; then
+  builtins="$(find "$build/compiler-rt/lib" -name 'libclang_rt.builtins-*.a' -print -quit)"
+  if [[ -z "${builtins:-}" ]]; then
+    echo "unable to locate compiler-rt builtins archive under $build/compiler-rt/lib" >&2
+    exit 1
+  fi
+  builtins_target="$(basename "$builtins" .a)"
+  builtins_target="${builtins_target#lib}"
+fi
+
 root="$(mktemp -d "$build/run-sandbox.XXXXXX")"
 launcher_shims="$root/shims"
 sysroot="$root/sysroot"
@@ -66,7 +94,7 @@ ninja -C "$build" \
   libc.a \
   libm.a \
   lib/libunwind.a \
-  clang_rt.builtins-x86_64 \
+  "$builtins_target" \
   cxx-test-depends
 
 mkdir -p "$sysroot/usr/include" "$empty_include"
@@ -79,7 +107,6 @@ cp -a "$build/libc/include/." "$sysroot/usr/include/"
 
 crtbegin="$("$base_compiler" --print-file-name=crtbeginT.o)"
 crtend="$("$base_compiler" --print-file-name=crtend.o)"
-builtins="$build/compiler-rt/lib/linux/libclang_rt.builtins-x86_64.a"
 
 cat > "$fortify_shim_c" <<'EOF'
 typedef __SIZE_TYPE__ size_t;

>From bfc45e5333fddc8cb34e9a71aefb6e61c0b3008a Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:39:18 -0400
Subject: [PATCH 15/22] update

---
 run.sh | 34 +++++++++++++++++++++++-----------
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/run.sh b/run.sh
index 81fbc98195c60..1bb52e3dede78 100755
--- a/run.sh
+++ b/run.sh
@@ -46,18 +46,18 @@ if [[ ! -f "$build/CMakeCache.txt" ]]; then
 fi
 
 builtins_target="clang_rt.builtins-$compiler_rt_arch"
-builtins="$build/compiler-rt/lib/linux/libclang_rt.builtins-$compiler_rt_arch.a"
-if [[ ! -f "$builtins" ]]; then
-  builtins="$(find "$build/compiler-rt/lib" -name "libclang_rt.builtins-$compiler_rt_arch.a" -print -quit)"
-fi
-if [[ -z "${builtins:-}" || ! -f "$builtins" ]]; then
-  builtins="$(find "$build/compiler-rt/lib" -name 'libclang_rt.builtins-*.a' -print -quit)"
-  if [[ -z "${builtins:-}" ]]; then
-    echo "unable to locate compiler-rt builtins archive under $build/compiler-rt/lib" >&2
-    exit 1
+builtins_target_candidates="$(ninja -C "$build" -t targets all | sed -n 's/:.*//; /^clang_rt\.builtins-/p; /^libclang_rt\.builtins-.*\.a$/p')"
+if ! grep -qx "$builtins_target" <<<"$builtins_target_candidates"; then
+  alt_target="libclang_rt.builtins-$compiler_rt_arch.a"
+  if grep -qx "$alt_target" <<<"$builtins_target_candidates"; then
+    builtins_target="$alt_target"
+  else
+    builtins_target="$(head -n 1 <<<"$builtins_target_candidates")"
+    if [[ -z "$builtins_target" ]]; then
+      echo "unable to locate a compiler-rt builtins target in $build" >&2
+      exit 1
+    fi
   fi
-  builtins_target="$(basename "$builtins" .a)"
-  builtins_target="${builtins_target#lib}"
 fi
 
 root="$(mktemp -d "$build/run-sandbox.XXXXXX")"
@@ -97,6 +97,18 @@ ninja -C "$build" \
   "$builtins_target" \
   cxx-test-depends
 
+builtins="$build/compiler-rt/lib/linux/libclang_rt.builtins-$compiler_rt_arch.a"
+if [[ ! -f "$builtins" ]]; then
+  builtins="$(find "$build/compiler-rt/lib" -name "libclang_rt.builtins-$compiler_rt_arch.a" -print -quit)"
+fi
+if [[ -z "${builtins:-}" || ! -f "$builtins" ]]; then
+  builtins="$(find "$build/compiler-rt/lib" -name 'libclang_rt.builtins-*.a' -print -quit)"
+  if [[ -z "${builtins:-}" ]]; then
+    echo "unable to locate compiler-rt builtins archive under $build/compiler-rt/lib" >&2
+    exit 1
+  fi
+fi
+
 mkdir -p "$sysroot/usr/include" "$empty_include"
 
 # Preserve Linux UAPI headers, but do not copy libc++ into /usr/include.

>From 5def5591aa795c35fbc0a2aa23262e011e8ed71c Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:42:53 -0400
Subject: [PATCH 16/22] update

---
 libc/config/linux/aarch64/entrypoints.txt | 1 +
 libc/config/linux/riscv/entrypoints.txt   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 79073faf08c40..c23d1214c6e6a 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -18,6 +18,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.ctype.toupper
 
     # dlfcn.h entrypoints
+    libc.src.dlfcn.dladdr
     libc.src.dlfcn.dlclose
     libc.src.dlfcn.dlerror
     libc.src.dlfcn.dlopen
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 6478aed3b0391..ff82dd479665a 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -18,6 +18,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.ctype.toupper
 
     # dlfcn.h entrypoints
+    libc.src.dlfcn.dladdr
     libc.src.dlfcn.dlclose
     libc.src.dlfcn.dlerror
     libc.src.dlfcn.dlopen

>From d982822212b2dac5026b4cfc9dbd27880ca7004c Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:45:02 -0400
Subject: [PATCH 17/22] update

---
 run.sh | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/run.sh b/run.sh
index 1bb52e3dede78..ba3a44812353a 100755
--- a/run.sh
+++ b/run.sh
@@ -33,6 +33,14 @@ if [[ ! -f "$build/CMakeCache.txt" ]]; then
     -DCMAKE_CXX_COMPILER="$base_compiler" \
     -DCMAKE_C_COMPILER_LAUNCHER= \
     -DCMAKE_CXX_COMPILER_LAUNCHER= \
+    -DLIBUNWIND_ENABLE_SHARED=OFF \
+    -DLIBUNWIND_ENABLE_STATIC=ON \
+    -DLIBCXXABI_ENABLE_SHARED=OFF \
+    -DLIBCXXABI_ENABLE_STATIC=ON \
+    -DLIBCXXABI_ENABLE_STATIC_UNWINDER=ON \
+    -DLIBCXX_ENABLE_SHARED=OFF \
+    -DLIBCXX_ENABLE_STATIC=ON \
+    -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \
     -DLIBCXX_ENABLE_FILESYSTEM=OFF \
     -DLIBCXX_ENABLE_WIDE_CHARACTERS=OFF \
     -DLLVM_LIBC_INCLUDE_SCUDO=ON \

>From d3ded092f6f896bb33ff8a1ce81a576837105afc Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:53:16 -0400
Subject: [PATCH 18/22] update

---
 libc/config/linux/aarch64/entrypoints.txt | 307 +++++++++++++++++++---
 1 file changed, 269 insertions(+), 38 deletions(-)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index c23d1214c6e6a..cc2e74240dbe5 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -37,6 +37,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.poll.poll
 
     # sched.h entrypoints
+    libc.src.sched.getcpu
     libc.src.sched.sched_get_priority_max
     libc.src.sched.sched_get_priority_min
     libc.src.sched.sched_getaffinity
@@ -185,6 +186,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdbit.stdc_trailing_zeros_us
 
     # stdlib.h entrypoints
+    libc.src.stdlib.a64l
     libc.src.stdlib.abs
     libc.src.stdlib.atof
     libc.src.stdlib.atoi
@@ -192,6 +194,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.atoll
     libc.src.stdlib.bsearch
     libc.src.stdlib.div
+    libc.src.stdlib.l64a
     libc.src.stdlib.labs
     libc.src.stdlib.ldiv
     libc.src.stdlib.llabs
@@ -203,8 +206,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.srand
     libc.src.stdlib.strfromd
     libc.src.stdlib.strfromf
-    # TODO: long double support is buggy with clang-11. Re-enable when buildbots are upgraded.
-    # libc.src.stdlib.strfroml
+    libc.src.stdlib.strfroml
     libc.src.stdlib.strtod
     libc.src.stdlib.strtof
     libc.src.stdlib.strtol
@@ -257,6 +259,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # sys/ioctl.h entrypoints
     libc.src.sys.ioctl.ioctl
 
+    # sys/ipc.h entrypoints
+    libc.src.sys.ipc.ftok
+
     # sys/mman.h entrypoints
     libc.src.sys.mman.madvise
     libc.src.sys.mman.mincore
@@ -270,6 +275,11 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.mman.munlock
     libc.src.sys.mman.munlockall
     libc.src.sys.mman.munmap
+    libc.src.sys.mman.pkey_alloc
+    libc.src.sys.mman.pkey_free
+    libc.src.sys.mman.pkey_get
+    libc.src.sys.mman.pkey_mprotect
+    libc.src.sys.mman.pkey_set
     libc.src.sys.mman.remap_file_pages
     libc.src.sys.mman.posix_madvise
     libc.src.sys.mman.shm_open
@@ -282,6 +292,11 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.resource.getrlimit
     libc.src.sys.resource.setrlimit
 
+    # sys/sem.h entrypoints
+    libc.src.sys.sem.semget
+    libc.src.sys.sem.semctl
+    libc.src.sys.sem.semop
+
     # sys/sendfile entrypoints
     libc.src.sys.sendfile.sendfile
 
@@ -300,6 +315,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.statvfs.fstatvfs
     libc.src.sys.statvfs.statvfs
 
+    # sys/time.h entrypoints
+    libc.src.sys.time.utimes
+
     # sys/utsname.h entrypoints
     libc.src.sys.utsname.uname
 
@@ -330,6 +348,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     # unistd.h entrypoints
     libc.src.unistd.access
     libc.src.unistd.chdir
+    libc.src.unistd.chown
     libc.src.unistd.close
     libc.src.unistd.dup
     libc.src.unistd.dup2
@@ -350,6 +369,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.unistd.getppid
     libc.src.unistd.getsid
     libc.src.unistd.gettid
+    libc.src.unistd.getgid
     libc.src.unistd.getuid
     libc.src.unistd.isatty
     libc.src.unistd.link
@@ -374,8 +394,42 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.unistd.write
 
     # wchar.h entrypoints
+    libc.src.wchar.btowc
     libc.src.wchar.wcslen
+    libc.src.wchar.wcsnlen
     libc.src.wchar.wctob
+    libc.src.wchar.wmemmove
+    libc.src.wchar.wmemset
+    libc.src.wchar.wcschr
+    libc.src.wchar.wcsncmp
+    libc.src.wchar.wcsxfrm
+    libc.src.wchar.wcscmp
+    libc.src.wchar.wcspbrk
+    libc.src.wchar.wcsrchr
+    libc.src.wchar.wcsspn
+    libc.src.wchar.wcscspn
+    libc.src.wchar.wcsdup
+    libc.src.wchar.wmemcmp
+    libc.src.wchar.wmempcpy
+    libc.src.wchar.wmemcpy
+    libc.src.wchar.wcsncpy
+    libc.src.wchar.wcscat
+    libc.src.wchar.wcsstr
+    libc.src.wchar.wcsncat
+    libc.src.wchar.wcslcat
+    libc.src.wchar.wcscpy
+    libc.src.wchar.wcslcpy
+    libc.src.wchar.wmemchr
+    libc.src.wchar.wcpcpy
+    libc.src.wchar.wcpncpy
+    libc.src.wchar.wcstod
+    libc.src.wchar.wcstof
+    libc.src.wchar.wcstok
+    libc.src.wchar.wcstol
+    libc.src.wchar.wcstold
+    libc.src.wchar.wcstoll
+    libc.src.wchar.wcstoul
+    libc.src.wchar.wcstoull
 
     # wctype.h entrypoints
     libc.src.wctype.iswalpha
@@ -473,16 +527,17 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.cosf
     libc.src.math.coshf
     libc.src.math.cospif
-    libc.src.math.daddl
-    libc.src.math.ddivl
     libc.src.math.dfmal
     libc.src.math.dmull
     libc.src.math.dsqrtl
+    libc.src.math.daddl
+    libc.src.math.ddivl
     libc.src.math.dsubl
     libc.src.math.erff
     libc.src.math.exp
     libc.src.math.exp10
     libc.src.math.exp10f
+    libc.src.math.exp10m1f
     libc.src.math.exp2
     libc.src.math.exp2f
     libc.src.math.exp2m1f
@@ -498,6 +553,10 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.fdim
     libc.src.math.fdimf
     libc.src.math.fdiml
+    libc.src.math.fdiv
+    libc.src.math.fdivl
+    libc.src.math.ffma
+    libc.src.math.ffmal
     libc.src.math.floor
     libc.src.math.floorf
     libc.src.math.floorl
@@ -691,40 +750,50 @@ endif()
 if(LIBC_TYPES_HAS_FLOAT16)
   list(APPEND TARGET_LIBM_ENTRYPOINTS
     # math.h C23 _Float16 entrypoints
+    libc.src.math.acosf16
     libc.src.math.acoshf16
+    libc.src.math.acospif16
+    libc.src.math.asinf16
+    libc.src.math.asinhf16
     libc.src.math.asinpif16
+    libc.src.math.atanf16
     libc.src.math.atan2f16
+    libc.src.math.atanhf16
+    libc.src.math.atanpif16
     libc.src.math.canonicalizef16
     libc.src.math.ceilf16
     libc.src.math.copysignf16
+    libc.src.math.cosf16
+    libc.src.math.coshf16
     libc.src.math.cospif16
     libc.src.math.erff16
     libc.src.math.erfcf16
+    libc.src.math.exp10f16
+    libc.src.math.exp10m1f16
+    libc.src.math.exp2f16
+    libc.src.math.exp2m1f16
     libc.src.math.expf16
+    libc.src.math.expm1f16
     libc.src.math.f16add
     libc.src.math.f16addf
-    # libc.src.math.f16addl
+    libc.src.math.f16addl
     libc.src.math.f16div
     libc.src.math.f16divf
-    # libc.src.math.f16divl
+    libc.src.math.f16divl
     libc.src.math.f16fma
     libc.src.math.f16fmaf
-    # libc.src.math.f16fmal
+    libc.src.math.f16fmal
     libc.src.math.f16mul
     libc.src.math.f16mulf
-    # libc.src.math.f16mull
+    libc.src.math.f16mull
     libc.src.math.f16sqrt
     libc.src.math.f16sqrtf
-    # libc.src.math.f16sqrtl
+    libc.src.math.f16sqrtl
     libc.src.math.f16sub
     libc.src.math.f16subf
-    # libc.src.math.f16subl
+    libc.src.math.f16subl
     libc.src.math.fabsf16
     libc.src.math.fdimf16
-    libc.src.math.fdiv
-    libc.src.math.fdivl
-    libc.src.math.ffma
-    libc.src.math.ffmal
     libc.src.math.floorf16
     libc.src.math.fmaf16
     libc.src.math.fmaxf16
@@ -737,11 +806,12 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.fminimum_magf16
     libc.src.math.fminimum_numf16
     libc.src.math.fminimumf16
-    # libc.src.math.fmodf16
+    libc.src.math.fmodf16
     libc.src.math.frexpf16
     libc.src.math.fromfpf16
     libc.src.math.fromfpxf16
     libc.src.math.getpayloadf16
+    libc.src.math.hypotf16
     libc.src.math.ilogbf16
     libc.src.math.iscanonicalf16
     libc.src.math.issignalingf16
@@ -749,20 +819,20 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.llogbf16
     libc.src.math.llrintf16
     libc.src.math.llroundf16
+    libc.src.math.log10f16
     libc.src.math.log10p1f16
+    libc.src.math.log2f16
     libc.src.math.log2p1f16
     libc.src.math.logbf16
+    libc.src.math.logf16
     libc.src.math.lrintf16
     libc.src.math.lroundf16
-    # libc.src.math.modff16
+    libc.src.math.modff16
     libc.src.math.nanf16
     libc.src.math.nearbyintf16
     libc.src.math.nextafterf16
     libc.src.math.nextdownf16
-    # Temporarily disable nexttowardf16 on aarch64 because the conversion
-    # between _Float16 and long double will crash clang-11.  This is fixed in
-    # clang-12 and after: https://godbolt.org/z/8ceT9454c
-    # libc.src.math.nexttowardf16
+    libc.src.math.nexttowardf16
     libc.src.math.nextupf16
     libc.src.math.remainderf16
     libc.src.math.remquof16
@@ -775,8 +845,13 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.scalbnf16
     libc.src.math.setpayloadf16
     libc.src.math.setpayloadsigf16
+    libc.src.math.sinf16
+    libc.src.math.sinhf16
     libc.src.math.sinpif16
     libc.src.math.sqrtf16
+    libc.src.math.tanf16
+    libc.src.math.tanhf16
+    libc.src.math.tanpif16
     libc.src.math.totalorderf16
     libc.src.math.totalordermagf16
     libc.src.math.truncf16
@@ -784,17 +859,17 @@ if(LIBC_TYPES_HAS_FLOAT16)
     libc.src.math.ufromfpxf16
   )
 
-  # if(LIBC_TYPES_HAS_FLOAT128)
-  #   list(APPEND TARGET_LIBM_ENTRYPOINTS
-  #     # math.h C23 mixed _Float16 and _Float128 entrypoints
-  #     libc.src.math.f16addf128
-  #     libc.src.math.f16divf128
-  #     libc.src.math.f16fmaf128
-  #     libc.src.math.f16mulf128
-  #     libc.src.math.f16sqrtf128
-  #     libc.src.math.f16subf128
-  #   )
-  # endif()
+  if(LIBC_TYPES_HAS_FLOAT128)
+    list(APPEND TARGET_LIBM_ENTRYPOINTS
+      # math.h C23 mixed _Float16 and _Float128 entrypoints
+      libc.src.math.f16addf128
+      libc.src.math.f16divf128
+      libc.src.math.f16fmaf128
+      libc.src.math.f16mulf128
+      libc.src.math.f16sqrtf128
+      libc.src.math.f16subf128
+    )
+  endif()
 endif()
 
 if(LIBC_TYPES_HAS_CFLOAT128)
@@ -811,6 +886,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
   list(APPEND TARGET_LIBM_ENTRYPOINTS
     # math.h C23 _Float128 entrypoints
     libc.src.math.atan2f128
+    libc.src.math.atan2l
     libc.src.math.canonicalizef128
     libc.src.math.ceilf128
     libc.src.math.copysignf128
@@ -965,8 +1041,120 @@ if(LIBC_TYPES_HAS_FLOAT128)
   )
 endif()
 
+if(LIBC_COMPILER_HAS_FIXED_POINT)
+  list(APPEND TARGET_LIBM_ENTRYPOINTS
+    # stdfix.h _Fract and _Accum entrypoints
+    libc.src.stdfix.abshk
+    libc.src.stdfix.abshr
+    libc.src.stdfix.absk
+    libc.src.stdfix.abslk
+    libc.src.stdfix.abslr
+    libc.src.stdfix.absr
+    libc.src.stdfix.exphk
+    libc.src.stdfix.expk
+    libc.src.stdfix.roundhk
+    libc.src.stdfix.roundhr
+    libc.src.stdfix.roundk
+    libc.src.stdfix.roundlk
+    libc.src.stdfix.roundlr
+    libc.src.stdfix.roundr
+    libc.src.stdfix.rounduhk
+    libc.src.stdfix.rounduhr
+    libc.src.stdfix.rounduk
+    libc.src.stdfix.roundulk
+    libc.src.stdfix.roundulr
+    libc.src.stdfix.roundur
+    libc.src.stdfix.sqrtuhk
+    libc.src.stdfix.sqrtuhr
+    libc.src.stdfix.sqrtuk
+    libc.src.stdfix.sqrtur
+    # libc.src.stdfix.sqrtulk
+    libc.src.stdfix.sqrtulr
+    libc.src.stdfix.uhksqrtus
+    libc.src.stdfix.uksqrtui
+    libc.src.stdfix.hrbits
+    libc.src.stdfix.uhrbits
+    libc.src.stdfix.rbits
+    libc.src.stdfix.urbits
+    libc.src.stdfix.lrbits
+    libc.src.stdfix.ulrbits
+    libc.src.stdfix.hkbits
+    libc.src.stdfix.uhkbits
+    libc.src.stdfix.kbits
+    libc.src.stdfix.ukbits
+    libc.src.stdfix.lkbits
+    libc.src.stdfix.ulkbits
+    libc.src.stdfix.bitshr
+    libc.src.stdfix.bitsr
+    libc.src.stdfix.bitslr
+    libc.src.stdfix.bitshk
+    libc.src.stdfix.bitsk
+    libc.src.stdfix.bitslk
+    libc.src.stdfix.bitsuhr
+    libc.src.stdfix.bitsur
+    libc.src.stdfix.bitsulr
+    libc.src.stdfix.bitsuhk
+    libc.src.stdfix.bitsuk
+    libc.src.stdfix.bitsulk
+    libc.src.stdfix.countlshr
+    libc.src.stdfix.countlsr
+    libc.src.stdfix.countlslr
+    libc.src.stdfix.countlshk
+    libc.src.stdfix.countlsk
+    libc.src.stdfix.countlslk
+    libc.src.stdfix.countlsuhr
+    libc.src.stdfix.countlsur
+    libc.src.stdfix.countlsulr
+    libc.src.stdfix.countlsuhk
+    libc.src.stdfix.countlsuk
+    libc.src.stdfix.countlsulk
+    libc.src.stdfix.idivr
+    libc.src.stdfix.idivlr
+    libc.src.stdfix.idivk
+    libc.src.stdfix.idivlk
+    libc.src.stdfix.idivur
+    libc.src.stdfix.idivulr
+    libc.src.stdfix.idivuk
+    libc.src.stdfix.idivulk
+    libc.src.stdfix.rdivi
+  )
+endif()
+
 if(LLVM_LIBC_FULL_BUILD)
   list(APPEND TARGET_LIBC_ENTRYPOINTS
+    # ctype.h entrypoints
+    libc.src.ctype.isalnum_l
+    libc.src.ctype.isalpha_l
+    libc.src.ctype.isblank_l
+    libc.src.ctype.iscntrl_l
+    libc.src.ctype.isdigit_l
+    libc.src.ctype.isgraph_l
+    libc.src.ctype.islower_l
+    libc.src.ctype.isprint_l
+    libc.src.ctype.ispunct_l
+    libc.src.ctype.isspace_l
+    libc.src.ctype.isupper_l
+    libc.src.ctype.isxdigit_l
+    libc.src.ctype.tolower_l
+    libc.src.ctype.toupper_l
+
+    # stdlib.h entrypoints
+    libc.src.stdlib.strtod_l
+    libc.src.stdlib.strtof_l
+    libc.src.stdlib.strtol_l
+    libc.src.stdlib.strtold_l
+    libc.src.stdlib.strtoll_l
+    libc.src.stdlib.strtoul_l
+    libc.src.stdlib.strtoull_l
+
+    # string.h entrypoints
+    libc.src.string.strcoll_l
+    libc.src.string.strxfrm_l
+
+    # strings.h entrypoints
+    libc.src.strings.strcasecmp_l
+    libc.src.strings.strncasecmp_l
+
     # assert.h entrypoints
     libc.src.assert.__assert_fail
 
@@ -1021,6 +1209,9 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_join
     libc.src.pthread.pthread_key_create
     libc.src.pthread.pthread_key_delete
+    libc.src.pthread.pthread_barrier_init
+    libc.src.pthread.pthread_barrier_wait
+    libc.src.pthread.pthread_barrier_destroy
     libc.src.pthread.pthread_mutex_destroy
     libc.src.pthread.pthread_mutex_init
     libc.src.pthread.pthread_mutex_lock
@@ -1067,16 +1258,16 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.sched.__sched_setcpuset
     libc.src.sched.__sched_getcpuisset
 
-    # strings.h entrypoints
-    libc.src.strings.strcasecmp_l
-    libc.src.strings.strncasecmp_l
-
     # setjmp.h entrypoints
     libc.src.setjmp.longjmp
     libc.src.setjmp.setjmp
     libc.src.setjmp.siglongjmp
     libc.src.setjmp.sigsetjmp
 
+    # ucontext.h entrypoints
+    libc.src.ucontext.getcontext
+    libc.src.ucontext.setcontext
+
     # stdio.h entrypoints
     libc.src.stdio.clearerr
     libc.src.stdio.clearerr_unlocked
@@ -1128,7 +1319,11 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.stdlib.atexit
     libc.src.stdlib.exit
     libc.src.stdlib.getenv
+    libc.src.stdlib.mbstowcs
+    libc.src.stdlib.mbtowc
     libc.src.stdlib.quick_exit
+    libc.src.stdlib.wcstombs
+    libc.src.stdlib.wctomb
 
     # signal.h entrypoints
     libc.src.signal.kill
@@ -1202,11 +1397,24 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.time.gettimeofday
     libc.src.time.gmtime
     libc.src.time.gmtime_r
+    libc.src.time.localtime
+    libc.src.time.localtime_r
     libc.src.time.mktime
     libc.src.time.nanosleep
+    libc.src.time.strftime
+    libc.src.time.strftime_l
     libc.src.time.time
     libc.src.time.timespec_get
 
+    # locale.h entrypoints
+    libc.src.locale.localeconv
+    libc.src.locale.duplocale
+    libc.src.locale.freelocale
+    libc.src.locale.localeconv
+    libc.src.locale.newlocale
+    libc.src.locale.setlocale
+    libc.src.locale.uselocale
+
     # unistd.h entrypoints
     libc.src.unistd.__llvm_libc_syscall
     libc.src.unistd._exit
@@ -1226,20 +1434,43 @@ if(LLVM_LIBC_FULL_BUILD)
     # sys/socket.h entrypoints
     libc.src.sys.socket.accept
     libc.src.sys.socket.accept4
+    libc.src.sys.socket.socket
     libc.src.sys.socket.bind
     libc.src.sys.socket.connect
     libc.src.sys.socket.getsockopt
     libc.src.sys.socket.listen
-    libc.src.sys.socket.setsockopt
     libc.src.sys.socket.shutdown
-    libc.src.sys.socket.socket
+    libc.src.sys.socket.socketpair
+    libc.src.sys.socket.setsockopt
+    libc.src.sys.socket.send
+    libc.src.sys.socket.sendto
+    libc.src.sys.socket.sendmsg
+    libc.src.sys.socket.recv
+    libc.src.sys.socket.recvfrom
+    libc.src.sys.socket.recvmsg
+
+    # wchar.h entrypoints
+    libc.src.wchar.mblen
+    libc.src.wchar.mbrlen
+    libc.src.wchar.mbsinit
+    libc.src.wchar.mbrtowc
+    libc.src.wchar.mbsrtowcs
+    libc.src.wchar.mbsnrtowcs
+    libc.src.wchar.wcrtomb
+    libc.src.wchar.wcsrtombs
+    libc.src.wchar.wcsnrtombs
+
+    # nl_types.h entrypoints
+    libc.src.nl_types.catopen 
+    libc.src.nl_types.catclose
+    libc.src.nl_types.catgets
   )
 endif()
 
 set(TARGET_LIBMVEC_ENTRYPOINTS)
 
 if(LIBC_COMPILER_HAS_EXT_VECTOR_TYPE)
-  list(APPEND TARGET_LIBMVEC_ENTRYPOINTS
+list(APPEND TARGET_LIBMVEC_ENTRYPOINTS
     libc.src.mathvec.expf
   )
 endif()

>From 5f84b26afaa5037e2bdd90365a8ac98f0145a3ea Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 21:55:19 -0400
Subject: [PATCH 19/22] update

---
 libc/config/linux/aarch64/entrypoints.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index cc2e74240dbe5..27d948aa89536 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1265,8 +1265,8 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.setjmp.sigsetjmp
 
     # ucontext.h entrypoints
-    libc.src.ucontext.getcontext
-    libc.src.ucontext.setcontext
+    #libc.src.ucontext.getcontext
+    #libc.src.ucontext.setcontext
 
     # stdio.h entrypoints
     libc.src.stdio.clearerr

>From 64b5d6dfe73354030446f734c1cac90945c8eb43 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 22:00:57 -0400
Subject: [PATCH 20/22] update

---
 libc/config/linux/aarch64/headers.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index 4784fc5d29ddc..0e5d5c753aed1 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -20,6 +20,7 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.malloc
     libc.include.math
     libc.include.netinet_in
+    libc.include.nl_types
     libc.include.poll
     libc.include.pthread
     libc.include.sched
@@ -38,12 +39,14 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.sys_auxv
     libc.include.sys_epoll
     libc.include.sys_ioctl
+    libc.include.sys_ipc
     libc.include.sys_mman
     libc.include.sys_prctl
     libc.include.sys_queue
     libc.include.sys_random
     libc.include.sys_resource
     libc.include.sys_select
+    libc.include.sys_sem
     libc.include.sys_socket
     libc.include.sys_stat
     libc.include.sys_statvfs

>From e193162a33fff4dc0f9dec832b1ad18fe4409dc8 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 22:13:51 -0400
Subject: [PATCH 21/22] update

---
 run.sh | 44 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 41 insertions(+), 3 deletions(-)

diff --git a/run.sh b/run.sh
index ba3a44812353a..764d1a1bc976b 100755
--- a/run.sh
+++ b/run.sh
@@ -7,6 +7,9 @@ base_c_compiler="${CC:-/usr/bin/clang}"
 base_compiler="${CXX:-/usr/bin/clang++}"
 lit_jobs="${LIT_JOBS:-4}"
 host_arch="$(uname -m)"
+multiarch_triple=""
+configure_c_flags="${CFLAGS:-}"
+configure_cxx_flags="${CXXFLAGS:-}"
 
 case "$host_arch" in
   x86_64)
@@ -22,6 +25,22 @@ esac
 
 cd "$repo"
 
+for candidate in \
+  "$("$base_c_compiler" -print-multiarch 2>/dev/null || true)" \
+  "$("$base_compiler" -print-multiarch 2>/dev/null || true)" \
+  "$("$base_c_compiler" -dumpmachine 2>/dev/null || true)" \
+  "$("$base_compiler" -dumpmachine 2>/dev/null || true)"; do
+  if [[ -n "$candidate" && -d "/usr/include/$candidate" ]]; then
+    multiarch_triple="$candidate"
+    break
+  fi
+done
+
+if [[ -n "$multiarch_triple" ]]; then
+  configure_c_flags="${configure_c_flags:+$configure_c_flags }-idirafter/usr/include/$multiarch_triple"
+  configure_cxx_flags="${configure_cxx_flags:+$configure_cxx_flags }-idirafter/usr/include/$multiarch_triple"
+fi
+
 if [[ ! -f "$build/CMakeCache.txt" ]]; then
   mkdir -p "$build"
   cmake \
@@ -31,6 +50,8 @@ if [[ ! -f "$build/CMakeCache.txt" ]]; then
     -DCMAKE_BUILD_TYPE=Release \
     -DCMAKE_C_COMPILER="$base_c_compiler" \
     -DCMAKE_CXX_COMPILER="$base_compiler" \
+    -DCMAKE_C_FLAGS="$configure_c_flags" \
+    -DCMAKE_CXX_FLAGS="$configure_cxx_flags" \
     -DCMAKE_C_COMPILER_LAUNCHER= \
     -DCMAKE_CXX_COMPILER_LAUNCHER= \
     -DLIBUNWIND_ENABLE_SHARED=OFF \
@@ -76,6 +97,7 @@ lit_wrapper="$root/llvm-lit-fork"
 empty_include="$root/empty-usr-local-include"
 fortify_shim_c="$root/fortify-shim.c"
 fortify_shim_o="$root/fortify-shim.o"
+multiarch_include_dir=""
 
 cleanup() {
   rm -rf "$root"
@@ -120,9 +142,21 @@ fi
 mkdir -p "$sysroot/usr/include" "$empty_include"
 
 # Preserve Linux UAPI headers, but do not copy libc++ into /usr/include.
-cp -a /usr/include/linux "$sysroot/usr/include/"
-cp -a /usr/include/asm "$sysroot/usr/include/"
-cp -a /usr/include/asm-generic "$sysroot/usr/include/"
+if [[ -d /usr/include/linux ]]; then
+  cp -a /usr/include/linux "$sysroot/usr/include/"
+fi
+if [[ -d /usr/include/asm-generic ]]; then
+  cp -a /usr/include/asm-generic "$sysroot/usr/include/"
+fi
+if [[ -n "$multiarch_triple" ]]; then
+  multiarch_include_dir="$sysroot/usr/include/$multiarch_triple"
+  mkdir -p "$multiarch_include_dir"
+fi
+if [[ -d /usr/include/asm ]]; then
+  cp -a /usr/include/asm "${multiarch_include_dir:-$sysroot/usr/include}/"
+elif [[ -n "$multiarch_triple" && -d "/usr/include/$multiarch_triple/asm" ]]; then
+  cp -a "/usr/include/$multiarch_triple/asm" "$multiarch_include_dir/"
+fi
 cp -a "$build/libc/include/." "$sysroot/usr/include/"
 
 crtbegin="$("$base_compiler" --print-file-name=crtbeginT.o)"
@@ -205,6 +239,7 @@ crtbegin=$crtbegin
 crtend=$crtend
 builtins=$builtins
 fortify_shim_o=$fortify_shim_o
+multiarch_include_dir=$multiarch_include_dir
 
 linking=1
 for arg in "\$@"; do
@@ -221,6 +256,9 @@ common_args=(
   -fno-stack-protector
   -Wno-missing-braces
 )
+if [[ -n "\$multiarch_include_dir" ]]; then
+  common_args+=(-isystem "\$multiarch_include_dir")
+fi
 
 if (( linking )); then
   exec "\$base_compiler" \

>From 141bfe7f0d5ef1423e6e286e6f6b3013191090c6 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Thu, 23 Apr 2026 23:53:53 -0400
Subject: [PATCH 22/22] update

---
 run.sh | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/run.sh b/run.sh
index 764d1a1bc976b..846b0c6121747 100755
--- a/run.sh
+++ b/run.sh
@@ -26,6 +26,14 @@ esac
 cd "$repo"
 
 for candidate in \
+  "$(
+    case "$host_arch" in
+      x86_64) echo x86_64-linux-gnu ;;
+      aarch64|arm64) echo aarch64-linux-gnu ;;
+      riscv64) echo riscv64-linux-gnu ;;
+      *) ;;
+    esac
+  )" \
   "$("$base_c_compiler" -print-multiarch 2>/dev/null || true)" \
   "$("$base_compiler" -print-multiarch 2>/dev/null || true)" \
   "$("$base_c_compiler" -dumpmachine 2>/dev/null || true)" \
@@ -36,6 +44,10 @@ for candidate in \
   fi
 done
 
+if [[ -z "$multiarch_triple" ]]; then
+  multiarch_triple="$(find /usr/include -mindepth 1 -maxdepth 1 -type d -name '*-linux-gnu' -exec test -d '{}/asm' ';' -print -quit | xargs -r basename)"
+fi
+
 if [[ -n "$multiarch_triple" ]]; then
   configure_c_flags="${configure_c_flags:+$configure_c_flags }-idirafter/usr/include/$multiarch_triple"
   configure_cxx_flags="${configure_cxx_flags:+$configure_cxx_flags }-idirafter/usr/include/$multiarch_triple"
@@ -98,6 +110,7 @@ empty_include="$root/empty-usr-local-include"
 fortify_shim_c="$root/fortify-shim.c"
 fortify_shim_o="$root/fortify-shim.o"
 multiarch_include_dir=""
+asm_source_dir=""
 
 cleanup() {
   rm -rf "$root"
@@ -152,10 +165,14 @@ if [[ -n "$multiarch_triple" ]]; then
   multiarch_include_dir="$sysroot/usr/include/$multiarch_triple"
   mkdir -p "$multiarch_include_dir"
 fi
-if [[ -d /usr/include/asm ]]; then
-  cp -a /usr/include/asm "${multiarch_include_dir:-$sysroot/usr/include}/"
-elif [[ -n "$multiarch_triple" && -d "/usr/include/$multiarch_triple/asm" ]]; then
-  cp -a "/usr/include/$multiarch_triple/asm" "$multiarch_include_dir/"
+if [[ -n "$multiarch_triple" && -d "/usr/include/$multiarch_triple/asm" ]]; then
+  asm_source_dir="$(readlink -f "/usr/include/$multiarch_triple/asm")"
+elif [[ -d /usr/include/asm ]]; then
+  asm_source_dir="$(readlink -f /usr/include/asm)"
+fi
+if [[ -n "$asm_source_dir" ]]; then
+  mkdir -p "${multiarch_include_dir:-$sysroot/usr/include}/asm"
+  cp -a "$asm_source_dir/." "${multiarch_include_dir:-$sysroot/usr/include}/asm/"
 fi
 cp -a "$build/libc/include/." "$sysroot/usr/include/"
 



More information about the libc-commits mailing list