92 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			92 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #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>;
 | |
| }
 |