[libc-commits] [libc] a1aba84 - [libc] Reland #148948 "Implement barriers for pthreads" (#151021)
via libc-commits
libc-commits at lists.llvm.org
Tue Jul 29 09:39:45 PDT 2025
Author: Uzair Nawaz
Date: 2025-07-29T16:39:40Z
New Revision: a1aba84c2bc23d98a25e265678dd4752f78c5b3f
URL: https://github.com/llvm/llvm-project/commit/a1aba84c2bc23d98a25e265678dd4752f78c5b3f
DIFF: https://github.com/llvm/llvm-project/commit/a1aba84c2bc23d98a25e265678dd4752f78c5b3f.diff
LOG: [libc] Reland #148948 "Implement barriers for pthreads" (#151021)
Fixed build dependencies for pthread_barrier_t (add __barrier_type to
cmake dependencies)
Added:
libc/hdr/pthread_macros.h
libc/hdr/types/pthread_barrier_t.h
libc/hdr/types/pthread_barrierattr_t.h
libc/include/llvm-libc-types/__barrier_type.h
libc/include/llvm-libc-types/pthread_barrier_t.h
libc/include/llvm-libc-types/pthread_barrierattr_t.h
libc/src/__support/threads/linux/barrier.cpp
libc/src/__support/threads/linux/barrier.h
libc/src/pthread/pthread_barrier_destroy.cpp
libc/src/pthread/pthread_barrier_destroy.h
libc/src/pthread/pthread_barrier_init.cpp
libc/src/pthread/pthread_barrier_init.h
libc/src/pthread/pthread_barrier_wait.cpp
libc/src/pthread/pthread_barrier_wait.h
libc/test/integration/src/pthread/pthread_barrier_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/hdr/CMakeLists.txt
libc/hdr/types/CMakeLists.txt
libc/include/CMakeLists.txt
libc/include/llvm-libc-macros/pthread-macros.h
libc/include/llvm-libc-types/CMakeLists.txt
libc/include/pthread.yaml
libc/src/__support/threads/linux/CMakeLists.txt
libc/src/pthread/CMakeLists.txt
libc/test/integration/src/pthread/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 1fa63d67ca7d7..3ec05a57143f9 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1056,6 +1056,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/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index 5fc25d0ca5689..f3f01c1ed0e30 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..f913015abd31c
--- /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 c21236307a91d..1c1f242e84341 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -241,6 +241,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/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..d9d14c12e4de6
--- /dev/null
+++ b/libc/hdr/types/pthread_barrierattr_t.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from pthread_barrierattr_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/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 120f3850b5cee..74fcea0f15e2f 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -392,6 +392,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/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/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 4ccdde619a39e..451beae6f1e6f 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)
@@ -53,6 +54,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 DEPENDS .__barrier_type)
+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/__barrier_type.h b/libc/include/llvm-libc-types/__barrier_type.h
new file mode 100644
index 0000000000000..59712619e917d
--- /dev/null
+++ b/libc/include/llvm-libc-types/__barrier_type.h
@@ -0,0 +1,21 @@
+//===-- Definition of __barrier_type 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
new file mode 100644
index 0000000000000..86fbf7c116652
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_barrier_t.h
@@ -0,0 +1,15 @@
+//===-- 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
+
+#include "__barrier_type.h"
+typedef __barrier_type 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/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/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt
index cbb788645a139..14aaad214f43a 100644
--- a/libc/src/__support/threads/linux/CMakeLists.txt
+++ b/libc/src/__support/threads/linux/CMakeLists.txt
@@ -124,3 +124,14 @@ add_object_library(
libc.src.__support.threads.linux.raw_mutex
libc.src.__support.CPP.mutex
)
+
+add_object_library(
+ barrier
+ HDRS
+ barrier.h
+ SRCS
+ barrier.cpp
+ DEPENDS
+ libc.src.__support.threads.CndVar
+ libc.src.__support.threads.mutex
+)
diff --git a/libc/src/__support/threads/linux/barrier.cpp b/libc/src/__support/threads/linux/barrier.cpp
new file mode 100644
index 0000000000000..cf7207b53094b
--- /dev/null
+++ b/libc/src/__support/threads/linux/barrier.cpp
@@ -0,0 +1,85 @@
+//===-- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/threads/linux/barrier.h"
+#include "hdr/errno_macros.h"
+#include "src/__support/threads/CndVar.h"
+#include "src/__support/threads/mutex.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int Barrier::init(Barrier *b,
+ [[maybe_unused]] const pthread_barrierattr_t *attr,
+ unsigned count) {
+ LIBC_ASSERT(attr == nullptr); // TODO implement barrierattr
+ 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;
+
+ auto mutex_err = Mutex::init(&b->m, false, false, false, false);
+ if (mutex_err != MutexError::NONE)
+ return EAGAIN;
+
+ 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) {
+ // 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--;
+
+ if (waiting == 0) {
+ // all threads have exited the barrier, let's let the ones waiting to enter
+ // continue
+ blocking = true;
+ entering.broadcast();
+ m.unlock();
+
+ // 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();
+
+ return 0;
+}
+
+int Barrier::destroy(Barrier *b) {
+ CndVar::destroy(&b->entering);
+ CndVar::destroy(&b->exiting);
+ Mutex::destroy(&b->m);
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/threads/linux/barrier.h b/libc/src/__support/threads/linux/barrier.h
new file mode 100644
index 0000000000000..f0655bfc52a10
--- /dev/null
+++ b/libc/src/__support/threads/linux/barrier.h
@@ -0,0 +1,50 @@
+//===-- 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 "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/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();
+};
+
+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
diff erent 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/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index c5db6fa910db7..fe31e6a915e7b 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -272,6 +272,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.linux.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.linux.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.linux.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
new file mode 100644
index 0000000000000..82de8f2741862
--- /dev/null
+++ b/libc/src/pthread/pthread_barrier_destroy.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of the pthread_barrier_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_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/linux/barrier.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..e27552ce7e5ae
--- /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 "hdr/types/pthread_barrier_t.h"
+#include "src/__support/macros/config.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..2e92238a49243
--- /dev/null
+++ b/libc/src/pthread/pthread_barrier_init.cpp
@@ -0,0 +1,26 @@
+//===-- 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_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/linux/barrier.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+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..bb17f3f5664da
--- /dev/null
+++ b/libc/src/pthread/pthread_barrier_init.h
@@ -0,0 +1,24 @@
+//===-- 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 "hdr/types/pthread_barrier_t.h"
+#include "hdr/types/pthread_barrierattr_t.h"
+#include "src/__support/macros/config.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..dbd1333a2aa3b
--- /dev/null
+++ b/libc/src/pthread/pthread_barrier_wait.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of the pthread_barrier_wait 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_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/linux/barrier.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, pthread_barrier_wait, (pthread_barrier_t * b)) {
+ 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..16ddc06f5be6d
--- /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 "hdr/types/pthread_barrier_t.h"
+#include "src/__support/macros/config.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/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index 0bdd99c253fe1..251b009994ab5 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -18,6 +18,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
new file mode 100644
index 0000000000000..c8e11047e1d80
--- /dev/null
+++ b/libc/test/integration/src/pthread/pthread_barrier_test.cpp
@@ -0,0 +1,117 @@
+//===-- 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/__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/string/memset.h"
+
+#include "test/IntegrationTest/test.h"
+
+#include <pthread.h>
+
+pthread_barrier_t barrier;
+LIBC_NAMESPACE::cpp::Atomic<int> counter;
+
+void *increment_counter_and_wait(void *args) {
+ counter.fetch_add(1);
+ return reinterpret_cast<void *>(
+ LIBC_NAMESPACE::pthread_barrier_wait(&barrier));
+}
+
+void single_use_barrier_test(int num_threads) {
+ counter.set(0);
+ // 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), 0);
+
+ for (int i = 0; i < num_threads - 1; ++i)
+ LIBC_NAMESPACE::pthread_create(&threads[i], nullptr,
+ increment_counter_and_wait, nullptr);
+
+ uintptr_t return_val_sum =
+ reinterpret_cast<uintptr_t>(increment_counter_and_wait(nullptr));
+ ASSERT_EQ(counter.load(), num_threads);
+
+ // 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 reused_barrier_test() {
+ counter.set(0);
+ const int NUM_THREADS = 30;
+ const int REPEAT = 20;
+ 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), 0);
+
+ for (int i = 0; i < REPEAT; ++i) {
+ for (int j = 0; j < NUM_THREADS - 1; ++j)
+ LIBC_NAMESPACE::pthread_create(&threads[j], nullptr,
+ increment_counter_and_wait, nullptr);
+
+ uintptr_t return_val_sum =
+ reinterpret_cast<uintptr_t>(increment_counter_and_wait(nullptr));
+ ASSERT_EQ(counter.load(), NUM_THREADS * (i + 1));
+
+ // 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 *barrier_wait(void *in) {
+ return reinterpret_cast<void *>(
+ LIBC_NAMESPACE::pthread_barrier_wait(&barrier));
+}
+
+TEST_MAIN() {
+ // 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;
+}
More information about the libc-commits
mailing list