[libc-commits] [libc] [libc] Implement barriers for pthreads (PR #148948)
Uzair Nawaz via libc-commits
libc-commits at lists.llvm.org
Tue Jul 22 14:46:45 PDT 2025
https://github.com/uzairnawaz updated https://github.com/llvm/llvm-project/pull/148948
>From 2d5b880393cbd430f088da8146a41f68d490c6dc Mon Sep 17 00:00:00 2001
From: Uzair Nawaz <uzairnawaz at google.com>
Date: Thu, 10 Jul 2025 21:01:39 +0000
Subject: [PATCH 01/10] Barrier class implemented; begin work on public
functions
---
libc/include/llvm-libc-types/CMakeLists.txt | 2 +
.../llvm-libc-types/pthread_barrier_t.h | 16 +++++
.../llvm-libc-types/pthread_barrierattr_t.h | 16 +++++
libc/src/__support/threads/barrier.cpp | 70 +++++++++++++++++++
libc/src/__support/threads/barrier.h | 39 +++++++++++
libc/src/pthread/pthread_barrier_destroy.cpp | 24 +++++++
libc/src/pthread/pthread_barrier_destroy.h | 21 ++++++
libc/src/pthread/pthread_barrier_init.cpp | 32 +++++++++
libc/src/pthread/pthread_barrier_init.h | 23 ++++++
libc/src/pthread/pthread_barrier_wait.cpp | 27 +++++++
libc/src/pthread/pthread_barrier_wait.h | 21 ++++++
.../src/pthread/pthread_barrier_test.cpp | 35 ++++++++++
12 files changed, 326 insertions(+)
create mode 100644 libc/include/llvm-libc-types/pthread_barrier_t.h
create mode 100644 libc/include/llvm-libc-types/pthread_barrierattr_t.h
create mode 100644 libc/src/__support/threads/barrier.cpp
create mode 100644 libc/src/__support/threads/barrier.h
create mode 100644 libc/src/pthread/pthread_barrier_destroy.cpp
create mode 100644 libc/src/pthread/pthread_barrier_destroy.h
create mode 100644 libc/src/pthread/pthread_barrier_init.cpp
create mode 100644 libc/src/pthread/pthread_barrier_init.h
create mode 100644 libc/src/pthread/pthread_barrier_wait.cpp
create mode 100644 libc/src/pthread/pthread_barrier_wait.h
create mode 100644 libc/test/integration/src/pthread/pthread_barrier_test.cpp
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index b24c97301668a..405c2cd26b863 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -53,6 +53,8 @@ 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)
add_header(pthread_mutexattr_t HDR pthread_mutexattr_t.h)
+add_header(pthread_barrier_t HDR pthread_barrier_t.h)
+add_header(pthread_barrierattr_t HDR pthread_barrierattr_t.h)
add_header(pthread_once_t HDR pthread_once_t.h DEPENDS .__futex_word)
add_header(pthread_rwlock_t HDR pthread_rwlock_t.h DEPENDS .__futex_word .pid_t)
add_header(pthread_rwlockattr_t HDR pthread_rwlockattr_t.h)
diff --git a/libc/include/llvm-libc-types/pthread_barrier_t.h b/libc/include/llvm-libc-types/pthread_barrier_t.h
new file mode 100644
index 0000000000000..d95477afb226c
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_barrier_t.h
@@ -0,0 +1,16 @@
+//===-- Definition of pthread_barrier_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_BARRIER_T_H
+#define LLVM_LIBC_TYPES_PTHREAD_BARRIER_T_H
+
+typedef struct {
+ char padding[88];
+} pthread_barrier_t;
+
+#endif // LLVM_LIBC_TYPES_PTHREAD_BARRIER_T_H
diff --git a/libc/include/llvm-libc-types/pthread_barrierattr_t.h b/libc/include/llvm-libc-types/pthread_barrierattr_t.h
new file mode 100644
index 0000000000000..064be5bfb6721
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_barrierattr_t.h
@@ -0,0 +1,16 @@
+//===-- Definition of pthread_barrierattr_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_BARRIERATTR_T_H
+#define LLVM_LIBC_TYPES_PTHREAD_BARRIERATTR_T_H
+
+typedef struct {
+ bool pshared;
+} pthread_barrierattr_t;
+
+#endif // LLVM_LIBC_TYPES_PTHREAD_BARRIERATTR_T_H
diff --git a/libc/src/__support/threads/barrier.cpp b/libc/src/__support/threads/barrier.cpp
new file mode 100644
index 0000000000000..db0e38e9eb71e
--- /dev/null
+++ b/libc/src/__support/threads/barrier.cpp
@@ -0,0 +1,70 @@
+//===-- Linux implementation of the callonce function ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/threads/barrier.h"
+#include "src/__support/threads/mutex.h"
+#include "hdr/errno_macros.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int Barrier::init(Barrier *b, const pthread_barrierattr_t* attr, unsigned count) {
+ if (count == 0)
+ return EINVAL;
+
+ b->expected = count;
+ b->waiting = 0;
+ b->blocking = true;
+
+ int err;
+ err = CndVar::init(&b->entering);
+ if (err != 0)
+ return err;
+
+ err = CndVar::init(&b->exiting);
+ if (err != 0)
+ return err;
+
+ Mutex::init(&b->m, false, false, false, false);
+ return 0;
+}
+
+int Barrier::wait() {
+ m.lock();
+
+ // if the barrier is emptying out threads, wait until it finishes
+ while (!blocking) {
+ entering.wait(&m);
+ }
+ waiting++;
+
+ if (waiting == expected) {
+ // this is the last thread to call wait(), so lets wake everyone up
+ blocking = false;
+ waiting--;
+ exiting.broadcast();
+ } else {
+ // block threads until waiting = expected
+ while (blocking) {
+ exiting.wait(&m);
+ }
+ }
+
+ // all threads have exited the barrier, lets let the ones waiting to enter
+ // continue
+ if (waiting == 0) {
+ blocking = true;
+ entering.broadcast();
+ }
+ m.unlock();
+}
+
+int Barrier::destroy(Barrier *b) {
+
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/threads/barrier.h b/libc/src/__support/threads/barrier.h
new file mode 100644
index 0000000000000..e46d5b9773a4f
--- /dev/null
+++ b/libc/src/__support/threads/barrier.h
@@ -0,0 +1,39 @@
+//===-- A platform independent abstraction layer for barriers --*- 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___SUPPORT_SRC_THREADS_LINUX_BARRIER_H
+#define LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_BARRIER_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/CndVar.h"
+#include "src/__support/threads/mutex.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// NOTE: if the size of this class changes, you must ensure that the size of
+// pthread_barrier_t (found in include/llvm-libc/types/pthread_barrier_t.h) is
+// the same size
+
+class Barrier {
+private:
+ unsigned expected;
+ unsigned waiting;
+ bool blocking;
+ CndVar entering;
+ CndVar exiting;
+ Mutex m;
+
+public:
+ static int init(Barrier *b, const pthread_barrierattr_t* attr, unsigned count);
+ static int destroy(Barrier *b);
+ int wait();
+};
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_BARRIER_H
diff --git a/libc/src/pthread/pthread_barrier_destroy.cpp b/libc/src/pthread/pthread_barrier_destroy.cpp
new file mode 100644
index 0000000000000..00863f8d6ff6b
--- /dev/null
+++ b/libc/src/pthread/pthread_barrier_destroy.cpp
@@ -0,0 +1,24 @@
+//===-- Linux implementation of the pthread_barrier_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_mutex_init.h"
+#include "pthread_mutexattr.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/barrier.h"
+
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pthread_barrier_destroy, (pthread_barrier_t * b)) {
+ return Barrier::destroy(reinterpret_cast<Barrier *>(b));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_barrier_destroy.h b/libc/src/pthread/pthread_barrier_destroy.h
new file mode 100644
index 0000000000000..0b1d0f090ec26
--- /dev/null
+++ b/libc/src/pthread/pthread_barrier_destroy.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pthread_barrier_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_BARRIER_DESTROY_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_DESTROY_H
+
+#include "src/__support/macros/config.h"
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_barrier_destroy(pthread_barrier_t *b);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_DESTROY_H
diff --git a/libc/src/pthread/pthread_barrier_init.cpp b/libc/src/pthread/pthread_barrier_init.cpp
new file mode 100644
index 0000000000000..234f58a6c7d62
--- /dev/null
+++ b/libc/src/pthread/pthread_barrier_init.cpp
@@ -0,0 +1,32 @@
+//===-- Linux implementation of the pthread_barrier_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_mutex_init.h"
+#include "pthread_mutexattr.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/barrier.h"
+
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(
+ sizeof(Barrier) <= sizeof(pthread_barrier_t),
+ "The public pthread_barrier_t type cannot accommodate the internal "
+ "barrier type.");
+
+LLVM_LIBC_FUNCTION(int, pthread_barrier_init,
+ (pthread_barrier_t * b,
+ const pthread_barrierattr_t *__restrict attr,
+ unsigned count)) {
+ return Barrier::init(reinterpret_cast<Barrier *>(b), attr, count);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_barrier_init.h b/libc/src/pthread/pthread_barrier_init.h
new file mode 100644
index 0000000000000..ea79df6da7ea9
--- /dev/null
+++ b/libc/src/pthread/pthread_barrier_init.h
@@ -0,0 +1,23 @@
+//===-- Implementation header for pthread_barrier_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_BARRIER_INIT_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_INIT_H
+
+#include "src/__support/macros/config.h"
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_barrier_init(pthread_barrier_t *b,
+ const pthread_barrierattr_t *__restrict attr,
+ unsigned count);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_INIT_H
diff --git a/libc/src/pthread/pthread_barrier_wait.cpp b/libc/src/pthread/pthread_barrier_wait.cpp
new file mode 100644
index 0000000000000..ba23cc0f4e072
--- /dev/null
+++ b/libc/src/pthread/pthread_barrier_wait.cpp
@@ -0,0 +1,27 @@
+//===-- Linux implementation of the pthread_barrier_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_mutex_init.h"
+#include "pthread_mutexattr.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/threads/barrier.h"
+
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pthread_barrier_wait,
+ (pthread_barrier_t * b,
+ const pthread_barrierattr_t *__restrict attr,
+ unsigned count)) {
+ return reinterpret_cast<Barrier *>(b)->wait();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_barrier_wait.h b/libc/src/pthread/pthread_barrier_wait.h
new file mode 100644
index 0000000000000..738ca56bd53e4
--- /dev/null
+++ b/libc/src/pthread/pthread_barrier_wait.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pthread_barrier_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_BARRIER_WAIT_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_WAIT_H
+
+#include "src/__support/macros/config.h"
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_barrier_wait(pthread_barrier_t *b);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_WAIT_H
diff --git a/libc/test/integration/src/pthread/pthread_barrier_test.cpp b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
new file mode 100644
index 0000000000000..33d5945a6687d
--- /dev/null
+++ b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
@@ -0,0 +1,35 @@
+//===-- Tests for pthread_barrier_t ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/pthread/pthread_barrier_destroy.h"
+#include "src/pthread/pthread_barrier_init.h"
+#include "src/pthread/pthread_barrier_wait.h"
+
+#include "src/pthread/pthread_create.h"
+
+#include "test/IntegrationTest/test.h"
+
+#include <pthread.h>
+#include <stdint.h> // uintptr_t
+
+constexpr int START = 0;
+constexpr int MAX = 10000;
+
+pthread_barrier_t barrier;
+static int shared_int = START;
+
+void increment_shared_counter() {
+
+}
+
+
+
+TEST_MAIN() {
+
+ return 0;
+}
>From cefd7de20b8877741b89c0410e4109e34f454ca7 Mon Sep 17 00:00:00 2001
From: Uzair Nawaz <uzairnawaz at google.com>
Date: Tue, 15 Jul 2025 17:00:56 +0000
Subject: [PATCH 02/10] pthread test + public function
---
libc/config/linux/x86_64/entrypoints.txt | 3 +
libc/include/CMakeLists.txt | 2 +
libc/include/pthread.yaml | 22 +++++++
libc/src/__support/threads/CMakeLists.txt | 11 ++++
libc/src/__support/threads/barrier.cpp | 14 +++--
libc/src/__support/threads/barrier.h | 5 +-
libc/src/pthread/CMakeLists.txt | 34 ++++++++++
libc/src/pthread/pthread_barrier_destroy.cpp | 3 +-
libc/src/pthread/pthread_barrier_init.cpp | 3 +-
libc/src/pthread/pthread_barrier_wait.cpp | 7 +--
.../integration/src/pthread/CMakeLists.txt | 17 +++++
.../src/pthread/pthread_barrier_test.cpp | 63 +++++++++++++++++--
12 files changed, 164 insertions(+), 20 deletions(-)
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 59c248871f83a..3a631c9056163 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1039,6 +1039,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
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 55268d19529c7..3c16468b8110e 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -390,6 +390,8 @@ add_header_macro(
.llvm-libc-types.pthread_attr_t
.llvm-libc-types.pthread_condattr_t
.llvm-libc-types.pthread_key_t
+ .llvm-libc-types.pthread_barrier_t
+ .llvm-libc-types.pthread_barrierattr_t
.llvm-libc-types.pthread_mutex_t
.llvm-libc-types.pthread_mutexattr_t
.llvm-libc-types.pthread_once_t
diff --git a/libc/include/pthread.yaml b/libc/include/pthread.yaml
index 5b27e68d2f2d8..8afce2098adde 100644
--- a/libc/include/pthread.yaml
+++ b/libc/include/pthread.yaml
@@ -6,6 +6,8 @@ types:
- type_name: pthread_once_t
- type_name: pthread_mutex_t
- type_name: pthread_mutexattr_t
+ - type_name: pthread_barrier_t
+ - type_name: pthread_barrierattr_t
- type_name: pthread_key_t
- type_name: pthread_condattr_t
- type_name: __pthread_tss_dtor_t
@@ -277,6 +279,26 @@ functions:
arguments:
- type: pthread_mutexattr_t *__restrict
- type: int
+ - name: pthread_barrier_init
+ standards:
+ - POSIX
+ return_type: int
+ arguments:
+ - type: pthread_barrier_t *__restrict
+ - type: const pthread_barrierattr_t *__restrict
+ - type: int
+ - name: pthread_barrier_wait
+ standards:
+ - POSIX
+ return_type: int
+ arguments:
+ - type: pthread_barrier_t *
+ - name: pthread_barrier_destroy
+ standards:
+ - POSIX
+ return_type: int
+ arguments:
+ - type: pthread_barrier_t *
- name: pthread_once
standards:
- POSIX
diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt
index bd49bbb5ad2fe..3cf50b6d3f8a9 100644
--- a/libc/src/__support/threads/CMakeLists.txt
+++ b/libc/src/__support/threads/CMakeLists.txt
@@ -90,6 +90,17 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.CndVar)
)
endif()
+add_object_library(
+ barrier
+ HDRS
+ barrier.h
+ SRCS
+ barrier.cpp
+ DEPENDS
+ .CndVar
+ .mutex
+)
+
if (LLVM_LIBC_FULL_BUILD)
set(identifier_dependency_on_thread libc.src.__support.threads.thread)
endif()
diff --git a/libc/src/__support/threads/barrier.cpp b/libc/src/__support/threads/barrier.cpp
index db0e38e9eb71e..809898ac17ccf 100644
--- a/libc/src/__support/threads/barrier.cpp
+++ b/libc/src/__support/threads/barrier.cpp
@@ -7,12 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/__support/threads/barrier.h"
-#include "src/__support/threads/mutex.h"
+#include "barrier.h"
#include "hdr/errno_macros.h"
+#include "src/__support/threads/mutex.h"
namespace LIBC_NAMESPACE_DECL {
-int Barrier::init(Barrier *b, const pthread_barrierattr_t* attr, unsigned count) {
+int Barrier::init(Barrier *b, const pthread_barrierattr_t *attr,
+ unsigned count) {
+ LIBC_ASSERT(attr == nullptr); // TODO implement barrierattr
if (count == 0)
return EINVAL;
@@ -45,7 +48,6 @@ int Barrier::wait() {
if (waiting == expected) {
// this is the last thread to call wait(), so lets wake everyone up
blocking = false;
- waiting--;
exiting.broadcast();
} else {
// block threads until waiting = expected
@@ -53,6 +55,7 @@ int Barrier::wait() {
exiting.wait(&m);
}
}
+ waiting--;
// all threads have exited the barrier, lets let the ones waiting to enter
// continue
@@ -61,10 +64,13 @@ int Barrier::wait() {
entering.broadcast();
}
m.unlock();
+
+ return 0;
}
int Barrier::destroy(Barrier *b) {
-
+ Mutex::destroy(&b->m);
+ return 0;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/threads/barrier.h b/libc/src/__support/threads/barrier.h
index e46d5b9773a4f..d97aafe56d2cd 100644
--- a/libc/src/__support/threads/barrier.h
+++ b/libc/src/__support/threads/barrier.h
@@ -9,6 +9,8 @@
#ifndef LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_BARRIER_H
#define LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_BARRIER_H
+#include "include/llvm-libc-types/pthread_barrier_t.h"
+#include "include/llvm-libc-types/pthread_barrierattr_t.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/CndVar.h"
#include "src/__support/threads/mutex.h"
@@ -29,7 +31,8 @@ class Barrier {
Mutex m;
public:
- static int init(Barrier *b, const pthread_barrierattr_t* attr, unsigned count);
+ static int init(Barrier *b, const pthread_barrierattr_t *attr,
+ unsigned count);
static int destroy(Barrier *b);
int wait();
};
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index c8c66805667fa..e5a0a34cf46a6 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -271,6 +271,40 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ pthread_barrier_init
+ SRCS
+ pthread_barrier_init.cpp
+ HDRS
+ pthread_barrier_init.h
+ DEPENDS
+ libc.src.errno.errno
+ libc.include.pthread
+ libc.src.__support.threads.barrier
+)
+
+add_entrypoint_object(
+ pthread_barrier_destroy
+ SRCS
+ pthread_barrier_destroy.cpp
+ HDRS
+ pthread_barrier_destroy.h
+ DEPENDS
+ libc.include.pthread
+ libc.src.__support.threads.barrier
+)
+
+add_entrypoint_object(
+ pthread_barrier_wait
+ SRCS
+ pthread_barrier_wait.cpp
+ HDRS
+ pthread_barrier_wait.h
+ DEPENDS
+ libc.include.pthread
+ libc.src.__support.threads.barrier
+)
+
add_entrypoint_object(
pthread_mutex_init
SRCS
diff --git a/libc/src/pthread/pthread_barrier_destroy.cpp b/libc/src/pthread/pthread_barrier_destroy.cpp
index 00863f8d6ff6b..389e1751ed3ee 100644
--- a/libc/src/pthread/pthread_barrier_destroy.cpp
+++ b/libc/src/pthread/pthread_barrier_destroy.cpp
@@ -6,8 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "pthread_mutex_init.h"
-#include "pthread_mutexattr.h"
+#include "pthread_barrier_destroy.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
diff --git a/libc/src/pthread/pthread_barrier_init.cpp b/libc/src/pthread/pthread_barrier_init.cpp
index 234f58a6c7d62..1d0d87342d823 100644
--- a/libc/src/pthread/pthread_barrier_init.cpp
+++ b/libc/src/pthread/pthread_barrier_init.cpp
@@ -6,8 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "pthread_mutex_init.h"
-#include "pthread_mutexattr.h"
+#include "pthread_barrier_init.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
diff --git a/libc/src/pthread/pthread_barrier_wait.cpp b/libc/src/pthread/pthread_barrier_wait.cpp
index ba23cc0f4e072..75bba94ba438f 100644
--- a/libc/src/pthread/pthread_barrier_wait.cpp
+++ b/libc/src/pthread/pthread_barrier_wait.cpp
@@ -6,8 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "pthread_mutex_init.h"
-#include "pthread_mutexattr.h"
+#include "pthread_barrier_wait.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
@@ -18,9 +17,7 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, pthread_barrier_wait,
- (pthread_barrier_t * b,
- const pthread_barrierattr_t *__restrict attr,
- unsigned count)) {
+ (pthread_barrier_t * b)) {
return reinterpret_cast<Barrier *>(b)->wait();
}
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index 208ba3fd43507..ce3bb9da9d58e 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -17,6 +17,23 @@ add_integration_test(
libc.src.pthread.pthread_join
)
+add_integration_test(
+ pthread_barrier_test
+ SUITE
+ libc-pthread-integration-tests
+ SRCS
+ pthread_barrier_test.cpp
+ DEPENDS
+ libc.include.pthread
+ libc.src.errno.errno
+ libc.src.pthread.pthread_barrier_destroy
+ libc.src.pthread.pthread_barrier_wait
+ libc.src.pthread.pthread_barrier_init
+ libc.src.pthread.pthread_create
+ libc.src.pthread.pthread_join
+ libc.src.stdio.printf
+)
+
add_integration_test(
pthread_rwlock_test
SUITE
diff --git a/libc/test/integration/src/pthread/pthread_barrier_test.cpp b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
index 33d5945a6687d..b87f21a2a2c51 100644
--- a/libc/test/integration/src/pthread/pthread_barrier_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
@@ -10,26 +10,77 @@
#include "src/pthread/pthread_barrier_init.h"
#include "src/pthread/pthread_barrier_wait.h"
+#include "src/__support/CPP/atomic.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/stdio/printf.h"
#include "test/IntegrationTest/test.h"
#include <pthread.h>
#include <stdint.h> // uintptr_t
-constexpr int START = 0;
-constexpr int MAX = 10000;
-
pthread_barrier_t barrier;
-static int shared_int = START;
-void increment_shared_counter() {
+void smoke_test() {
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, 1), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_barrier_wait(&barrier), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_barrier_destroy(&barrier), 0);
+}
+LIBC_NAMESPACE::cpp::Atomic<int> counter;
+void *increment_counter_and_wait(void *args) {
+ counter.fetch_add(1);
+ LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
+ return 0;
}
+void shared_counter() {
+ counter.set(0);
+ const int NUM_THREADS = 30;
+ pthread_t threads[NUM_THREADS];
+ ASSERT_EQ(
+ LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, NUM_THREADS + 1),
+ 0);
+ for (int i = 0; i < NUM_THREADS; ++i)
+ LIBC_NAMESPACE::pthread_create(&threads[i], nullptr,
+ increment_counter_and_wait, nullptr);
+
+ LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
+ ASSERT_EQ(counter.load(), NUM_THREADS);
+}
+
+void reusable_shared_counter() {
+ counter.set(0);
+ const int NUM_THREADS = 30;
+ const int REPEAT = 10;
+ pthread_t threads[NUM_THREADS * REPEAT];
+ ASSERT_EQ(
+ LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, NUM_THREADS + 1),
+ 0);
+
+ for (int i = 0; i < REPEAT; ++i) {
+ for (int j = 0; j < NUM_THREADS; ++j) {
+ LIBC_NAMESPACE::pthread_create(&threads[NUM_THREADS * i + j], nullptr,
+ increment_counter_and_wait, nullptr);
+ }
+ LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
+ ASSERT_EQ(counter.load(), NUM_THREADS * (i + 1));
+ }
+
+ for (int i = 0; i < NUM_THREADS * REPEAT; ++i) {
+ LIBC_NAMESPACE::pthread_join(threads[i], nullptr);
+ }
+}
TEST_MAIN() {
-
+ smoke_test();
+ shared_counter();
+ reusable_shared_counter();
return 0;
}
>From d645f954d8374d3cf3b4ba61dc18b16724c21717 Mon Sep 17 00:00:00 2001
From: Uzair Nawaz <uzairnawaz at google.com>
Date: Tue, 15 Jul 2025 17:20:06 +0000
Subject: [PATCH 03/10] fix test to join threads
---
.../src/pthread/pthread_barrier_test.cpp | 21 ++++++++++---------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/libc/test/integration/src/pthread/pthread_barrier_test.cpp b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
index b87f21a2a2c51..8cf2aaf16acbe 100644
--- a/libc/test/integration/src/pthread/pthread_barrier_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
@@ -22,7 +22,6 @@
#include "test/IntegrationTest/test.h"
#include <pthread.h>
-#include <stdint.h> // uintptr_t
pthread_barrier_t barrier;
@@ -39,7 +38,7 @@ void *increment_counter_and_wait(void *args) {
return 0;
}
-void shared_counter() {
+void single_use_barrier() {
counter.set(0);
const int NUM_THREADS = 30;
pthread_t threads[NUM_THREADS];
@@ -53,34 +52,36 @@ void shared_counter() {
LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
ASSERT_EQ(counter.load(), NUM_THREADS);
+
+ for (int i = 0; i < NUM_THREADS; ++i)
+ LIBC_NAMESPACE::pthread_join(threads[i], nullptr);
}
-void reusable_shared_counter() {
+void reusable_barrier() {
counter.set(0);
const int NUM_THREADS = 30;
- const int REPEAT = 10;
+ const int REPEAT = 20;
pthread_t threads[NUM_THREADS * REPEAT];
ASSERT_EQ(
LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, NUM_THREADS + 1),
0);
for (int i = 0; i < REPEAT; ++i) {
- for (int j = 0; j < NUM_THREADS; ++j) {
+ for (int j = 0; j < NUM_THREADS; ++j)
LIBC_NAMESPACE::pthread_create(&threads[NUM_THREADS * i + j], nullptr,
increment_counter_and_wait, nullptr);
- }
+
LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
ASSERT_EQ(counter.load(), NUM_THREADS * (i + 1));
}
- for (int i = 0; i < NUM_THREADS * REPEAT; ++i) {
+ for (int i = 0; i < NUM_THREADS * REPEAT; ++i)
LIBC_NAMESPACE::pthread_join(threads[i], nullptr);
- }
}
TEST_MAIN() {
smoke_test();
- shared_counter();
- reusable_shared_counter();
+ single_use_barrier();
+ reusable_barrier();
return 0;
}
>From 8cad8c0a4533c525c1a41b13821c41edaa2e3359 Mon Sep 17 00:00:00 2001
From: Uzair Nawaz <uzairnawaz at google.com>
Date: Tue, 15 Jul 2025 18:00:24 +0000
Subject: [PATCH 04/10] implemented return value for barrier wait
---
.../include/llvm-libc-macros/pthread-macros.h | 2 ++
libc/src/__support/threads/barrier.cpp | 6 ++++
libc/src/__support/threads/barrier.h | 2 ++
libc/src/pthread/pthread_barrier_wait.cpp | 9 ++++--
.../src/pthread/pthread_barrier_test.cpp | 32 ++++++++++++++++++-
5 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/libc/include/llvm-libc-macros/pthread-macros.h b/libc/include/llvm-libc-macros/pthread-macros.h
index fcc6ef925e3f4..ce467b7cc4d07 100644
--- a/libc/include/llvm-libc-macros/pthread-macros.h
+++ b/libc/include/llvm-libc-macros/pthread-macros.h
@@ -22,6 +22,8 @@
#define PTHREAD_MUTEX_STALLED 0
#define PTHREAD_MUTEX_ROBUST 1
+#define PTHREAD_BARRIER_SERIAL_THREAD -1
+
#define PTHREAD_ONCE_INIT {0}
#define PTHREAD_PROCESS_PRIVATE 0
diff --git a/libc/src/__support/threads/barrier.cpp b/libc/src/__support/threads/barrier.cpp
index 809898ac17ccf..298cb17cb8d00 100644
--- a/libc/src/__support/threads/barrier.cpp
+++ b/libc/src/__support/threads/barrier.cpp
@@ -13,6 +13,8 @@
namespace LIBC_NAMESPACE_DECL {
+const int BARRIER_FIRST_EXITED = -1;
+
int Barrier::init(Barrier *b, const pthread_barrierattr_t *attr,
unsigned count) {
LIBC_ASSERT(attr == nullptr); // TODO implement barrierattr
@@ -62,6 +64,8 @@ int Barrier::wait() {
if (waiting == 0) {
blocking = true;
entering.broadcast();
+ m.unlock();
+ return BARRIER_FIRST_EXITED;
}
m.unlock();
@@ -69,6 +73,8 @@ int Barrier::wait() {
}
int Barrier::destroy(Barrier *b) {
+ CndVar::destroy(&b->entering);
+ CndVar::destroy(&b->exiting);
Mutex::destroy(&b->m);
return 0;
}
diff --git a/libc/src/__support/threads/barrier.h b/libc/src/__support/threads/barrier.h
index d97aafe56d2cd..b8b410ec1b35e 100644
--- a/libc/src/__support/threads/barrier.h
+++ b/libc/src/__support/threads/barrier.h
@@ -21,6 +21,8 @@ namespace LIBC_NAMESPACE_DECL {
// pthread_barrier_t (found in include/llvm-libc/types/pthread_barrier_t.h) is
// the same size
+extern const int BARRIER_FIRST_EXITED;
+
class Barrier {
private:
unsigned expected;
diff --git a/libc/src/pthread/pthread_barrier_wait.cpp b/libc/src/pthread/pthread_barrier_wait.cpp
index 75bba94ba438f..617d91dd16f77 100644
--- a/libc/src/pthread/pthread_barrier_wait.cpp
+++ b/libc/src/pthread/pthread_barrier_wait.cpp
@@ -16,9 +16,12 @@
namespace LIBC_NAMESPACE_DECL {
-LLVM_LIBC_FUNCTION(int, pthread_barrier_wait,
- (pthread_barrier_t * b)) {
- return reinterpret_cast<Barrier *>(b)->wait();
+LLVM_LIBC_FUNCTION(int, pthread_barrier_wait, (pthread_barrier_t * b)) {
+ int out = reinterpret_cast<Barrier *>(b)->wait();
+ if (out == BARRIER_FIRST_EXITED)
+ return PTHREAD_BARRIER_SERIAL_THREAD;
+
+ return out;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/integration/src/pthread/pthread_barrier_test.cpp b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
index 8cf2aaf16acbe..d4d696ec82507 100644
--- a/libc/test/integration/src/pthread/pthread_barrier_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
@@ -27,7 +27,8 @@ pthread_barrier_t barrier;
void smoke_test() {
ASSERT_EQ(LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, 1), 0);
- ASSERT_EQ(LIBC_NAMESPACE::pthread_barrier_wait(&barrier), 0);
+ ASSERT_EQ(LIBC_NAMESPACE::pthread_barrier_wait(&barrier),
+ PTHREAD_BARRIER_SERIAL_THREAD);
ASSERT_EQ(LIBC_NAMESPACE::pthread_barrier_destroy(&barrier), 0);
}
@@ -55,6 +56,8 @@ void single_use_barrier() {
for (int i = 0; i < NUM_THREADS; ++i)
LIBC_NAMESPACE::pthread_join(threads[i], nullptr);
+
+ LIBC_NAMESPACE::pthread_barrier_destroy(&barrier);
}
void reusable_barrier() {
@@ -77,11 +80,38 @@ void reusable_barrier() {
for (int i = 0; i < NUM_THREADS * REPEAT; ++i)
LIBC_NAMESPACE::pthread_join(threads[i], nullptr);
+
+ LIBC_NAMESPACE::pthread_barrier_destroy(&barrier);
+}
+
+void *barrier_wait(void* in) {
+ return reinterpret_cast<void *>(
+ LIBC_NAMESPACE::pthread_barrier_wait(&barrier));
+}
+
+// verify that only one of the wait() calls return PTHREAD_BARRIER_SERIAL_THREAD
+// with the rest returning 0
+void one_nonzero_wait_returnval() {
+ const int NUM_THREADS = 30;
+ pthread_t threads[NUM_THREADS];
+ LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, NUM_THREADS + 1);
+ for (int i = 0; i < NUM_THREADS; ++i)
+ LIBC_NAMESPACE::pthread_create(&threads[i], nullptr, barrier_wait, nullptr);
+
+ uintptr_t retsum = LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
+ for (int i = 0; i < NUM_THREADS; ++i) {
+ void* ret;
+ LIBC_NAMESPACE::pthread_join(threads[i], &ret);
+ retsum += reinterpret_cast<uintptr_t>(ret);
+ }
+
+ ASSERT_EQ(static_cast<int>(retsum), PTHREAD_BARRIER_SERIAL_THREAD);
}
TEST_MAIN() {
smoke_test();
single_use_barrier();
reusable_barrier();
+ one_nonzero_wait_returnval();
return 0;
}
>From 7adf56a5ed4705dca4816e7c889d42df6478a8d9 Mon Sep 17 00:00:00 2001
From: Uzair Nawaz <uzairnawaz at google.com>
Date: Tue, 15 Jul 2025 20:13:06 +0000
Subject: [PATCH 05/10] formatting
---
libc/src/__support/threads/barrier.cpp | 2 +-
libc/src/pthread/pthread_barrier_destroy.h | 2 +-
libc/src/pthread/pthread_barrier_wait.cpp | 2 +-
libc/test/integration/src/pthread/pthread_barrier_test.cpp | 4 ++--
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/libc/src/__support/threads/barrier.cpp b/libc/src/__support/threads/barrier.cpp
index 298cb17cb8d00..050abb3391446 100644
--- a/libc/src/__support/threads/barrier.cpp
+++ b/libc/src/__support/threads/barrier.cpp
@@ -1,4 +1,4 @@
-//===-- Linux implementation of the callonce function ---------------------===//
+//===-- Implementation of Barrier class ------------- ---------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/pthread/pthread_barrier_destroy.h b/libc/src/pthread/pthread_barrier_destroy.h
index 0b1d0f090ec26..58ac08862d90c 100644
--- a/libc/src/pthread/pthread_barrier_destroy.h
+++ b/libc/src/pthread/pthread_barrier_destroy.h
@@ -1,4 +1,4 @@
-//===-- Implementation header for pthread_barrier_destroy ----------*- C++ -*-===//
+//===-- Implementation header for pthread_barrier_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.
diff --git a/libc/src/pthread/pthread_barrier_wait.cpp b/libc/src/pthread/pthread_barrier_wait.cpp
index 617d91dd16f77..7b12c907f4fb1 100644
--- a/libc/src/pthread/pthread_barrier_wait.cpp
+++ b/libc/src/pthread/pthread_barrier_wait.cpp
@@ -20,7 +20,7 @@ LLVM_LIBC_FUNCTION(int, pthread_barrier_wait, (pthread_barrier_t * b)) {
int out = reinterpret_cast<Barrier *>(b)->wait();
if (out == BARRIER_FIRST_EXITED)
return PTHREAD_BARRIER_SERIAL_THREAD;
-
+
return out;
}
diff --git a/libc/test/integration/src/pthread/pthread_barrier_test.cpp b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
index d4d696ec82507..bde1230f5b86d 100644
--- a/libc/test/integration/src/pthread/pthread_barrier_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
@@ -84,7 +84,7 @@ void reusable_barrier() {
LIBC_NAMESPACE::pthread_barrier_destroy(&barrier);
}
-void *barrier_wait(void* in) {
+void *barrier_wait(void *in) {
return reinterpret_cast<void *>(
LIBC_NAMESPACE::pthread_barrier_wait(&barrier));
}
@@ -100,7 +100,7 @@ void one_nonzero_wait_returnval() {
uintptr_t retsum = LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
for (int i = 0; i < NUM_THREADS; ++i) {
- void* ret;
+ void *ret;
LIBC_NAMESPACE::pthread_join(threads[i], &ret);
retsum += reinterpret_cast<uintptr_t>(ret);
}
>From a349e6f20cb8d4058c8f0247d48bd8e837129420 Mon Sep 17 00:00:00 2001
From: Uzair Nawaz <uzairnawaz at google.com>
Date: Tue, 15 Jul 2025 20:22:42 +0000
Subject: [PATCH 06/10] mark attr param as unused
---
libc/src/__support/threads/barrier.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libc/src/__support/threads/barrier.cpp b/libc/src/__support/threads/barrier.cpp
index 050abb3391446..e63467d88b2bf 100644
--- a/libc/src/__support/threads/barrier.cpp
+++ b/libc/src/__support/threads/barrier.cpp
@@ -15,7 +15,8 @@ namespace LIBC_NAMESPACE_DECL {
const int BARRIER_FIRST_EXITED = -1;
-int Barrier::init(Barrier *b, const pthread_barrierattr_t *attr,
+int Barrier::init(Barrier *b,
+ const pthread_barrierattr_t *attr __attribute__((unused)),
unsigned count) {
LIBC_ASSERT(attr == nullptr); // TODO implement barrierattr
if (count == 0)
>From d901a3712e797e8a464e967cb99209e3fd000e62 Mon Sep 17 00:00:00 2001
From: Uzair Nawaz <uzairnawaz at google.com>
Date: Fri, 18 Jul 2025 16:47:38 +0000
Subject: [PATCH 07/10] reorganized for readability
---
libc/src/__support/threads/barrier.cpp | 17 +++++++++--------
libc/src/__support/threads/barrier.h | 9 +++++++++
libc/src/pthread/pthread_barrier_init.cpp | 5 -----
3 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/libc/src/__support/threads/barrier.cpp b/libc/src/__support/threads/barrier.cpp
index e63467d88b2bf..a9253d8c91611 100644
--- a/libc/src/__support/threads/barrier.cpp
+++ b/libc/src/__support/threads/barrier.cpp
@@ -9,6 +9,7 @@
#include "src/__support/threads/barrier.h"
#include "barrier.h"
#include "hdr/errno_macros.h"
+#include "src/__support/threads/CndVar.h"
#include "src/__support/threads/mutex.h"
namespace LIBC_NAMESPACE_DECL {
@@ -16,7 +17,7 @@ namespace LIBC_NAMESPACE_DECL {
const int BARRIER_FIRST_EXITED = -1;
int Barrier::init(Barrier *b,
- const pthread_barrierattr_t *attr __attribute__((unused)),
+ [[maybe_unused]] const pthread_barrierattr_t *attr,
unsigned count) {
LIBC_ASSERT(attr == nullptr); // TODO implement barrierattr
if (count == 0)
@@ -48,21 +49,21 @@ int Barrier::wait() {
}
waiting++;
- if (waiting == expected) {
- // this is the last thread to call wait(), so lets wake everyone up
- blocking = false;
- exiting.broadcast();
- } else {
+ if (waiting < expected) {
// block threads until waiting = expected
while (blocking) {
exiting.wait(&m);
}
+ } else {
+ // this is the last thread to call wait(), so lets wake everyone up
+ blocking = false;
+ exiting.broadcast();
}
waiting--;
- // all threads have exited the barrier, lets let the ones waiting to enter
- // continue
if (waiting == 0) {
+ // all threads have exited the barrier, let's let the ones waiting to enter
+ // continue
blocking = true;
entering.broadcast();
m.unlock();
diff --git a/libc/src/__support/threads/barrier.h b/libc/src/__support/threads/barrier.h
index b8b410ec1b35e..5aa99fe405cda 100644
--- a/libc/src/__support/threads/barrier.h
+++ b/libc/src/__support/threads/barrier.h
@@ -39,6 +39,15 @@ class Barrier {
int wait();
};
+static_assert(
+ sizeof(Barrier) <= sizeof(pthread_barrier_t),
+ "The public pthread_barrier_t type cannot accommodate the internal "
+ "barrier type.");
+
+static_assert(alignof(Barrier) == alignof(pthread_barrier_t),
+ "The public pthread_barrier_t type has a different alignment "
+ "than the internal barrier type.");
+
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_BARRIER_H
diff --git a/libc/src/pthread/pthread_barrier_init.cpp b/libc/src/pthread/pthread_barrier_init.cpp
index 1d0d87342d823..f17885432bf31 100644
--- a/libc/src/pthread/pthread_barrier_init.cpp
+++ b/libc/src/pthread/pthread_barrier_init.cpp
@@ -16,11 +16,6 @@
namespace LIBC_NAMESPACE_DECL {
-static_assert(
- sizeof(Barrier) <= sizeof(pthread_barrier_t),
- "The public pthread_barrier_t type cannot accommodate the internal "
- "barrier type.");
-
LLVM_LIBC_FUNCTION(int, pthread_barrier_init,
(pthread_barrier_t * b,
const pthread_barrierattr_t *__restrict attr,
>From 0512e7f596583298f89bd702c9d45b34f2554ea6 Mon Sep 17 00:00:00 2001
From: Uzair Nawaz <uzairnawaz at google.com>
Date: Fri, 18 Jul 2025 19:23:06 +0000
Subject: [PATCH 08/10] used internal pthread header
---
libc/hdr/types/pthread_barrier_t.h | 22 ++++++++++++++++++++
libc/hdr/types/pthread_barrierattr_t.h | 22 ++++++++++++++++++++
libc/src/pthread/pthread_barrier_destroy.cpp | 3 +--
libc/src/pthread/pthread_barrier_destroy.h | 2 +-
libc/src/pthread/pthread_barrier_init.cpp | 4 ++--
libc/src/pthread/pthread_barrier_init.h | 3 ++-
libc/src/pthread/pthread_barrier_wait.cpp | 3 +--
libc/src/pthread/pthread_barrier_wait.h | 2 +-
8 files changed, 52 insertions(+), 9 deletions(-)
create mode 100644 libc/hdr/types/pthread_barrier_t.h
create mode 100644 libc/hdr/types/pthread_barrierattr_t.h
diff --git a/libc/hdr/types/pthread_barrier_t.h b/libc/hdr/types/pthread_barrier_t.h
new file mode 100644
index 0000000000000..57bcdfc6a9901
--- /dev/null
+++ b/libc/hdr/types/pthread_barrier_t.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from pthread_barrier_t.h ---------------------===//
+//
+// 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_HDR_TYPES_PTHREAD_BARRIER_T_H
+#define LLVM_LIBC_HDR_TYPES_PTHREAD_BARRIER_T_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/pthread_barrier_t.h"
+
+#else // Overlay mode
+
+#error "Cannot overlay pthread_barrier_t"
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_PTHREAD_BARRIER_T_H
diff --git a/libc/hdr/types/pthread_barrierattr_t.h b/libc/hdr/types/pthread_barrierattr_t.h
new file mode 100644
index 0000000000000..d08dda1c2f36d
--- /dev/null
+++ b/libc/hdr/types/pthread_barrierattr_t.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from pthread_barrier_t.h ---------------------===//
+//
+// 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_HDR_TYPES_PTHREAD_BARRIERATTR_T_H
+#define LLVM_LIBC_HDR_TYPES_PTHREAD_BARRIERATTR_T_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/pthread_barrierattr_t.h"
+
+#else // Overlay mode
+
+#error "Cannot overlay pthread_barrierattr_t"
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_PTHREAD_BARRIERATTR_T_H
diff --git a/libc/src/pthread/pthread_barrier_destroy.cpp b/libc/src/pthread/pthread_barrier_destroy.cpp
index 389e1751ed3ee..6c9ae8d57ab2f 100644
--- a/libc/src/pthread/pthread_barrier_destroy.cpp
+++ b/libc/src/pthread/pthread_barrier_destroy.cpp
@@ -8,12 +8,11 @@
#include "pthread_barrier_destroy.h"
+#include "hdr/types/pthread_barrier_t.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/barrier.h"
-#include <pthread.h>
-
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, pthread_barrier_destroy, (pthread_barrier_t * b)) {
diff --git a/libc/src/pthread/pthread_barrier_destroy.h b/libc/src/pthread/pthread_barrier_destroy.h
index 58ac08862d90c..e27552ce7e5ae 100644
--- a/libc/src/pthread/pthread_barrier_destroy.h
+++ b/libc/src/pthread/pthread_barrier_destroy.h
@@ -9,8 +9,8 @@
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_DESTROY_H
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_DESTROY_H
+#include "hdr/types/pthread_barrier_t.h"
#include "src/__support/macros/config.h"
-#include <pthread.h>
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/pthread/pthread_barrier_init.cpp b/libc/src/pthread/pthread_barrier_init.cpp
index f17885432bf31..4317d82bc935f 100644
--- a/libc/src/pthread/pthread_barrier_init.cpp
+++ b/libc/src/pthread/pthread_barrier_init.cpp
@@ -8,12 +8,12 @@
#include "pthread_barrier_init.h"
+#include "hdr/types/pthread_barrier_t.h"
+#include "hdr/types/pthread_barrierattr_t.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/barrier.h"
-#include <pthread.h>
-
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, pthread_barrier_init,
diff --git a/libc/src/pthread/pthread_barrier_init.h b/libc/src/pthread/pthread_barrier_init.h
index ea79df6da7ea9..bb17f3f5664da 100644
--- a/libc/src/pthread/pthread_barrier_init.h
+++ b/libc/src/pthread/pthread_barrier_init.h
@@ -9,8 +9,9 @@
#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_INIT_H
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_INIT_H
+#include "hdr/types/pthread_barrier_t.h"
+#include "hdr/types/pthread_barrierattr_t.h"
#include "src/__support/macros/config.h"
-#include <pthread.h>
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/pthread/pthread_barrier_wait.cpp b/libc/src/pthread/pthread_barrier_wait.cpp
index 7b12c907f4fb1..7e34babdb2579 100644
--- a/libc/src/pthread/pthread_barrier_wait.cpp
+++ b/libc/src/pthread/pthread_barrier_wait.cpp
@@ -8,12 +8,11 @@
#include "pthread_barrier_wait.h"
+#include "hdr/types/pthread_barrier_t.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/barrier.h"
-#include <pthread.h>
-
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, pthread_barrier_wait, (pthread_barrier_t * b)) {
diff --git a/libc/src/pthread/pthread_barrier_wait.h b/libc/src/pthread/pthread_barrier_wait.h
index 738ca56bd53e4..52eb172d6264c 100644
--- a/libc/src/pthread/pthread_barrier_wait.h
+++ b/libc/src/pthread/pthread_barrier_wait.h
@@ -10,7 +10,7 @@
#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_BARRIER_WAIT_H
#include "src/__support/macros/config.h"
-#include <pthread.h>
+#include "hdr/types/pthread_barrier_t.h"
namespace LIBC_NAMESPACE_DECL {
>From ecf9f6c5ddcda1a717eca30286d103f394ed7c4b Mon Sep 17 00:00:00 2001
From: Uzair Nawaz <uzairnawaz at google.com>
Date: Tue, 22 Jul 2025 21:40:56 +0000
Subject: [PATCH 09/10] fix pthread_barrier_t public struct
opaqueness/alignment + test cleanup
---
libc/hdr/CMakeLists.txt | 9 ++
libc/hdr/pthread_macros.h | 22 ++++
libc/hdr/types/CMakeLists.txt | 16 +++
libc/include/llvm-libc-types/CMakeLists.txt | 1 +
libc/include/llvm-libc-types/__barrier_type.h | 21 ++++
.../llvm-libc-types/pthread_barrier_t.h | 7 +-
libc/src/__support/threads/barrier.cpp | 12 +-
libc/src/__support/threads/barrier.h | 5 +-
libc/src/pthread/pthread_barrier_wait.cpp | 6 +-
.../src/pthread/pthread_barrier_test.cpp | 107 +++++++++---------
10 files changed, 136 insertions(+), 70 deletions(-)
create mode 100644 libc/hdr/pthread_macros.h
create mode 100644 libc/include/llvm-libc-types/__barrier_type.h
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index 052a773a4fcec..0aa79e98446c1 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -72,6 +72,15 @@ add_proxy_header_library(
libc.include.fenv
)
+add_proxy_header_library(
+ pthread_macros
+ HDRS
+ pthread_macros.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-macros.pthread_macros
+ libc.include.pthread
+)
+
add_proxy_header_library(
sched_macros
HDRS
diff --git a/libc/hdr/pthread_macros.h b/libc/hdr/pthread_macros.h
new file mode 100644
index 0000000000000..b0bab73687e3b
--- /dev/null
+++ b/libc/hdr/pthread_macros.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from pthread.h ----------------------------------===//
+//
+// 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_HDR_PTHREAD_MACROS_H
+#define LLVM_LIBC_HDR_PTHREAD_MACROS_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-macros/pthread-macros.h"
+
+#else // Overlay mode
+
+#include <pthread.h>
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_PTHREAD_MACROS_H
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index e4b3cb0faa820..2f2d6e8f0f985 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -237,6 +237,22 @@ add_proxy_header_library(
libc.include.llvm-libc-types.pid_t
)
+add_proxy_header_library(
+ pthread_barrier_t
+ HDRS
+ pthread_barrier_t.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.pthread_barrier_t
+)
+
+add_proxy_header_library(
+ pthread_barrierattr_t
+ HDRS
+ pthread_barrierattr_t.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.pthread_barrierattr_t
+)
+
add_proxy_header_library(
atexithandler_t
HDRS
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 405c2cd26b863..ba621757a31ed 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -10,6 +10,7 @@ add_header(__exec_envp_t HDR __exec_envp_t.h)
add_header(__futex_word HDR __futex_word.h)
add_header(pid_t HDR pid_t.h)
add_header(__mutex_type HDR __mutex_type.h DEPENDS .__futex_word .pid_t)
+add_header(__barrier_type HDR __barrier_type.h)
add_header(__pthread_once_func_t HDR __pthread_once_func_t.h)
add_header(__pthread_start_t HDR __pthread_start_t.h)
add_header(__pthread_tss_dtor_t HDR __pthread_tss_dtor_t.h)
diff --git a/libc/include/llvm-libc-types/__barrier_type.h b/libc/include/llvm-libc-types/__barrier_type.h
new file mode 100644
index 0000000000000..97406b8843ee5
--- /dev/null
+++ b/libc/include/llvm-libc-types/__barrier_type.h
@@ -0,0 +1,21 @@
+//===-- Definition of pthread_barrier_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__BARRIER_TYPE_H
+#define LLVM_LIBC_TYPES__BARRIER_TYPE_H
+
+typedef struct __attribute__((aligned(8 /* alignof (Barrier) */))) {
+ unsigned expected;
+ unsigned waiting;
+ bool blocking;
+ char entering[24 /* sizeof (CndVar) */];
+ char exiting[24 /* sizeof (CndVar) */];
+ char mutex[24 /* sizeof (Mutex) */];
+} __barrier_type;
+
+#endif // LLVM_LIBC_TYPES__BARRIER_TYPE_H
diff --git a/libc/include/llvm-libc-types/pthread_barrier_t.h b/libc/include/llvm-libc-types/pthread_barrier_t.h
index d95477afb226c..3a3d4706d43e6 100644
--- a/libc/include/llvm-libc-types/pthread_barrier_t.h
+++ b/libc/include/llvm-libc-types/pthread_barrier_t.h
@@ -1,4 +1,4 @@
-//===-- Definition of pthread_barrier_t type ------------------------------===//
+//===-- Definition of pthread_barrier_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.
@@ -9,8 +9,7 @@
#ifndef LLVM_LIBC_TYPES_PTHREAD_BARRIER_T_H
#define LLVM_LIBC_TYPES_PTHREAD_BARRIER_T_H
-typedef struct {
- char padding[88];
-} pthread_barrier_t;
+#include "include/llvm-libc-types/__barrier_type.h"
+typedef __barrier_type pthread_barrier_t;
#endif // LLVM_LIBC_TYPES_PTHREAD_BARRIER_T_H
diff --git a/libc/src/__support/threads/barrier.cpp b/libc/src/__support/threads/barrier.cpp
index a9253d8c91611..e39fb17637633 100644
--- a/libc/src/__support/threads/barrier.cpp
+++ b/libc/src/__support/threads/barrier.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-const int BARRIER_FIRST_EXITED = -1;
-
int Barrier::init(Barrier *b,
[[maybe_unused]] const pthread_barrierattr_t *attr,
unsigned count) {
@@ -36,7 +34,10 @@ int Barrier::init(Barrier *b,
if (err != 0)
return err;
- Mutex::init(&b->m, false, false, false, false);
+ auto mutex_err = Mutex::init(&b->m, false, false, false, false);
+ if (mutex_err != MutexError::NONE)
+ return EAGAIN;
+
return 0;
}
@@ -67,7 +68,10 @@ int Barrier::wait() {
blocking = true;
entering.broadcast();
m.unlock();
- return BARRIER_FIRST_EXITED;
+
+ // POSIX dictates that the barrier should return a special value to just one
+ // thread, so we can arbitrarily choose this thread
+ return PTHREAD_BARRIER_SERIAL_THREAD;
}
m.unlock();
diff --git a/libc/src/__support/threads/barrier.h b/libc/src/__support/threads/barrier.h
index 5aa99fe405cda..aae811a70e41c 100644
--- a/libc/src/__support/threads/barrier.h
+++ b/libc/src/__support/threads/barrier.h
@@ -9,9 +9,9 @@
#ifndef LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_BARRIER_H
#define LLVM_LIBC___SUPPORT_SRC_THREADS_LINUX_BARRIER_H
+#include "hdr/pthread_macros.h"
#include "include/llvm-libc-types/pthread_barrier_t.h"
#include "include/llvm-libc-types/pthread_barrierattr_t.h"
-#include "src/__support/macros/config.h"
#include "src/__support/threads/CndVar.h"
#include "src/__support/threads/mutex.h"
@@ -20,9 +20,6 @@ namespace LIBC_NAMESPACE_DECL {
// NOTE: if the size of this class changes, you must ensure that the size of
// pthread_barrier_t (found in include/llvm-libc/types/pthread_barrier_t.h) is
// the same size
-
-extern const int BARRIER_FIRST_EXITED;
-
class Barrier {
private:
unsigned expected;
diff --git a/libc/src/pthread/pthread_barrier_wait.cpp b/libc/src/pthread/pthread_barrier_wait.cpp
index 7e34babdb2579..3d68c4f8938c9 100644
--- a/libc/src/pthread/pthread_barrier_wait.cpp
+++ b/libc/src/pthread/pthread_barrier_wait.cpp
@@ -16,11 +16,7 @@
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, pthread_barrier_wait, (pthread_barrier_t * b)) {
- int out = reinterpret_cast<Barrier *>(b)->wait();
- if (out == BARRIER_FIRST_EXITED)
- return PTHREAD_BARRIER_SERIAL_THREAD;
-
- return out;
+ return reinterpret_cast<Barrier *>(b)->wait();
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/integration/src/pthread/pthread_barrier_test.cpp b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
index bde1230f5b86d..2ba4d3ac22897 100644
--- a/libc/test/integration/src/pthread/pthread_barrier_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
@@ -18,68 +18,87 @@
#include "src/pthread/pthread_mutex_lock.h"
#include "src/pthread/pthread_mutex_unlock.h"
#include "src/stdio/printf.h"
+#include "src/string/memset.h"
#include "test/IntegrationTest/test.h"
#include <pthread.h>
pthread_barrier_t barrier;
-
-void smoke_test() {
- ASSERT_EQ(LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, 1), 0);
- ASSERT_EQ(LIBC_NAMESPACE::pthread_barrier_wait(&barrier),
- PTHREAD_BARRIER_SERIAL_THREAD);
- ASSERT_EQ(LIBC_NAMESPACE::pthread_barrier_destroy(&barrier), 0);
-}
-
LIBC_NAMESPACE::cpp::Atomic<int> counter;
+
void *increment_counter_and_wait(void *args) {
counter.fetch_add(1);
- LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
- return 0;
+ return reinterpret_cast<void *>(
+ LIBC_NAMESPACE::pthread_barrier_wait(&barrier));
}
-void single_use_barrier() {
+void single_use_barrier_test(int num_threads) {
counter.set(0);
- const int NUM_THREADS = 30;
- pthread_t threads[NUM_THREADS];
+ // create n - 1 ADDITIONAL threads since the current thread will also wait at
+ // the barrier
+ pthread_t threads[num_threads - 1];
+ LIBC_NAMESPACE::memset(&barrier, 0, sizeof(pthread_barrier_t));
ASSERT_EQ(
- LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, NUM_THREADS + 1),
- 0);
+ LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, num_threads), 0);
- for (int i = 0; i < NUM_THREADS; ++i)
+ for (int i = 0; i < num_threads - 1; ++i)
LIBC_NAMESPACE::pthread_create(&threads[i], nullptr,
increment_counter_and_wait, nullptr);
- LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
- ASSERT_EQ(counter.load(), NUM_THREADS);
+ uintptr_t return_val_sum =
+ reinterpret_cast<uintptr_t>(increment_counter_and_wait(nullptr));
+ ASSERT_EQ(counter.load(), num_threads);
- for (int i = 0; i < NUM_THREADS; ++i)
- LIBC_NAMESPACE::pthread_join(threads[i], nullptr);
+ // verify only one thread got the PTHREAD_BARRIER_SERIAL_THREAD return value
+ for (int i = 0; i < num_threads - 1; ++i) {
+ void *ret;
+ LIBC_NAMESPACE::pthread_join(threads[i], &ret);
+ if (reinterpret_cast<uintptr_t>(ret) ==
+ static_cast<uintptr_t>(PTHREAD_BARRIER_SERIAL_THREAD)) {
+ return_val_sum += reinterpret_cast<uintptr_t>(ret);
+ } else {
+ ASSERT_EQ(ret, 0);
+ }
+ }
+ ASSERT_EQ(return_val_sum,
+ static_cast<uintptr_t>(PTHREAD_BARRIER_SERIAL_THREAD));
LIBC_NAMESPACE::pthread_barrier_destroy(&barrier);
}
-void reusable_barrier() {
+void reused_barrier_test() {
counter.set(0);
const int NUM_THREADS = 30;
const int REPEAT = 20;
- pthread_t threads[NUM_THREADS * REPEAT];
+ pthread_t threads[NUM_THREADS - 1]; // subtract 1 for main thread
+ LIBC_NAMESPACE::memset(&barrier, 0, sizeof(pthread_barrier_t));
ASSERT_EQ(
- LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, NUM_THREADS + 1),
- 0);
+ LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, NUM_THREADS), 0);
for (int i = 0; i < REPEAT; ++i) {
- for (int j = 0; j < NUM_THREADS; ++j)
- LIBC_NAMESPACE::pthread_create(&threads[NUM_THREADS * i + j], nullptr,
+ for (int j = 0; j < NUM_THREADS - 1; ++j)
+ LIBC_NAMESPACE::pthread_create(&threads[j], nullptr,
increment_counter_and_wait, nullptr);
- LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
+ uintptr_t return_val_sum =
+ reinterpret_cast<uintptr_t>(increment_counter_and_wait(nullptr));
ASSERT_EQ(counter.load(), NUM_THREADS * (i + 1));
- }
- for (int i = 0; i < NUM_THREADS * REPEAT; ++i)
- LIBC_NAMESPACE::pthread_join(threads[i], nullptr);
+ // verify only one thread got the PTHREAD_BARRIER_SERIAL_THREAD return value
+ for (int i = 0; i < NUM_THREADS - 1; ++i) {
+ void *ret;
+ LIBC_NAMESPACE::pthread_join(threads[i], &ret);
+ if (reinterpret_cast<uintptr_t>(ret) ==
+ static_cast<uintptr_t>(PTHREAD_BARRIER_SERIAL_THREAD)) {
+ return_val_sum += reinterpret_cast<uintptr_t>(ret);
+ } else {
+ ASSERT_EQ(ret, 0);
+ }
+ }
+ ASSERT_EQ(return_val_sum,
+ static_cast<uintptr_t>(PTHREAD_BARRIER_SERIAL_THREAD));
+ }
LIBC_NAMESPACE::pthread_barrier_destroy(&barrier);
}
@@ -89,29 +108,11 @@ void *barrier_wait(void *in) {
LIBC_NAMESPACE::pthread_barrier_wait(&barrier));
}
-// verify that only one of the wait() calls return PTHREAD_BARRIER_SERIAL_THREAD
-// with the rest returning 0
-void one_nonzero_wait_returnval() {
- const int NUM_THREADS = 30;
- pthread_t threads[NUM_THREADS];
- LIBC_NAMESPACE::pthread_barrier_init(&barrier, nullptr, NUM_THREADS + 1);
- for (int i = 0; i < NUM_THREADS; ++i)
- LIBC_NAMESPACE::pthread_create(&threads[i], nullptr, barrier_wait, nullptr);
-
- uintptr_t retsum = LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
- for (int i = 0; i < NUM_THREADS; ++i) {
- void *ret;
- LIBC_NAMESPACE::pthread_join(threads[i], &ret);
- retsum += reinterpret_cast<uintptr_t>(ret);
- }
-
- ASSERT_EQ(static_cast<int>(retsum), PTHREAD_BARRIER_SERIAL_THREAD);
-}
-
TEST_MAIN() {
- smoke_test();
- single_use_barrier();
- reusable_barrier();
- one_nonzero_wait_returnval();
+ // don't create any additional threads; only use main thread
+ single_use_barrier_test(1);
+
+ single_use_barrier_test(30);
+ reused_barrier_test();
return 0;
}
>From 1a828f403477d63b986bae8fd1deb9c3f269270b Mon Sep 17 00:00:00 2001
From: Uzair Nawaz <uzairnawaz at google.com>
Date: Tue, 22 Jul 2025 21:46:16 +0000
Subject: [PATCH 10/10] formatting
---
libc/hdr/pthread_macros.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/hdr/pthread_macros.h b/libc/hdr/pthread_macros.h
index b0bab73687e3b..f913015abd31c 100644
--- a/libc/hdr/pthread_macros.h
+++ b/libc/hdr/pthread_macros.h
@@ -1,4 +1,4 @@
-//===-- Definition of macros from pthread.h ----------------------------------===//
+//===-- Definition of macros from pthread.h -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
More information about the libc-commits
mailing list