[libc-commits] [libc] [libc] rework mutex (PR #92168)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Thu May 16 16:05:32 PDT 2024
================
@@ -0,0 +1,117 @@
+//===--- Implementation of a Linux RawMutex class ---------------*- 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___SUPPORT_THREADS_LINUX_RAW_MUTEX_H
+#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_RAW_MUTEX_H
+
+#include "futex_word.h"
+#include "src/__support/CPP/optional.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/threads/linux/futex_utils.h"
+#include "src/__support/threads/sleep.h"
+#include "src/__support/time/linux/abs_timeout.h"
+#ifdef LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY
+#include "src/__support/time/linux/monotonicity.h"
+#endif
+
+#ifndef LIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT
+#define LIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT 100
+#endif
+
+namespace LIBC_NAMESPACE {
+namespace internal {
+// Lock is a simple timable lock for internal usage.
+// This is separated from Mutex because this one does not need to consider
+// robustness and reentrancy. Also, this one has spin optimization for shorter
+// critical sections.
+class RawMutex {
+protected:
+ Futex futex;
+ LIBC_INLINE_VAR static constexpr FutexWordType UNLOCKED = 0b00;
+ LIBC_INLINE_VAR static constexpr FutexWordType LOCKED = 0b01;
+ LIBC_INLINE_VAR static constexpr FutexWordType IN_CONTENTION = 0b10;
+
+ LIBC_INLINE FutexWordType spin(uint_fast32_t spin_count) {
+ FutexWordType result;
+ for (;;) {
+ result = futex.load(cpp::MemoryOrder::RELAXED);
+ // spin until one of the following conditions is met:
+ // - the mutex is unlocked
+ // - the mutex is in contention
+ // - the spin count reaches 0
+ if (result != LOCKED || spin_count == 0)
+ return result;
+ // Pause the pipeline to avoid extraneous memory operations due to
+ // speculation.
+ sleep_briefly();
+ spin_count--;
+ };
+ }
+
+ // Return true if the lock is acquired. Return false if timeout happens before
+ // the lock is acquired.
+ [[gnu::cold]] LIBC_INLINE bool
+ lock_slow(cpp::optional<Futex::Timeout> timeout, bool is_pshared,
+ uint_fast32_t spin_count) {
+ FutexWordType state = spin(spin_count);
+ // Before go into contention state, try to grab the lock.
+ if (state == UNLOCKED &&
+ futex.compare_exchange_strong(state, LOCKED, cpp::MemoryOrder::ACQUIRE,
+ cpp::MemoryOrder::RELAXED))
+ return true;
+#ifdef LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY
+ if (timeout)
+ ensure_monotonicity(*timeout);
+#endif
+ for (;;) {
+ // Try to grab the lock if it is unlocked. Mark the contention flag if it
+ // is locked.
+ if (state != IN_CONTENTION &&
+ futex.exchange(IN_CONTENTION, cpp::MemoryOrder::ACQUIRE) == UNLOCKED)
+ return true;
+ // Contention persists. Park the thread and wait for further notification.
+ if (-ETIMEDOUT == futex.wait(IN_CONTENTION, timeout, is_pshared))
+ return false;
+ // Continue to spin after waking up.
+ state = spin(spin_count);
+ }
+ }
+
+ [[gnu::cold]] LIBC_INLINE void wake(bool is_pshared) {
+ futex.notify_one(is_pshared);
+ }
+
+public:
+ LIBC_INLINE static void init(RawMutex *mutex) { mutex->futex = UNLOCKED; }
+ LIBC_INLINE constexpr RawMutex() : futex(UNLOCKED) {}
+ LIBC_INLINE bool try_lock() {
+ FutexWordType expected = UNLOCKED;
+ // Use strong version since this is a one-time operation.
+ return futex.compare_exchange_strong(
+ expected, LOCKED, cpp::MemoryOrder::ACQUIRE, cpp::MemoryOrder::RELAXED);
+ }
+ LIBC_INLINE bool
+ lock(cpp::optional<Futex::Timeout> timeout = cpp::nullopt,
+ bool is_shared = false,
+ uint_fast32_t spin_count = LIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT) {
+ // Timeout will not be checked if immediate lock is possible.
+ return try_lock() || lock_slow(timeout, is_shared, spin_count);
----------------
SchrodingerZhu wrote:
fixed
https://github.com/llvm/llvm-project/pull/92168
More information about the libc-commits
mailing list