Skip to content

[libc] add spin lock family functions #100509

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 7, 2024

Conversation

SchrodingerZhu
Copy link
Contributor

@SchrodingerZhu SchrodingerZhu commented Jul 25, 2024

This PR:

  • add entrypoints for pthread_spin_*
  • additionally, the fixes a typo that has been disabling lock related tests

@SchrodingerZhu SchrodingerZhu marked this pull request as ready for review July 27, 2024 05:02
@llvmbot llvmbot added the libc label Jul 27, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 27, 2024

@llvm/pr-subscribers-libc

Author: Schrodinger ZHU Yifan (SchrodingerZhu)

Changes

TODO:

  • add test cases

Patch is 25.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/100509.diff

20 Files Affected:

  • (modified) libc/config/linux/aarch64/entrypoints.txt (+5)
  • (modified) libc/config/linux/api.td (+1)
  • (modified) libc/docs/dev/undefined_behavior.rst (+9)
  • (modified) libc/include/CMakeLists.txt (+1)
  • (modified) libc/include/llvm-libc-types/CMakeLists.txt (+1)
  • (added) libc/include/llvm-libc-types/pthread_spinlock_t.h (+17)
  • (modified) libc/newhdrgen/yaml/pthread.yaml (+26)
  • (modified) libc/spec/posix.td (+29)
  • (modified) libc/src/__support/threads/spin_lock.h (+10-26)
  • (modified) libc/src/pthread/CMakeLists.txt (+65)
  • (added) libc/src/pthread/pthread_spin_destroy.cpp (+46)
  • (added) libc/src/pthread/pthread_spin_destroy.h (+22)
  • (added) libc/src/pthread/pthread_spin_init.cpp (+33)
  • (added) libc/src/pthread/pthread_spin_init.h (+21)
  • (added) libc/src/pthread/pthread_spin_lock.cpp (+45)
  • (added) libc/src/pthread/pthread_spin_lock.h (+21)
  • (added) libc/src/pthread/pthread_spin_trylock.cpp (+39)
  • (added) libc/src/pthread/pthread_spin_trylock.h (+22)
  • (added) libc/src/pthread/pthread_spin_unlock.cpp (+42)
  • (added) libc/src/pthread/pthread_spin_unlock.h (+22)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 2334fed773702..bf3a31fc5afb9 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -707,6 +707,11 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_rwlockattr_init
     libc.src.pthread.pthread_rwlockattr_setkind_np
     libc.src.pthread.pthread_rwlockattr_setpshared
+    libc.src.pthread.pthread_spin_destroy
+    libc.src.pthread.pthread_spin_init
+    libc.src.pthread.pthread_spin_lock
+    libc.src.pthread.pthread_spin_trylock
+    libc.src.pthread.pthread_spin_unlock
     libc.src.pthread.pthread_self
     libc.src.pthread.pthread_setname_np
     libc.src.pthread.pthread_setspecific
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 320f3e92183bf..6a7c64296bf92 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -143,6 +143,7 @@ def PThreadAPI : PublicAPI<"pthread.h"> {
       "pthread_once_t",
       "pthread_rwlockattr_t",
       "pthread_rwlock_t",
+      "pthread_spinlock_t",
       "pthread_t",
   ];
 }
diff --git a/libc/docs/dev/undefined_behavior.rst b/libc/docs/dev/undefined_behavior.rst
index b712780222aa3..49574bc32d2cd 100644
--- a/libc/docs/dev/undefined_behavior.rst
+++ b/libc/docs/dev/undefined_behavior.rst
@@ -116,3 +116,12 @@ inherited from parent process triggered inside the instruction window between ``
 and ``exec*``. As libc failed to maintain its internal states correctly, even though the
 functions used inside the signal handlers are marked as ``async-signal-safe`` (such as
 ``getpid``), they will still return wrong values or lead to other even worse situations.
+
+PThread SpinLock Destroy
+------------------------
+POSIX.1 Issue 7 updates the spinlock destroy behavior description such that the return code for
+uninitialized spinlock and invalid spinlock is left undefined. We follow the recommendation as in
+POSIX.1-2024, where EINVAL is returned if the spinlock is invalid (here we only check for null pointers) or
+EBUSY is returned if the spinlock is currently locked. The lock is poisoned after a successful destroy. That is,
+subsequent operations on the lock object without any reinitialization will return EINVAL.
+
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 37cae19123318..cbde24e17619f 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -386,6 +386,7 @@ add_header_macro(
     .llvm-libc-types.pthread_once_t
     .llvm-libc-types.pthread_rwlock_t
     .llvm-libc-types.pthread_rwlockattr_t
+    .llvm-libc-types.pthread_spinlock_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 d8b975572e0dd..9e77ab226ce6c 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -56,6 +56,7 @@ add_header(pthread_mutexattr_t HDR pthread_mutexattr_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)
+add_header(pthread_spinlock_t HDR pthread_spinlock_t.h DEPENDS .pid_t)
 add_header(pthread_t HDR pthread_t.h DEPENDS .__thread_type)
 add_header(rlim_t HDR rlim_t.h)
 add_header(time_t HDR time_t.h)
diff --git a/libc/include/llvm-libc-types/pthread_spinlock_t.h b/libc/include/llvm-libc-types/pthread_spinlock_t.h
new file mode 100644
index 0000000000000..03eb02dded9ef
--- /dev/null
+++ b/libc/include/llvm-libc-types/pthread_spinlock_t.h
@@ -0,0 +1,17 @@
+//===-- Definition of pthread_spinlock_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_SPINLOCK_T_H
+#define LLVM_LIBC_TYPES_PTHREAD_SPINLOCK_T_H
+#include "llvm-libc-types/pid_t.h"
+typedef struct {
+  unsigned char __lockword;
+  pid_t __owner;
+} pthread_spinlock_t;
+
+#endif // LLVM_LIBC_TYPES_PTHREAD_SPINLOCK_T_H
diff --git a/libc/newhdrgen/yaml/pthread.yaml b/libc/newhdrgen/yaml/pthread.yaml
index 292d91751e406..5cc8e0642444d 100644
--- a/libc/newhdrgen/yaml/pthread.yaml
+++ b/libc/newhdrgen/yaml/pthread.yaml
@@ -390,3 +390,29 @@ functions:
     return_type: int
     arguments:
       - type: pthread_rwlock_t *
+  - name: pthread_spin_init
+    standards: POSIX
+    return_type: int
+    arguments:
+      - type: pthread_spinlock_t *
+      - type: int
+  - name: pthread_spin_destroy
+    standards: POSIX
+    return_type: int
+    arguments:
+      - type: pthread_spinlock_t *
+  - name: pthread_spin_lock
+    standards: POSIX
+    return_type: int
+    arguments:
+      - type: pthread_spinlock_t *
+  - name: pthread_spin_trylock
+    standards: POSIX
+    return_type: int
+    arguments:
+      - type: pthread_spinlock_t *
+  - name: pthread_spin_unlock
+    standards: POSIX
+    return_type: int
+    arguments:
+      - type: pthread_spinlock_t *
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 48f743dff4e6f..2da004b1eae40 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -132,6 +132,9 @@ def POSIX : StandardSpec<"POSIX"> {
   PtrType PThreadRWLockTPtr = PtrType<PThreadRWLockTType>;
   RestrictedPtrType RestrictedPThreadRWLockTPtr = RestrictedPtrType<PThreadRWLockTType>;
 
+  NamedType PThreadSpinLockTType = NamedType<"pthread_spinlock_t">;
+  PtrType PThreadSpinLockTPtr = PtrType<PThreadSpinLockTType>;
+
   PtrType PThreadTPtr = PtrType<PThreadTType>;
   RestrictedPtrType RestrictedPThreadTPtr = RestrictedPtrType<PThreadTType>;
 
@@ -1039,6 +1042,7 @@ def POSIX : StandardSpec<"POSIX"> {
         PThreadOnceT,
         PThreadRWLockAttrTType,
         PThreadRWLockTType,
+        PThreadSpinLockTType,
         PThreadStartT,
         PThreadTSSDtorT,
         PThreadTType,
@@ -1340,6 +1344,31 @@ def POSIX : StandardSpec<"POSIX"> {
         RetValSpec<IntType>,
         [ArgSpec<PThreadRWLockTPtr>]
       >,
+      FunctionSpec<
+        "pthread_spin_init",
+        RetValSpec<IntType>,
+        [ArgSpec<PThreadSpinLockTPtr>, ArgSpec<IntType>]
+      >,
+      FunctionSpec<
+        "pthread_spin_destroy",
+        RetValSpec<IntType>,
+        [ArgSpec<PThreadSpinLockTPtr>]
+      >,
+      FunctionSpec<
+        "pthread_spin_lock",
+        RetValSpec<IntType>,
+        [ArgSpec<PThreadSpinLockTPtr>]
+      >,
+      FunctionSpec<
+        "pthread_spin_trylock",
+        RetValSpec<IntType>,
+        [ArgSpec<PThreadSpinLockTPtr>]
+      >,
+      FunctionSpec<
+        "pthread_spin_unlock",
+        RetValSpec<IntType>,
+        [ArgSpec<PThreadSpinLockTPtr>]
+      >
     ]
   >;
 
diff --git a/libc/src/__support/threads/spin_lock.h b/libc/src/__support/threads/spin_lock.h
index 8a36550568464..e176ad9eeac2a 100644
--- a/libc/src/__support/threads/spin_lock.h
+++ b/libc/src/__support/threads/spin_lock.h
@@ -11,26 +11,17 @@
 
 #include "src/__support/CPP/atomic.h"
 #include "src/__support/macros/attributes.h"
-#include "src/__support/macros/properties/architectures.h"
 #include "src/__support/threads/sleep.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-namespace spinlock {
-template <typename LockWord, typename Return>
-using AtomicOp = Return (cpp::Atomic<LockWord>::*)(LockWord, cpp::MemoryOrder,
-                                                   cpp::MemoryScope);
-}
-
-template <typename LockWord, spinlock::AtomicOp<LockWord, LockWord> Acquire,
-          spinlock::AtomicOp<LockWord, void> Release>
-class SpinLockAdaptor {
-  cpp::Atomic<LockWord> flag;
+class SpinLock {
+  cpp::Atomic<unsigned char> flag;
 
 public:
-  LIBC_INLINE constexpr SpinLockAdaptor() : flag{false} {}
+  LIBC_INLINE constexpr SpinLock() : flag{0} {}
   LIBC_INLINE bool try_lock() {
-    return !flag.*Acquire(static_cast<LockWord>(1), cpp::MemoryOrder::ACQUIRE);
+    return !flag.exchange(1u, cpp::MemoryOrder::ACQUIRE);
   }
   LIBC_INLINE void lock() {
     // clang-format off
@@ -60,22 +51,15 @@ class SpinLockAdaptor {
       while (flag.load(cpp::MemoryOrder::RELAXED))
         sleep_briefly();
   }
-  LIBC_INLINE void unlock() {
-    flag.*Release(static_cast<LockWord>(0), cpp::MemoryOrder::RELEASE);
+  LIBC_INLINE void unlock() { flag.store(0u, cpp::MemoryOrder::RELEASE); }
+  LIBC_INLINE bool is_locked() { return flag.load(cpp::MemoryOrder::ACQUIRE); }
+  LIBC_INLINE bool is_invalid() {
+    return flag.load(cpp::MemoryOrder::ACQUIRE) > 1;
   }
+  // poison the lock
+  LIBC_INLINE ~SpinLock() { flag.store(0xffu, cpp::MemoryOrder::RELEASE); }
 };
 
-// It is reported that atomic operations with higher-order semantics
-// lead to better performance on GPUs.
-#ifdef LIBC_TARGET_ARCH_IS_GPU
-using SpinLock =
-    SpinLockAdaptor<unsigned int, &cpp::Atomic<unsigned int>::fetch_or,
-                    &cpp::Atomic<unsigned int>::fetch_and>;
-#else
-using SpinLock = SpinLockAdaptor<bool, &cpp::Atomic<bool>::exchange,
-                                 &cpp::Atomic<bool>::store>;
-#endif
-
 } // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_SPIN_LOCK_H
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index dc748b22e0378..45dcd5ff6fd3f 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -622,6 +622,71 @@ add_entrypoint_object(
     libc.src.__support.threads.linux.rwlock
 )
 
+add_entrypoint_object(
+  pthread_spin_init
+  SRCS
+    pthread_spin_init.cpp
+  HDRS
+    pthread_spin_init.h
+  DEPENDS
+    libc.include.pthread
+    libc.src.__support.threads.spin_lock
+    libc.src.__support.threads.tid
+    libc.hdr.errno_macros
+)
+
+add_entrypoint_object(
+  pthread_spin_destroy
+  SRCS
+    pthread_spin_destroy.cpp
+  HDRS
+    pthread_spin_destroy.h
+  DEPENDS
+    libc.include.pthread
+    libc.src.__support.threads.spin_lock
+    libc.src.__support.threads.tid
+    libc.hdr.errno_macros
+)
+
+add_entrypoint_object(
+  pthread_spin_lock
+  SRCS
+    pthread_spin_lock.cpp
+  HDRS
+    pthread_spin_lock.h
+  DEPENDS
+    libc.include.pthread
+    libc.src.__support.threads.spin_lock
+    libc.src.__support.threads.tid
+    libc.hdr.errno_macros
+)
+
+add_entrypoint_object(
+  pthread_spin_trylock
+  SRCS
+    pthread_spin_trylock.cpp
+  HDRS
+    pthread_spin_trylock.h
+  DEPENDS
+    libc.include.pthread
+    libc.src.__support.threads.spin_lock
+    libc.src.__support.threads.tid
+    libc.hdr.errno_macros
+)
+
+add_entrypoint_object(
+  pthread_spin_unlock
+  SRCS
+    pthread_spin_unlock.cpp
+  HDRS
+    pthread_spin_unlock.h
+  DEPENDS
+    libc.include.pthread
+    libc.src.__support.threads.spin_lock
+    libc.src.__support.threads.tid
+    libc.hdr.errno_macros
+)
+
 add_entrypoint_object(
   pthread_once
   SRCS
diff --git a/libc/src/pthread/pthread_spin_destroy.cpp b/libc/src/pthread/pthread_spin_destroy.cpp
new file mode 100644
index 0000000000000..229dcb47c03ba
--- /dev/null
+++ b/libc/src/pthread/pthread_spin_destroy.cpp
@@ -0,0 +1,46 @@
+//===-- Implementation of pthread_spin_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 "src/pthread/pthread_spin_destroy.h"
+#include "hdr/errno_macros.h"
+#include "src/__support/common.h"
+#include "src/__support/threads/spin_lock.h"
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(sizeof(pthread_spinlock_t::__lockword) == sizeof(SpinLock) &&
+                  alignof(decltype(pthread_spinlock_t::__lockword)) ==
+                      alignof(SpinLock),
+              "pthread_spinlock_t::__lockword and SpinLock must be of the same "
+              "size and alignment");
+
+LLVM_LIBC_FUNCTION(int, pthread_spin_destroy,
+                   ([[maybe_unused]] pthread_spinlock_t * lock)) {
+  auto *spin_lock = reinterpret_cast<SpinLock *>(&lock->__lockword);
+  // Accroding to POSIX.1-2024:
+  // If an implementation detects that the value specified by the lock argument
+  // to pthread_spin_destroy() does not refer to an initialized spin lock
+  // object, it is recommended that the function should fail and report an
+  // [EINVAL] error.
+  if (!spin_lock || spin_lock->is_invalid())
+    return EINVAL;
+
+  // If an implementation detects that the value specified by the lock argument
+  // to pthread_spin_destroy() or pthread_spin_init() refers to a locked spin
+  // lock object, or detects that the value specified by the lock argument to
+  // pthread_spin_init() refers to an already initialized spin lock object, it
+  // is recommended that the function should fail and report an [EBUSY] error.
+  if (spin_lock->is_locked())
+    return EBUSY;
+
+  // poison the lock
+  spin_lock->~SpinLock();
+  lock->__owner = 0;
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_spin_destroy.h b/libc/src/pthread/pthread_spin_destroy.h
new file mode 100644
index 0000000000000..a6f38aac8da33
--- /dev/null
+++ b/libc/src/pthread/pthread_spin_destroy.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for pthread_spin_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_SPIN_DESTROY_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_SPIN_DESTROY_H
+
+#include "src/__support/macros/config.h"
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_spin_destroy(pthread_spinlock_t *lock);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_SPIN_DESTROY_H
diff --git a/libc/src/pthread/pthread_spin_init.cpp b/libc/src/pthread/pthread_spin_init.cpp
new file mode 100644
index 0000000000000..e399a20507e3b
--- /dev/null
+++ b/libc/src/pthread/pthread_spin_init.cpp
@@ -0,0 +1,33 @@
+//===-- Implementation of pthread_spin_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 "src/pthread/pthread_spin_init.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/common.h"
+#include "src/__support/threads/spin_lock.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(sizeof(pthread_spinlock_t::__lockword) == sizeof(SpinLock) &&
+                  alignof(decltype(pthread_spinlock_t::__lockword)) ==
+                      alignof(SpinLock),
+              "pthread_spinlock_t::__lockword and SpinLock must be of the same "
+              "size and alignment");
+
+LLVM_LIBC_FUNCTION(int, pthread_spin_init,
+                   (pthread_spinlock_t * lock, [[maybe_unused]] int pshared)) {
+  // The spin lock here is a simple atomic flag, so we don't need to do any
+  // special handling for pshared.
+  ::new (&lock->__lockword) SpinLock();
+  lock->__owner = 0;
+  // No memory allocation needed, hence always succeeds. POSIX.1-2024 does not
+  // specify checking on invalid lock or pshared values.
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_spin_init.h b/libc/src/pthread/pthread_spin_init.h
new file mode 100644
index 0000000000000..89f7e3adc82e9
--- /dev/null
+++ b/libc/src/pthread/pthread_spin_init.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pthread_spin_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_SPIN_INIT_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_SPIN_INIT_H
+
+#include "src/__support/macros/config.h"
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_SPIN_INIT_H
diff --git a/libc/src/pthread/pthread_spin_lock.cpp b/libc/src/pthread/pthread_spin_lock.cpp
new file mode 100644
index 0000000000000..d155eda620131
--- /dev/null
+++ b/libc/src/pthread/pthread_spin_lock.cpp
@@ -0,0 +1,45 @@
+//===-- Implementation of pthread_spin_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 "src/pthread/pthread_spin_lock.h"
+#include "hdr/errno_macros.h"
+#include "src/__support/common.h"
+#include "src/__support/threads/spin_lock.h"
+#include "src/__support/threads/tid.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(sizeof(pthread_spinlock_t::__lockword) == sizeof(SpinLock) &&
+                  alignof(decltype(pthread_spinlock_t::__lockword)) ==
+                      alignof(SpinLock),
+              "pthread_spinlock_t::__lockword and SpinLock must be of the same "
+              "size and alignment");
+
+LLVM_LIBC_FUNCTION(int, pthread_spin_lock, (pthread_spinlock_t * lock)) {
+  auto spin_lock = reinterpret_cast<SpinLock *>(&lock->__lockword);
+  // If an implementation detects that the value specified by the lock argument
+  // to pthread_spin_lock() or pthread_spin_trylock() does not refer to an
+  // initialized spin lock object, it is recommended that the function should
+  // fail and report an [EINVAL] error.
+  if (!spin_lock || spin_lock->is_invalid())
+    return EINVAL;
+
+  pid_t self_tid = gettid_inline();
+  // If an implementation detects that the value specified by the lock argument
+  // to pthread_spin_lock() refers to a spin lock object for which the calling
+  // thread already holds the lock, it is recommended that the function should
+  // fail and report an [EDEADLK] error.
+  if (lock->__owner == self_tid)
+    return EDEADLK;
+
+  spin_lock->lock();
+  lock->__owner = self_tid;
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_spin_lock.h b/libc/src/pthread/pthread_spin_lock.h
new file mode 100644
index 0000000000000..835aa858b25f8
--- /dev/null
+++ b/libc/src/pthread/pthread_spin_lock.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for pthread_spin_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_SPIN_LOCK_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_SPIN_LOCK_H
+
+#include "src/__support/macros/config.h"
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_spin_lock(pthread_spinlock_t *lock);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_SPIN_LOCK_H
diff --git a/libc/src/pthread/pthread_spin_trylock.cpp b/libc/src/pthread/pthread_spin_trylock.cpp
new file mode 100644
index 0000000000000..87ce870d2a367
--- /dev/null
+++ b/libc/src/pthread/pthread_spin_trylock.cpp
@@ -0,0 +1,39 @@
+//===-- Implementation of pthread_spin_trylock 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
+//
+//===-----------------------------------------------...
[truncated]

@SchrodingerZhu SchrodingerZhu requested review from jhuber6 and lntue July 27, 2024 05:04
@SchrodingerZhu SchrodingerZhu requested a review from lntue July 28, 2024 03:34
@SchrodingerZhu SchrodingerZhu force-pushed the libc/pthread_spin_lock branch from 7083aac to 2e9a60c Compare July 28, 2024 03:55
@SchrodingerZhu SchrodingerZhu force-pushed the libc/pthread_spin_lock branch from 2e9a60c to 7a3b6ca Compare August 3, 2024 05:21
@SchrodingerZhu
Copy link
Contributor Author

@lntue @jhuber6 I have updated this to follow up latest tid cache mechanism. Please take a look. Thank you!

#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_SPIN_DESTROY_H

#include "src/__support/macros/config.h"
#include <pthread.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any issues created for pthread's proxy headers yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess no. Such routines are hardly used in overlay mode. That is being said, I think we should open one as many implementations do support overlay mode.

@SchrodingerZhu SchrodingerZhu requested a review from lntue August 7, 2024 03:49
Copy link
Contributor

@lntue lntue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This is much clearer than the previous version!

@SchrodingerZhu SchrodingerZhu merged commit 03841e7 into llvm:main Aug 7, 2024
5 of 6 checks passed
@SchrodingerZhu SchrodingerZhu deleted the libc/pthread_spin_lock branch August 7, 2024 04:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants