You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

91 lines
2.0 KiB

#pragma once
#include <atomic>
#include <mutex>
#ifdef __powerpc__
#include "../../arch/powerpc/include/uapi/asm/unistd.h"
#endif
// Simple spinlock mutex based on std::atomic_flag
// Compatible with std::lock_guard
namespace vlc
{
#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1310 && ( defined(_M_ARM) )
extern "C" void YieldProcessor();
#else
extern "C" void _mm_pause();
#endif
#endif
static inline void cpu_relax()
{
#if defined(__arc__) || defined(__mips__) || defined(__arm__) || defined(__powerpc__)
asm volatile("" ::: "memory");
#elif defined(__i386__) || defined(__x86_64__)
asm volatile("rep; nop" ::: "memory");
#elif defined(__aarch64__)
asm volatile("yield" ::: "memory");
#elif defined(__ia64__)
asm volatile ("hint @pause" ::: "memory");
#elif defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1310 && ( defined(_M_ARM) )
YieldProcessor();
#else
_mm_pause();
#endif
#endif
}
// Optimized Spinlock implementation
// Reference https://rigtorp.se/spinlock/
class Spinlock
{
public:
Spinlock() : m_lock(false)
{
}
Spinlock(const Spinlock&) = delete;
Spinlock& operator = (const Spinlock&) = delete;
void lock() noexcept
{
for (;;)
{
// Optimistically assume the lock is free on the first try
if (!m_lock.exchange(true, std::memory_order_acquire))
return;
while (m_lock.load(std::memory_order_relaxed))
{
// Hint CPU that we're in spin-wait loop
cpu_relax();
}
}
}
bool try_lock() noexcept
{
// Check first that we have free lock without CAS
// because CAS writes to destination memory even if comparison failed
// so we can reduce memory traffic just by prior checking for free lock
return !m_lock.load(std::memory_order_relaxed) &&
!m_lock.exchange(true, std::memory_order_acquire);
}
void unlock() noexcept
{
m_lock.store(false, std::memory_order_release);
}
private:
std::atomic<bool> m_lock;
};
using SpinlockGuard = std::lock_guard<Spinlock>;
}