|
|
@ -7,7 +7,7 @@ |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
#include <mutex>
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
|
|
|
|
#include <optional>
|
|
|
#include <xbyak/xbyak.h>
|
|
|
#include <xbyak/xbyak.h>
|
|
|
|
|
|
|
|
|
#include "dynarmic/backend/x64/abi.h"
|
|
|
#include "dynarmic/backend/x64/abi.h"
|
|
|
@ -42,43 +42,46 @@ void EmitSpinLockUnlock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
namespace { |
|
|
namespace { |
|
|
|
|
|
|
|
|
struct SpinLockImpl { |
|
|
struct SpinLockImpl { |
|
|
void Initialize(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Initialize() noexcept; |
|
|
|
|
|
static void GlobalInitialize() noexcept; |
|
|
Xbyak::CodeGenerator code = Xbyak::CodeGenerator(4096, default_cg_mode); |
|
|
Xbyak::CodeGenerator code = Xbyak::CodeGenerator(4096, default_cg_mode); |
|
|
|
|
|
|
|
|
void (*lock)(volatile int*); |
|
|
|
|
|
void (*unlock)(volatile int*); |
|
|
|
|
|
|
|
|
void (*lock)(volatile int*) = nullptr; |
|
|
|
|
|
void (*unlock)(volatile int*) = nullptr; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
std::once_flag flag; |
|
|
std::once_flag flag; |
|
|
SpinLockImpl impl; |
|
|
|
|
|
|
|
|
|
|
|
void SpinLockImpl::Initialize() { |
|
|
|
|
|
const Xbyak::Reg64 ABI_PARAM1 = Backend::X64::HostLocToReg64(Backend::X64::ABI_PARAM1); |
|
|
|
|
|
|
|
|
/// @brief Bear in mind that initializing the variable as-is on ctor time will trigger bugs
|
|
|
|
|
|
/// because some OSes do not prepare mprotect() properly at static ctor time
|
|
|
|
|
|
/// We can't really do anything about it, so just live with this fact
|
|
|
|
|
|
std::optional<SpinLockImpl> impl; |
|
|
|
|
|
|
|
|
|
|
|
void SpinLockImpl::Initialize() noexcept { |
|
|
|
|
|
Xbyak::Reg64 const ABI_PARAM1 = Backend::X64::HostLocToReg64(Backend::X64::ABI_PARAM1); |
|
|
code.align(); |
|
|
code.align(); |
|
|
lock = code.getCurr<void (*)(volatile int*)>(); |
|
|
lock = code.getCurr<void (*)(volatile int*)>(); |
|
|
EmitSpinLockLock(code, ABI_PARAM1, code.eax); |
|
|
EmitSpinLockLock(code, ABI_PARAM1, code.eax); |
|
|
code.ret(); |
|
|
code.ret(); |
|
|
|
|
|
|
|
|
code.align(); |
|
|
code.align(); |
|
|
unlock = code.getCurr<void (*)(volatile int*)>(); |
|
|
unlock = code.getCurr<void (*)(volatile int*)>(); |
|
|
EmitSpinLockUnlock(code, ABI_PARAM1, code.eax); |
|
|
EmitSpinLockUnlock(code, ABI_PARAM1, code.eax); |
|
|
code.ret(); |
|
|
code.ret(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void SpinLockImpl::GlobalInitialize() noexcept { |
|
|
|
|
|
impl.emplace(); |
|
|
|
|
|
impl->Initialize(); |
|
|
|
|
|
} |
|
|
} // namespace
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
void SpinLock::Lock() noexcept { |
|
|
void SpinLock::Lock() noexcept { |
|
|
std::call_once(flag, &SpinLockImpl::Initialize, impl); |
|
|
|
|
|
impl.lock(&storage); |
|
|
|
|
|
|
|
|
std::call_once(flag, &SpinLockImpl::GlobalInitialize); |
|
|
|
|
|
impl->lock(&storage); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void SpinLock::Unlock() noexcept { |
|
|
void SpinLock::Unlock() noexcept { |
|
|
std::call_once(flag, &SpinLockImpl::Initialize, impl); |
|
|
|
|
|
impl.unlock(&storage); |
|
|
|
|
|
|
|
|
std::call_once(flag, &SpinLockImpl::GlobalInitialize); |
|
|
|
|
|
impl->unlock(&storage); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} // namespace Dynarmic
|
|
|
} // namespace Dynarmic
|