chromium/third_party/angle/src/common/SimpleMutex.h

//
// 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_