[libc-commits] [libc] [libc][pthreads] pthread_cond_{destroy|init|signal|wait} (PR #88583)

Nick Desaulniers via libc-commits libc-commits at lists.llvm.org
Fri Apr 12 14:30:10 PDT 2024


https://github.com/nickdesaulniers created https://github.com/llvm/llvm-project/pull/88583

Basic support for pthread condition variables. Does not support:
- pthread_cond_{timedwait|broadcast}
- non-nullptr pthread_condattr_t values for pthread_cond_init

Relies on the existing CndVar, which should be moved from
libc/src/threads/linux/CndVar.h to libc/src/__support/threads/.

Link: #85282
Link: #88580
Link: #88581
Link: #88582


>From ad27cf171f1604a526a406ce8fb6840b9023c781 Mon Sep 17 00:00:00 2001
From: Nick Desaulniers <ndesaulniers at google.com>
Date: Fri, 12 Apr 2024 11:40:06 -0700
Subject: [PATCH] [libc][pthreads] pthread_cond_{destroy|init|signal|wait}

Basic support for pthread condition variables. Does not support:
- pthread_cond_{timedwait|broadcast}
- non-nullptr pthread_condattr_t values for pthread_cond_init

Relies on the existing CndVar, which should be moved from
libc/src/threads/linux/CndVar.h to libc/src/__support/threads/.

Link: #85282
Link: #88580
Link: #88581
Link: #88582
---
 libc/config/linux/api.td                      | 31 +++++++--
 libc/config/linux/x86_64/entrypoints.txt      |  4 ++
 libc/include/CMakeLists.txt                   |  2 +
 libc/include/llvm-libc-types/CMakeLists.txt   |  2 +
 libc/include/llvm-libc-types/pthread_cond_t.h | 19 ++++++
 .../llvm-libc-types/pthread_condattr_t.h      | 15 ++++
 libc/spec/posix.td                            | 52 +++++++++++++-
 libc/src/pthread/CMakeLists.txt               | 48 +++++++++++++
 libc/src/pthread/pthread_cond_destroy.cpp     | 30 ++++++++
 libc/src/pthread/pthread_cond_destroy.h       | 20 ++++++
 libc/src/pthread/pthread_cond_init.cpp        | 37 ++++++++++
 libc/src/pthread/pthread_cond_init.h          | 20 ++++++
 libc/src/pthread/pthread_cond_signal.cpp      | 35 ++++++++++
 libc/src/pthread/pthread_cond_signal.h        | 20 ++++++
 libc/src/pthread/pthread_cond_wait.cpp        | 37 ++++++++++
 libc/src/pthread/pthread_cond_wait.h          | 20 ++++++
 .../integration/src/pthread/CMakeLists.txt    | 20 ++++++
 .../src/pthread/pthread_cond_test.cpp         | 68 +++++++++++++++++++
 18 files changed, 473 insertions(+), 7 deletions(-)
 create mode 100644 libc/include/llvm-libc-types/pthread_cond_t.h
 create mode 100644 libc/include/llvm-libc-types/pthread_condattr_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
 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_wait.cpp
 create mode 100644 libc/src/pthread/pthread_cond_wait.h
 create mode 100644 libc/test/integration/src/pthread/pthread_cond_test.cpp

diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 9964971f191b75..c9d562a37f2dfc 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -175,6 +175,8 @@ def PThreadAPI : PublicAPI<"pthread.h"> {
       "__pthread_start_t",
       "__pthread_tss_dtor_t",
       "pthread_attr_t",
+      "pthread_cond_t",
+      "pthread_condattr_t",
       "pthread_mutex_t",
       "pthread_mutexattr_t",
       "pthread_t",
@@ -241,10 +243,31 @@ def SysSendfileAPI : PublicAPI<"sys/sendfile.h"> {
 }
 
 def SysTypesAPI : PublicAPI<"sys/types.h"> {
-  let Types = ["blkcnt_t", "blksize_t", "clockid_t", "dev_t", "gid_t", "ino_t",
-               "mode_t", "nlink_t", "off_t", "pid_t", "pthread_attr_t", "pthread_key_t",
-               "pthread_mutex_t", "pthread_mutexattr_t", "pthread_once_t", "pthread_t",
-               "size_t", "ssize_t", "suseconds_t", "time_t", "uid_t"];
+  let Types = [
+    "blkcnt_t",
+    "blksize_t",
+    "clockid_t",
+    "dev_t",
+    "gid_t",
+    "ino_t",
+    "mode_t",
+    "nlink_t",
+    "off_t",
+    "pid_t",
+    "pthread_attr_t",
+    "pthread_cond_t",
+    "pthread_condattr_t",
+    "pthread_key_t",
+    "pthread_mutex_t",
+    "pthread_mutexattr_t",
+    "pthread_once_t",
+    "pthread_t",
+    "size_t",
+    "ssize_t",
+    "suseconds_t",
+    "time_t",
+    "uid_t",
+  ];
 }
 
 def SysUtsNameAPI : PublicAPI<"sys/utsname.h"> {
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 6bb53cb76220fc..45e92ece6da6b4 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -634,6 +634,10 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_attr_setguardsize
     libc.src.pthread.pthread_attr_setstack
     libc.src.pthread.pthread_attr_setstacksize
+    libc.src.pthread.pthread_cond_destroy
+    libc.src.pthread.pthread_cond_init
+    libc.src.pthread.pthread_cond_signal
+    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/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 02c7dc8fbc0b33..c0cbb752f694c0 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -321,6 +321,8 @@ add_gen_header(
     .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_mutex_t
     .llvm-libc-types.pthread_mutexattr_t
     .llvm-libc-types.pthread_t
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 93a79e1477b337..90239ccf9c10f9 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -51,6 +51,8 @@ add_header(posix_spawnattr_t HDR posix_spawnattr_t.h)
 add_header(pthread_attr_t HDR pthread_attr_t.h DEPENDS .size_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_cond_t HDR pthread_cond_t.h DEPENDS .pthread_mutex_t)
+add_header(pthread_condattr_t HDR pthread_condattr_t.h)
 add_header(pthread_t HDR pthread_t.h DEPENDS .__thread_type)
 add_header(pthread_mutexattr_t HDR pthread_mutexattr_t.h)
 add_header(pthread_once_t HDR pthread_once_t.h DEPENDS .__futex_word)
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 00000000000000..60ca0ca6164c61
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_cond_t.h
@@ -0,0 +1,19 @@
+//===-- 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 "pthread_mutex_t.h"
+
+typedef struct {
+  void *__qfront;
+  void *__qback;
+  pthread_mutex_t __mtx;
+} pthread_cond_t;
+
+#endif // LLVM_LIBC_TYPES_PTHREAD_COND_T_H
diff --git a/libc/include/llvm-libc-types/pthread_condattr_t.h b/libc/include/llvm-libc-types/pthread_condattr_t.h
new file mode 100644
index 00000000000000..19d5f9ecf6f7cb
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_condattr_t.h
@@ -0,0 +1,15 @@
+//===-- Definition of pthread_condattr_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_CONDATTR_T_H
+#define LLVM_LIBC_TYPES_PTHREAD_CONDATTR_T_H
+
+typedef struct {
+  int pshared;
+} pthread_condattr_t;
+
+#endif // LLVM_LIBC_TYPES_PTHREAD_CONDATTR_T_H
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 45f7ecfe84e98e..fe0c90239d613d 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -117,6 +117,11 @@ def POSIX : StandardSpec<"POSIX"> {
   ConstType ConstPThreadMutexTPtr = ConstType<PThreadMutexTPtr>;
   ConstType ConstRestrictedPThreadMutexTPtr = ConstType<RestrictedPThreadMutexTPtr>;
 
+  NamedType PThreadCondTType = NamedType<"pthread_cond_t">;
+  PtrType PThreadCondTPtr = PtrType<PThreadCondTType>;
+  NamedType PThreadCondAttrTType = NamedType<"pthread_condattr_t">;
+  PtrType PThreadCondAttrTPtr = PtrType<PThreadCondAttrTType>;
+
   PtrType PThreadTPtr = PtrType<PThreadTType>;
   RestrictedPtrType RestrictedPThreadTPtr = RestrictedPtrType<PThreadTType>;
 
@@ -976,6 +981,8 @@ def POSIX : StandardSpec<"POSIX"> {
     [
         AtForkCallbackT,
         PThreadAttrTType,
+        PThreadCondTType,
+        PThreadCondAttrTType,
         PThreadKeyT,
         PThreadMutexAttrTType,
         PThreadMutexTType,
@@ -1042,6 +1049,23 @@ def POSIX : StandardSpec<"POSIX"> {
           RetValSpec<IntType>,
           [ArgSpec<PThreadAttrTPtr>, ArgSpec<VoidPtr>, ArgSpec<SizeTType>]
       >,
+      FunctionSpec<
+          "pthread_cond_destroy",
+          RetValSpec<IntType>,
+          [ArgSpec<PThreadCondTPtr>]
+      >,
+      FunctionSpec<"pthread_cond_init",
+          RetValSpec<IntType>,
+          [ArgSpec<PThreadCondTPtr>, ArgSpec<PThreadCondAttrTPtr>]
+      >,
+      FunctionSpec<"pthread_cond_signal",
+          RetValSpec<IntType>,
+          [ArgSpec<PThreadCondTPtr>]
+      >,
+      FunctionSpec<"pthread_cond_wait",
+          RetValSpec<IntType>,
+          [ArgSpec<PThreadCondTPtr>, ArgSpec<PThreadMutexTPtr>]
+      >,
       FunctionSpec<
           "pthread_create",
           RetValSpec<IntType>,
@@ -1517,9 +1541,31 @@ def POSIX : StandardSpec<"POSIX"> {
   HeaderSpec SysTypes = HeaderSpec<
     "sys/types.h",
     [], // Macros
-    [BlkCntT, BlkSizeT, ClockIdT, DevT, GidT, InoT, ModeTType, NLinkT, OffTType, PidT,
-     PThreadAttrTType, PThreadKeyT, PThreadMutexTType, PThreadMutexAttrTType, PThreadOnceT, PThreadTType,
-     SizeTType, SSizeTType, SuSecondsT, TimeTType, UidT],
+    [
+      BlkCntT,
+      BlkSizeT,
+      ClockIdT,
+      DevT,
+      GidT,
+      InoT,
+      ModeTType,
+      NLinkT,
+      OffTType,
+      PThreadAttrTType,
+      PThreadCondAttrTType,
+      PThreadCondTType,
+      PThreadKeyT,
+      PThreadMutexAttrTType,
+      PThreadMutexTType,
+      PThreadOnceT,
+      PThreadTType,
+      PidT,
+      SSizeTType,
+      SizeTType,
+      SuSecondsT,
+      TimeTType,
+      UidT
+    ], // Types
     [], // Enumerations
     []  // Functions
   >;
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index d5e6c802a84523..c467803d5ca044 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -266,6 +266,54 @@ add_entrypoint_object(
     -fno-omit-frame-pointer
 )
 
+add_entrypoint_object(
+  pthread_cond_destroy
+  SRCS
+    pthread_cond_destroy.cpp
+  HDRS
+    pthread_cond_destroy.h
+  DEPENDS
+    libc.include.errno
+    libc.include.pthread
+    libc.include.threads
+)
+
+add_entrypoint_object(
+  pthread_cond_init
+  SRCS
+    pthread_cond_init.cpp
+  HDRS
+    pthread_cond_init.h
+  DEPENDS
+    libc.include.errno
+    libc.include.pthread
+    libc.include.threads
+)
+
+add_entrypoint_object(
+  pthread_cond_signal
+  SRCS
+    pthread_cond_signal.cpp
+  HDRS
+    pthread_cond_signal.h
+  DEPENDS
+    libc.include.errno
+    libc.include.pthread
+    libc.include.threads
+)
+
+add_entrypoint_object(
+  pthread_cond_wait
+  SRCS
+    pthread_cond_wait.cpp
+  HDRS
+    pthread_cond_wait.h
+  DEPENDS
+    libc.include.errno
+    libc.include.pthread
+    libc.include.threads
+)
+
 add_entrypoint_object(
   pthread_join
   SRCS
diff --git a/libc/src/pthread/pthread_cond_destroy.cpp b/libc/src/pthread/pthread_cond_destroy.cpp
new file mode 100644
index 00000000000000..f2038df1a64fe6
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_destroy.cpp
@@ -0,0 +1,30 @@
+//===-- Linux implementation of the pthread_cond_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_cond_destroy.h"
+
+#include "include/llvm-libc-macros/generic-error-number-macros.h" // EINVAL
+#include "src/__support/common.h"
+#include "src/threads/linux/CndVar.h"
+
+#include <pthread.h> // pthread_cond_t
+// TODO: https://github.com/llvm/llvm-project/issues/88580
+#include <threads.h> // thrd_success
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_destroy, (pthread_cond_t * cond)) {
+  if (!cond)
+    return EINVAL;
+
+  CndVar *C = reinterpret_cast<CndVar *>(cond);
+  CndVar::destroy(C);
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/pthread/pthread_cond_destroy.h b/libc/src/pthread/pthread_cond_destroy.h
new file mode 100644
index 00000000000000..5a987e3f8b3c17
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_destroy.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_cond_destroy function -*- 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 <pthread.h>
+
+namespace LIBC_NAMESPACE {
+
+int pthread_cond_destroy(pthread_cond_t *cond);
+
+} // namespace LIBC_NAMESPACE
+
+#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 00000000000000..d3bb78925c9cf9
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_init.cpp
@@ -0,0 +1,37 @@
+//===-- Linux 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/generic-error-number-macros.h" // EINVAL
+#include "src/__support/common.h"
+#include "src/threads/linux/CndVar.h"
+
+#include <pthread.h> // pthread_cond_t, pthread_condattr_t
+// TODO: https://github.com/llvm/llvm-project/issues/88580
+#include <threads.h> // thrd_succes
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_init,
+                   (pthread_cond_t * cond, const pthread_condattr_t *attr)) {
+  // TODO: properly support pthread_condattr_t.
+  // https://github.com/llvm/llvm-project/issues/88582
+  if (attr)
+    return EINVAL;
+
+  CndVar *C = reinterpret_cast<CndVar *>(cond);
+  int ret = CndVar::init(C);
+  if (ret == thrd_success)
+    return 0;
+
+  // TODO: translate error codes?
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/pthread/pthread_cond_init.h b/libc/src/pthread/pthread_cond_init.h
new file mode 100644
index 00000000000000..2365ae3597175e
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_init.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_cond_init function ----*- 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 <pthread.h>
+
+namespace LIBC_NAMESPACE {
+
+int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_INIT_H
diff --git a/libc/src/pthread/pthread_cond_signal.cpp b/libc/src/pthread/pthread_cond_signal.cpp
new file mode 100644
index 00000000000000..b770d7119015c4
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_signal.cpp
@@ -0,0 +1,35 @@
+//===-- Linux implementation of the pthread_cond_signal 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_signal.h"
+
+#include "include/llvm-libc-macros/generic-error-number-macros.h" // EINVAL
+#include "src/__support/common.h"
+#include "src/threads/linux/CndVar.h"
+
+#include <pthread.h> // pthread_cond_t
+// TODO: https://github.com/llvm/llvm-project/issues/88580
+#include <threads.h> // thrd_success
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_signal, (pthread_cond_t * cond)) {
+  if (!cond)
+    return EINVAL;
+
+  CndVar *C = reinterpret_cast<CndVar *>(cond);
+  int ret = C->notify_one();
+
+  if (ret == thrd_success)
+    return 0;
+
+  // TODO: translate error codes.
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/pthread/pthread_cond_signal.h b/libc/src/pthread/pthread_cond_signal.h
new file mode 100644
index 00000000000000..56b3e04a6e2399
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_signal.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_cond_signal function --*- 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 <pthread.h>
+
+namespace LIBC_NAMESPACE {
+
+int pthread_cond_signal(pthread_cond_t *cond);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_SIGNAL_H
diff --git a/libc/src/pthread/pthread_cond_wait.cpp b/libc/src/pthread/pthread_cond_wait.cpp
new file mode 100644
index 00000000000000..dbc4f8ccf3e767
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_wait.cpp
@@ -0,0 +1,37 @@
+//===-- Linux implementation of the pthread_cond_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_cond_wait.h"
+
+#include "include/llvm-libc-macros/generic-error-number-macros.h" // EINVAL
+#include "src/__support/common.h"
+#include "src/threads/linux/CndVar.h"
+
+#include <pthread.h> // pthread_cond_t, pthread_mutex_t
+// TODO: https://github.com/llvm/llvm-project/issues/88580
+#include <threads.h> // thrd_success
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, pthread_cond_wait,
+                   (pthread_cond_t * cond, pthread_mutex_t *mutex)) {
+  if (!cond || !mutex)
+    return EINVAL;
+
+  auto *C = reinterpret_cast<CndVar *>(cond);
+  auto *M = reinterpret_cast<Mutex *>(mutex);
+  int ret = C->wait(M);
+
+  if (ret == thrd_success)
+    return 0;
+
+  // TODO translate error codes
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/pthread/pthread_cond_wait.h b/libc/src/pthread/pthread_cond_wait.h
new file mode 100644
index 00000000000000..809cc49c9f4da6
--- /dev/null
+++ b/libc/src/pthread/pthread_cond_wait.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_cond_wait function ----*- 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 <pthread.h>
+
+namespace LIBC_NAMESPACE {
+
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_WAIT_H
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index a10dc256200d9f..0ddbfd0c796780 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -161,3 +161,23 @@ add_integration_test(
     libc.src.__support.CPP.array
     libc.src.__support.CPP.new
 )
+
+add_integration_test(
+  pthread_cond_test
+  SUITE
+    libc-pthread-integration-tests
+  SRCS
+    pthread_cond_test.cpp
+  DEPENDS
+    libc.include.pthread
+    libc.src.pthread.pthread_cond_destroy
+    libc.src.pthread.pthread_cond_init
+    libc.src.pthread.pthread_cond_signal
+    libc.src.pthread.pthread_cond_wait
+    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
+)
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 00000000000000..4ab9ffd9b9b64f
--- /dev/null
+++ b/libc/test/integration/src/pthread/pthread_cond_test.cpp
@@ -0,0 +1,68 @@
+// TODO: license block
+
+#include "test/IntegrationTest/test.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_wait.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 <pthread.h>
+
+pthread_mutex_t waiter_mtx, main_thread_mtx;
+pthread_cond_t waiter_cnd, main_thread_cnd;
+
+void *waiter_thread_func(void *) {
+  LIBC_NAMESPACE::pthread_mutex_lock(&waiter_mtx);
+
+  LIBC_NAMESPACE::pthread_mutex_lock(&main_thread_mtx);
+  LIBC_NAMESPACE::pthread_cond_signal(&main_thread_cnd);
+  LIBC_NAMESPACE::pthread_mutex_unlock(&main_thread_mtx);
+
+  LIBC_NAMESPACE::pthread_cond_wait(&waiter_cnd, &waiter_mtx);
+  LIBC_NAMESPACE::pthread_mutex_unlock(&waiter_mtx);
+
+  return reinterpret_cast<void *>(0x600D);
+}
+
+void single_waiter_test() {
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&waiter_mtx, nullptr), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_init(&main_thread_mtx, nullptr), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_init(&waiter_cnd, nullptr), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_init(&main_thread_cnd, nullptr), 0);
+
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&main_thread_mtx), 0);
+
+  pthread_t waiter_thread;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&waiter_thread, nullptr,
+                                           waiter_thread_func, nullptr),
+            0);
+
+  ASSERT_EQ(
+      LIBC_NAMESPACE::pthread_cond_wait(&main_thread_cnd, &main_thread_mtx), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&main_thread_mtx), 0);
+
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_lock(&waiter_mtx), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_signal(&waiter_cnd), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_unlock(&waiter_mtx), 0);
+
+  void *retval;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_join(waiter_thread, &retval), 0);
+  ASSERT_EQ(reinterpret_cast<long>(retval), 0x600D);
+
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_destroy(&waiter_mtx), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_mutex_destroy(&main_thread_mtx), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_destroy(&waiter_cnd), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_cond_destroy(&main_thread_cnd), 0);
+}
+
+TEST_MAIN() {
+  single_waiter_test();
+  return 0;
+}



More information about the libc-commits mailing list