blob: ed8340f7c69e7dc1e3ed9ef0e6eb4c8ecd4e96f8 [file] [log] [blame]
//===-- mutex.h -------------------------------------------------*- 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 SCUDO_MUTEX_H_
#define SCUDO_MUTEX_H_
#include "atomic_helpers.h"
#include "common.h"
namespace scudo {
class StaticSpinMutex {
public:
void init() { atomic_store_relaxed(&State, 0); }
void lock() {
if (tryLock())
return;
lockSlow();
}
bool tryLock() {
return atomic_exchange(&State, 1, memory_order_acquire) == 0;
}
void unlock() { atomic_store(&State, 0, memory_order_release); }
void checkLocked() { CHECK_EQ(atomic_load_relaxed(&State), 1); }
private:
atomic_u8 State;
void NOINLINE lockSlow() {
for (u32 I = 0;; I++) {
if (I < 10)
yieldProcessor(10);
else
yieldPlatform();
if (atomic_load_relaxed(&State) == 0 &&
atomic_exchange(&State, 1, memory_order_acquire) == 0)
return;
}
}
};
class SpinMutex : public StaticSpinMutex {
public:
SpinMutex() { init(); }
private:
SpinMutex(const SpinMutex &) = delete;
void operator=(const SpinMutex &) = delete;
};
class BlockingMutex {
public:
explicit constexpr BlockingMutex(LinkerInitialized) : OpaqueStorage{0} {}
BlockingMutex() { memset(this, 0, sizeof(*this)); }
void lock();
void unlock();
void checkLocked() {
atomic_u32 *M = reinterpret_cast<atomic_u32 *>(&OpaqueStorage);
CHECK_NE(MtxUnlocked, atomic_load_relaxed(M));
}
private:
static constexpr uint32_t MtxUnlocked = 0;
uptr OpaqueStorage[1];
};
template <typename MutexType> class GenericScopedLock {
public:
explicit GenericScopedLock(MutexType *M) : Mutex(M) { Mutex->lock(); }
~GenericScopedLock() { Mutex->unlock(); }
private:
MutexType *Mutex;
GenericScopedLock(const GenericScopedLock &) = delete;
void operator=(const GenericScopedLock &) = delete;
};
typedef GenericScopedLock<StaticSpinMutex> SpinMutexLock;
typedef GenericScopedLock<BlockingMutex> BlockingMutexLock;
} // namespace scudo
#endif // SCUDO_MUTEX_H_