// // Copyright 2024 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // SimpleMutex.h: // A simple non-recursive mutex that only supports lock and unlock operations. As such, it can be // implemented more efficiently than a generic mutex such as std::mutex. In the uncontended // paths, the implementation boils down to basically an inlined atomic operation and an untaken // branch. The implementation in this file is inspired by Mesa's src/util/simple_mtx.h, which in // turn is based on "mutex3" in: // // "Futexes Are Tricky" // http://www.akkadia.org/drepper/futex.pdf // // Given that std::condition_variable only interacts with std::mutex, SimpleMutex cannot be used // with condition variables. // #ifndef COMMON_SIMPLEMUTEX_H_ #define COMMON_SIMPLEMUTEX_H_ #include "common/log_utils.h" #include "common/platform.h" #include <atomic> #include <mutex> // Enable futexes on: // // - Linux and derivatives (Android, ChromeOS, etc) // - Windows 8+ // // There is no TSAN support for futex currently, so it is disabled in that case #if !defined(ANGLE_WITH_TSAN) # if defined(ANGLE_PLATFORM_LINUX) || defined(ANGLE_PLATFORM_ANDROID) // Linux has had futexes for a very long time. Assume support. #define ANGLE_USE_FUTEX … # elif defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_ENABLE_WINDOWS_UWP) && \ !defined(ANGLE_WINDOWS_NO_FUTEX) // Windows has futexes since version 8, which is already end of life (let alone older versions). // Assume support. #define ANGLE_USE_FUTEX … # endif // defined(ANGLE_PLATFORM_LINUX) || defined(ANGLE_PLATFORM_ANDROID) #endif // !defined(ANGLE_WITH_TSAN) namespace angle { namespace priv { #if ANGLE_USE_FUTEX class MutexOnFutex { … }; #else // !ANGLE_USE_FUTEX class MutexOnStd { public: void lock() { mutex.lock(); } void unlock() { mutex.unlock(); } void assertLocked() { ASSERT(isLocked()); } private: bool isLocked() { // This works because angle::SimpleMutex does not support recursion const bool acquiredLock = mutex.try_lock(); if (acquiredLock) { mutex.unlock(); } return !acquiredLock; } std::mutex mutex; }; #endif // ANGLE_USE_FUTEX } // namespace priv #if ANGLE_USE_FUTEX SimpleMutex; #else using SimpleMutex = priv::MutexOnStd; #endif // A no-op mutex to replace SimpleMutex where a lock is not needed. struct NoOpMutex { … }; } // namespace angle #endif // COMMON_SIMPLEMUTEX_H_