[libc-commits] [libc] 2a5d507 - [libc] Add the pthread_mutex_t type.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Tue May 24 15:48:35 PDT 2022


Author: Siva Chandra Reddy
Date: 2022-05-24T22:48:14Z
New Revision: 2a5d5078d5dadb1aaa4487c89a92c91a98e2ed12

URL: https://github.com/llvm/llvm-project/commit/2a5d5078d5dadb1aaa4487c89a92c91a98e2ed12
DIFF: https://github.com/llvm/llvm-project/commit/2a5d5078d5dadb1aaa4487c89a92c91a98e2ed12.diff

LOG: [libc] Add the pthread_mutex_t type.

Simple implementations of the functions pthread_mutex_init,
pthread_mutex_destroy, pthread_mutex_lock and pthread_mutex_unlock have
have also been added. Future patches will extend these functions to add
features required by the POSIX specification.

Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D126235

Added: 
    libc/include/llvm-libc-types/pthread_mutex_t.h
    libc/src/pthread/pthread_mutex_destroy.cpp
    libc/src/pthread/pthread_mutex_destroy.h
    libc/src/pthread/pthread_mutex_init.cpp
    libc/src/pthread/pthread_mutex_init.h
    libc/src/pthread/pthread_mutex_lock.cpp
    libc/src/pthread/pthread_mutex_lock.h
    libc/src/pthread/pthread_mutex_unlock.cpp
    libc/src/pthread/pthread_mutex_unlock.h
    libc/test/src/pthread/pthread_mutex_test.cpp

Modified: 
    libc/config/linux/api.td
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/CMakeLists.txt
    libc/include/llvm-libc-types/CMakeLists.txt
    libc/include/llvm-libc-types/__mutex_type.h
    libc/spec/posix.td
    libc/src/pthread/CMakeLists.txt
    libc/src/pthread/pthread_mutexattr.h
    libc/test/src/pthread/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index c99e35e5f2f28..6862139d66c31 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -241,6 +241,7 @@ def ThreadsAPI : PublicAPI<"threads.h"> {
 def PThreadAPI : PublicAPI<"pthread.h"> {
   let Types = [
       "pthread_attr_t",
+      "pthread_mutex_t",
       "pthread_mutexattr_t"
   ];
 }

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a0b7a6b5af225..99937c7ebe592 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -236,6 +236,10 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_attr_setstack
     libc.src.pthread.pthread_attr_setstacksize
     libc.src.pthread.pthread_attr_init
+    libc.src.pthread.pthread_mutex_destroy
+    libc.src.pthread.pthread_mutex_init
+    libc.src.pthread.pthread_mutex_lock
+    libc.src.pthread.pthread_mutex_unlock
     libc.src.pthread.pthread_mutexattr_destroy
     libc.src.pthread.pthread_mutexattr_init
     libc.src.pthread.pthread_mutexattr_getpshared

diff  --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index d011d6d6f59be..5ffef44cbc62e 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -163,6 +163,7 @@ add_gen_header(
   DEPENDS
     .llvm_libc_common_h
     .llvm-libc-types.pthread_attr_t
+    .llvm-libc-types.pthread_mutex_t
     .llvm-libc-types.pthread_mutexattr_t
 )
 

diff  --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 3a5c17f4e29c1..681f7aa63fd28 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -20,7 +20,8 @@ add_header(mtx_t HDR mtx_t.h DEPENDS .__futex_word .__mutex_type)
 add_header(off_t HDR off_t.h)
 add_header(off64_t HDR off64_t.h)
 add_header(once_flag HDR once_flag.h DEPENDS .__futex_word)
-add_header(pthread_attr_t HDR pthread_attr_t.h)
+add_header(pthread_attr_t HDR pthread_attr_t.h DEPENDS .size_t)
+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(size_t HDR size_t.h)
 add_header(ssize_t HDR ssize_t.h)

diff  --git a/libc/include/llvm-libc-types/__mutex_type.h b/libc/include/llvm-libc-types/__mutex_type.h
index 37cb856fd58b8..ffd67e7c7bc33 100644
--- a/libc/include/llvm-libc-types/__mutex_type.h
+++ b/libc/include/llvm-libc-types/__mutex_type.h
@@ -6,6 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+#ifndef __LLVM_LIBC_TYPES___MUTEX_T_H
+#define __LLVM_LIBC_TYPES___MUTEX_T_H
+
 #include <llvm-libc-types/__futex_word.h>
 
 typedef struct {
@@ -22,3 +25,5 @@ typedef struct {
 #error "Mutex type not defined for the target platform."
 #endif
 } __mutex_type;
+
+#endif // __LLVM_LIBC_TYPES___MUTEX_T_H

diff  --git a/libc/include/llvm-libc-types/pthread_mutex_t.h b/libc/include/llvm-libc-types/pthread_mutex_t.h
new file mode 100644
index 0000000000000..65e43538cd27d
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_mutex_t.h
@@ -0,0 +1,16 @@
+//===-- Definition of pthread_mutex_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_MUTEX_T_H
+#define __LLVM_LIBC_TYPES_PTHREAD_MUTEX_T_H
+
+#include <llvm-libc-types/__mutex_type.h>
+
+typedef __mutex_type pthread_mutex_t;
+
+#endif // __LLVM_LIBC_TYPES_PTHREAD_MUTEX_T_H

diff  --git a/libc/spec/posix.td b/libc/spec/posix.td
index fbb6a78225dd8..2436d8eea4b1c 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -33,6 +33,12 @@ def POSIX : StandardSpec<"POSIX"> {
   ConstType ConstPThreadMutexAttrTPtr = ConstType<PThreadMutexAttrTPtr>;
   ConstType ConstRestrictedPThreadMutexAttrTPtr = ConstType<RestrictedPThreadMutexAttrTPtr>;
 
+  NamedType PThreadMutexTType = NamedType<"pthread_mutex_t">;
+  PtrType PThreadMutexTPtr = PtrType<PThreadMutexTType>;
+  RestrictedPtrType RestrictedPThreadMutexTPtr = RestrictedPtrType<PThreadMutexTType>;
+  ConstType ConstPThreadMutexTPtr = ConstType<PThreadMutexTPtr>;
+  ConstType ConstRestrictedPThreadMutexTPtr = ConstType<RestrictedPThreadMutexTPtr>;
+
   HeaderSpec Errno = HeaderSpec<
       "errno.h",
       [
@@ -386,7 +392,7 @@ def POSIX : StandardSpec<"POSIX"> {
   HeaderSpec PThread = HeaderSpec<
     "pthread.h",
     [], // Macros
-    [PThreadAttrTType, PThreadMutexAttrTType], // Types
+    [PThreadAttrTType, PThreadMutexAttrTType, PThreadMutexTType], // Types
     [], // Enumerations
     [
       FunctionSpec<
@@ -499,6 +505,26 @@ def POSIX : StandardSpec<"POSIX"> {
           RetValSpec<IntType>,
           [ArgSpec<RestrictedPThreadMutexAttrTPtr>, ArgSpec<IntType>]
       >,
+      FunctionSpec<
+          "pthread_mutex_init",
+          RetValSpec<IntType>,
+          [ArgSpec<RestrictedPThreadMutexTPtr>, ArgSpec<ConstRestrictedPThreadMutexAttrTPtr>]
+      >,
+      FunctionSpec<
+          "pthread_mutex_destroy",
+          RetValSpec<IntType>,
+          [ArgSpec<PThreadMutexTPtr>]
+      >,
+      FunctionSpec<
+          "pthread_mutex_lock",
+          RetValSpec<IntType>,
+          [ArgSpec<PThreadMutexTPtr>]
+      >,
+      FunctionSpec<
+          "pthread_mutex_unlock",
+          RetValSpec<IntType>,
+          [ArgSpec<PThreadMutexTPtr>]
+      >,
     ]
   >;
 

diff  --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index 5d447baef08a6..ca5f0e0433cb5 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -196,3 +196,49 @@ add_entrypoint_object(
     libc.include.errno
     libc.include.pthread
 )
+
+add_entrypoint_object(
+  pthread_mutex_init
+  SRCS
+    pthread_mutex_init.cpp
+  HDRS
+    pthread_mutex_init.h
+  DEPENDS
+    .pthread_mutexattr
+    libc.include.errno
+    libc.include.pthread
+    libc.src.__support.threads.mutex
+)
+
+add_entrypoint_object(
+  pthread_mutex_destroy
+  SRCS
+    pthread_mutex_destroy.cpp
+  HDRS
+    pthread_mutex_destroy.h
+  DEPENDS
+    libc.include.pthread
+    libc.src.__support.threads.mutex
+)
+
+add_entrypoint_object(
+  pthread_mutex_lock
+  SRCS
+    pthread_mutex_lock.cpp
+  HDRS
+    pthread_mutex_lock.h
+  DEPENDS
+    libc.include.pthread
+    libc.src.__support.threads.mutex
+)
+
+add_entrypoint_object(
+  pthread_mutex_unlock
+  SRCS
+    pthread_mutex_unlock.cpp
+  HDRS
+    pthread_mutex_unlock.h
+  DEPENDS
+    libc.include.pthread
+    libc.src.__support.threads.mutex
+)

diff  --git a/libc/src/pthread/pthread_mutex_destroy.cpp b/libc/src/pthread/pthread_mutex_destroy.cpp
new file mode 100644
index 0000000000000..acb344bbea52f
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_destroy.cpp
@@ -0,0 +1,26 @@
+//===-- Linux implementation of the pthread_mutex_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_mutex_destroy.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/mutex.h"
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, pthread_mutex_destroy, (pthread_mutex_t * mutex)) {
+  auto *m = reinterpret_cast<Mutex *>(mutex);
+  Mutex::destroy(m);
+  // TODO: When the Mutex class supports all the possible error conditions
+  // return the appropriate error value here.
+  return 0;
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/pthread/pthread_mutex_destroy.h b/libc/src/pthread/pthread_mutex_destroy.h
new file mode 100644
index 0000000000000..bd6ea1932c1b6
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_destroy.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_mutex_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_MUTEX__DESTROY_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX__DESTROY_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_mutex_destroy(pthread_mutex_t *mutex);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_DESTROY_H

diff  --git a/libc/src/pthread/pthread_mutex_init.cpp b/libc/src/pthread/pthread_mutex_init.cpp
new file mode 100644
index 0000000000000..5038ee0887593
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_init.cpp
@@ -0,0 +1,35 @@
+//===-- Linux implementation of the pthread_mutex_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/threads/mutex.h"
+
+#include <errno.h>
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+static_assert(sizeof(Mutex) <= sizeof(pthread_mutex_t),
+              "The public pthread_mutex_t type cannot accommodate the internal "
+              "mutex type.");
+
+LLVM_LIBC_FUNCTION(int, pthread_mutex_init,
+                   (pthread_mutex_t * m,
+                    const pthread_mutexattr_t *__restrict attr)) {
+  auto mutexattr = attr == nullptr ? DEFAULT_MUTEXATTR : *attr;
+  auto err =
+      Mutex::init(reinterpret_cast<Mutex *>(m), false,
+                  get_mutexattr_type(mutexattr) & PTHREAD_MUTEX_RECURSIVE,
+                  get_mutexattr_robust(mutexattr) & PTHREAD_MUTEX_ROBUST);
+  return err == MutexError::NONE ? 0 : EAGAIN;
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/pthread/pthread_mutex_init.h b/libc/src/pthread/pthread_mutex_init.h
new file mode 100644
index 0000000000000..d25fe8968cd63
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_init.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pthread_mutex_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_MUTEX_INIT_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_INIT_H
+
+#include "include/pthread.h"
+
+namespace __llvm_libc {
+
+int pthread_mutex_init(pthread_mutex_t *mutex,
+                       const pthread_mutexattr_t *__restrict attr);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_pthread_mutex_INIT_H

diff  --git a/libc/src/pthread/pthread_mutex_lock.cpp b/libc/src/pthread/pthread_mutex_lock.cpp
new file mode 100644
index 0000000000000..9daffafff942f
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_lock.cpp
@@ -0,0 +1,26 @@
+//===-- Linux implementation of the pthread_mutex_lock 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_lock.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/mutex.h"
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+// The implementation currently handles only plain mutexes.
+LLVM_LIBC_FUNCTION(int, pthread_mutex_lock, (pthread_mutex_t * mutex)) {
+  reinterpret_cast<Mutex *>(mutex)->lock();
+  // TODO: When the Mutex class supports all the possible error conditions
+  // return the appropriate error value here.
+  return 0;
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/pthread/pthread_mutex_lock.h b/libc/src/pthread/pthread_mutex_lock.h
new file mode 100644
index 0000000000000..bb47e59809698
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_lock.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_mutex_lock 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_MUTEX_LOCK_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_LOCK_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_mutex_lock(pthread_mutex_t *mutex);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_LOCK_H

diff  --git a/libc/src/pthread/pthread_mutex_unlock.cpp b/libc/src/pthread/pthread_mutex_unlock.cpp
new file mode 100644
index 0000000000000..3cc8c7cdac09b
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_unlock.cpp
@@ -0,0 +1,26 @@
+//===-- Linux implementation of the pthread_mutex_unlock 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_unlock.h"
+
+#include "src/__support/common.h"
+#include "src/__support/threads/mutex.h"
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+// The implementation currently handles only plain mutexes.
+LLVM_LIBC_FUNCTION(int, pthread_mutex_unlock, (pthread_mutex_t * mutex)) {
+  reinterpret_cast<Mutex *>(mutex)->unlock();
+  // TODO: When the Mutex class supports all the possible error conditions
+  // return the appropriate error value here.
+  return 0;
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/pthread/pthread_mutex_unlock.h b/libc/src/pthread/pthread_mutex_unlock.h
new file mode 100644
index 0000000000000..4653841244eb7
--- /dev/null
+++ b/libc/src/pthread/pthread_mutex_unlock.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for pthread_mutex_unlock 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_MUTEX_UNLOCK_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_UNLOCK_H
+
+#include <pthread.h>
+
+namespace __llvm_libc {
+
+int pthread_mutex_unlock(pthread_mutex_t *mutex);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_UNLOCK_H

diff  --git a/libc/src/pthread/pthread_mutexattr.h b/libc/src/pthread/pthread_mutexattr.h
index 4f969e288c881..98f9ff9067e44 100644
--- a/libc/src/pthread/pthread_mutexattr.h
+++ b/libc/src/pthread/pthread_mutexattr.h
@@ -31,6 +31,16 @@ constexpr pthread_mutexattr_t DEFAULT_MUTEXATTR =
     PTHREAD_MUTEX_STALLED << unsigned(PThreadMutexAttrPos::ROBUST_SHIFT) |
     PTHREAD_PROCESS_PRIVATE << unsigned(PThreadMutexAttrPos::PSHARED_SHIFT);
 
+static inline int get_mutexattr_type(pthread_mutexattr_t attr) {
+  return (attr & unsigned(PThreadMutexAttrPos::TYPE_MASK)) >>
+         unsigned(PThreadMutexAttrPos::TYPE_SHIFT);
+}
+
+static inline int get_mutexattr_robust(pthread_mutexattr_t attr) {
+  return (attr & unsigned(PThreadMutexAttrPos::ROBUST_MASK)) >>
+         unsigned(PThreadMutexAttrPos::ROBUST_SHIFT);
+}
+
 } // namespace __llvm_libc
 
 #endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEXATTR_H

diff  --git a/libc/test/src/pthread/CMakeLists.txt b/libc/test/src/pthread/CMakeLists.txt
index db0516cecc4fd..5f3bbcbdd9a36 100644
--- a/libc/test/src/pthread/CMakeLists.txt
+++ b/libc/test/src/pthread/CMakeLists.txt
@@ -39,3 +39,20 @@ add_libc_unittest(
     libc.src.pthread.pthread_mutexattr_setrobust
     libc.src.pthread.pthread_mutexattr_settype
 )
+
+add_libc_unittest(
+  phtread_mutex_test
+  SUITE
+    libc_pthread_unittests
+  SRCS
+    pthread_mutex_test.cpp
+  DEPENDS
+    libc.include.pthread
+    libc.src.errno.errno
+    libc.src.pthread.pthread_mutex_destroy
+    libc.src.pthread.pthread_mutex_init
+    libc.src.pthread.pthread_mutex_lock
+    libc.src.pthread.pthread_mutex_unlock
+    libc.src.threads.thrd_create
+    libc.src.threads.thrd_join
+)

diff  --git a/libc/test/src/pthread/pthread_mutex_test.cpp b/libc/test/src/pthread/pthread_mutex_test.cpp
new file mode 100644
index 0000000000000..8b06294169ed6
--- /dev/null
+++ b/libc/test/src/pthread/pthread_mutex_test.cpp
@@ -0,0 +1,188 @@
+//===-- Unittests for pthread_mutex_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_mutex_destroy.h"
+#include "src/pthread/pthread_mutex_init.h"
+#include "src/pthread/pthread_mutex_lock.h"
+#include "src/pthread/pthread_mutex_unlock.h"
+
+// TODO: When pthread_t type is available, use it to spawn threads instead of
+// thrd_t.
+#include "src/threads/thrd_create.h"
+#include "src/threads/thrd_join.h"
+
+#include "utils/UnitTest/Test.h"
+
+#include <pthread.h>
+
+constexpr int START = 0;
+constexpr int MAX = 10000;
+
+pthread_mutex_t mutex;
+static int shared_int = START;
+
+int counter(void *arg) {
+  int last_count = START;
+  while (true) {
+    __llvm_libc::pthread_mutex_lock(&mutex);
+    if (shared_int == last_count + 1) {
+      shared_int++;
+      last_count = shared_int;
+    }
+    __llvm_libc::pthread_mutex_unlock(&mutex);
+    if (last_count >= MAX)
+      break;
+  }
+  return 0;
+}
+
+TEST(LlvmLibcMutexTest, RelayCounter) {
+  ASSERT_EQ(__llvm_libc::pthread_mutex_init(&mutex, nullptr), 0);
+
+  // The idea of this test is that two competing threads will update
+  // a counter only if the other thread has updated it.
+  thrd_t thread;
+  __llvm_libc::thrd_create(&thread, counter, nullptr);
+
+  int last_count = START;
+  while (true) {
+    ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&mutex), 0);
+    if (shared_int == START) {
+      ++shared_int;
+      last_count = shared_int;
+    } else if (shared_int != last_count) {
+      ASSERT_EQ(shared_int, last_count + 1);
+      ++shared_int;
+      last_count = shared_int;
+    }
+    ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&mutex), 0);
+    if (last_count > MAX)
+      break;
+  }
+
+  int retval = 123;
+  __llvm_libc::thrd_join(&thread, &retval);
+  ASSERT_EQ(retval, 0);
+
+  __llvm_libc::pthread_mutex_destroy(&mutex);
+}
+
+pthread_mutex_t start_lock, step_lock;
+bool started, step;
+
+int stepper(void *arg) {
+  __llvm_libc::pthread_mutex_lock(&start_lock);
+  started = true;
+  __llvm_libc::pthread_mutex_unlock(&start_lock);
+
+  __llvm_libc::pthread_mutex_lock(&step_lock);
+  step = true;
+  __llvm_libc::pthread_mutex_unlock(&step_lock);
+  return 0;
+}
+
+TEST(LlvmLibcMutexTest, WaitAndStep) {
+  ASSERT_EQ(__llvm_libc::pthread_mutex_init(&start_lock, nullptr), 0);
+  ASSERT_EQ(__llvm_libc::pthread_mutex_init(&step_lock, nullptr), 0);
+
+  // In this test, we start a new thread but block it before it can make a
+  // step. Once we ensure that the thread is blocked, we unblock it.
+  // After unblocking, we then verify that the thread was indeed unblocked.
+  step = false;
+  started = false;
+  ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0);
+
+  thrd_t thread;
+  __llvm_libc::thrd_create(&thread, stepper, nullptr);
+
+  while (true) {
+    // Make sure the thread actually started.
+    ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&start_lock), 0);
+    bool s = started;
+    ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&start_lock), 0);
+    if (s)
+      break;
+  }
+
+  // Since |step_lock| is still locked, |step| should be false.
+  ASSERT_FALSE(step);
+
+  // Unlock the step lock and wait until the step is made.
+  ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&step_lock), 0);
+
+  while (true) {
+    ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0);
+    bool current_step_value = step;
+    ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&step_lock), 0);
+    if (current_step_value)
+      break;
+  }
+
+  int retval = 123;
+  __llvm_libc::thrd_join(&thread, &retval);
+  ASSERT_EQ(retval, 0);
+
+  __llvm_libc::pthread_mutex_destroy(&start_lock);
+  __llvm_libc::pthread_mutex_destroy(&step_lock);
+}
+
+static constexpr int THREAD_COUNT = 10;
+static pthread_mutex_t multiple_waiter_lock;
+static pthread_mutex_t counter_lock;
+static int wait_count = 0;
+
+int waiter_func(void *) {
+  __llvm_libc::pthread_mutex_lock(&counter_lock);
+  ++wait_count;
+  __llvm_libc::pthread_mutex_unlock(&counter_lock);
+
+  // Block on the waiter lock until the main
+  // thread unblocks.
+  __llvm_libc::pthread_mutex_lock(&multiple_waiter_lock);
+  __llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock);
+
+  __llvm_libc::pthread_mutex_lock(&counter_lock);
+  --wait_count;
+  __llvm_libc::pthread_mutex_unlock(&counter_lock);
+
+  return 0;
+}
+
+TEST(LlvmLibcMutexTest, MultipleWaiters) {
+  __llvm_libc::pthread_mutex_init(&multiple_waiter_lock, nullptr);
+  __llvm_libc::pthread_mutex_init(&counter_lock, nullptr);
+
+  __llvm_libc::pthread_mutex_lock(&multiple_waiter_lock);
+  thrd_t waiters[THREAD_COUNT];
+  for (int i = 0; i < THREAD_COUNT; ++i) {
+    __llvm_libc::thrd_create(waiters + i, waiter_func, nullptr);
+  }
+
+  // Spin until the counter is incremented to the desired
+  // value.
+  while (true) {
+    __llvm_libc::pthread_mutex_lock(&counter_lock);
+    if (wait_count == THREAD_COUNT) {
+      __llvm_libc::pthread_mutex_unlock(&counter_lock);
+      break;
+    }
+    __llvm_libc::pthread_mutex_unlock(&counter_lock);
+  }
+
+  __llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock);
+
+  int retval;
+  for (int i = 0; i < THREAD_COUNT; ++i) {
+    __llvm_libc::thrd_join(waiters + i, &retval);
+  }
+
+  ASSERT_EQ(wait_count, 0);
+
+  __llvm_libc::pthread_mutex_destroy(&multiple_waiter_lock);
+  __llvm_libc::pthread_mutex_destroy(&counter_lock);
+}


        


More information about the libc-commits mailing list