Fix vm::lock_range wrong check

Minor header refactoring.
This commit is contained in:
Nekotekina 2020-11-03 07:18:42 +03:00
parent 8d5e119582
commit ba5ed5f380
9 changed files with 44 additions and 28 deletions

View File

@ -74,6 +74,7 @@
#include "sync.h"
#include "util/logs.hpp"
#include "Emu/Memory/vm_locking.h"
LOG_CHANNEL(sig_log, "SIG");
LOG_CHANNEL(sys_log, "SYS");

View File

@ -1,6 +1,7 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/Memory/vm_ptr.h"
#include "Emu/Memory/vm_locking.h"
#include "Emu/Cell/PPUFunction.h"
#include "Emu/Cell/ErrorCodes.h"
@ -1114,6 +1115,26 @@ DECLARE(lv2_obj::g_waiting);
thread_local DECLARE(lv2_obj::g_to_awake);
void lv2_obj::sleep(cpu_thread& cpu, const u64 timeout)
{
vm::temporary_unlock(cpu);
std::lock_guard{g_mutex}, sleep_unlocked(cpu, timeout);
g_to_awake.clear();
}
bool lv2_obj::awake(cpu_thread* const thread, s32 prio)
{
vm::temporary_unlock();
std::lock_guard lock(g_mutex);
return awake_unlocked(thread, prio);
}
bool lv2_obj::yield(cpu_thread& thread)
{
vm::temporary_unlock(thread);
return awake(&thread, yield_cmd);
}
void lv2_obj::sleep_unlocked(cpu_thread& thread, u64 timeout)
{
const u64 start_time = get_guest_system_time();

View File

@ -6,6 +6,7 @@
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/PPUCallback.h"
#include "Emu/Memory/vm_locking.h"
#include "sys_event.h"
#include "sys_process.h"
#include "sys_mmapper.h"

View File

@ -3,6 +3,7 @@
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Memory/vm_locking.h"
#include "Emu/RSX/RSXThread.h"
#include "sys_event.h"

View File

@ -4,7 +4,6 @@
#include "Utilities/sema.h"
#include "Utilities/cond.h"
#include "Emu/Memory/vm_locking.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/IdManager.h"
@ -156,26 +155,12 @@ private:
static bool awake_unlocked(cpu_thread*, s32 prio = enqueue_cmd);
public:
static void sleep(cpu_thread& cpu, const u64 timeout = 0)
{
vm::temporary_unlock(cpu);
std::lock_guard{g_mutex}, sleep_unlocked(cpu, timeout);
g_to_awake.clear();
}
static void sleep(cpu_thread& cpu, const u64 timeout = 0);
static inline bool awake(cpu_thread* const thread, s32 prio = enqueue_cmd)
{
vm::temporary_unlock();
std::lock_guard lock(g_mutex);
return awake_unlocked(thread, prio);
}
static bool awake(cpu_thread* const thread, s32 prio = enqueue_cmd);
// Returns true on successful context switch, false otherwise
static bool yield(cpu_thread& thread)
{
vm::temporary_unlock(thread);
return awake(&thread, yield_cmd);
}
static bool yield(cpu_thread& thread);
static void set_priority(cpu_thread& thread, s32 prio)
{

View File

@ -166,29 +166,29 @@ namespace vm
for (u64 i = 0;; i++)
{
const u64 lock_val = g_range_lock.load();
const u64 is_shared = g_shareable[begin >> 16].load();
const u64 lock_addr = static_cast<u32>(lock_val); // -> u64
const u32 lock_size = static_cast<u32>(lock_val >> 35);
u64 addr = begin;
// See range_lock()
if (g_shareable[begin >> 16] | (((lock_val >> 32) & (range_full_mask >> 32)) ^ (range_locked >> 32)))
if (is_shared)
{
addr = addr & 0xffff;
}
if (addr + size <= lock_addr || addr >= lock_addr + lock_size) [[likely]]
if ((lock_val & range_full_mask) != range_locked || addr + size <= lock_addr || addr >= lock_addr + lock_size) [[likely]]
{
range_lock->store(begin | (u64{size} << 32));
const u64 new_lock_val = g_range_lock.load();
if (!(new_lock_val | (new_lock_val != lock_val))) [[likely]]
if (!new_lock_val || new_lock_val == lock_val) [[likely]]
{
break;
}
range_lock->release(0);
range_lock->store(0);
}
std::shared_lock lock(g_mutex, std::try_to_lock);

View File

@ -43,6 +43,10 @@ namespace vm
FORCE_INLINE void range_lock(atomic_t<u64, 64>* range_lock, u32 begin, u32 size)
{
const u64 lock_val = g_range_lock.load();
#ifndef _MSC_VER
__asm__(""); // Tiny barrier
#endif
const u64 is_shared = g_shareable[begin >> 16].load();
const u64 lock_addr = static_cast<u32>(lock_val); // -> u64
const u32 lock_size = static_cast<u32>(lock_val >> 35);
@ -50,24 +54,25 @@ namespace vm
// Optimization: if range_locked is not used, the addr check will always pass
// Otherwise, g_shareable is unchanged and its value is reliable to read
if (g_shareable[begin >> 16] | (((lock_val >> 32) & (range_full_mask >> 32)) ^ (range_locked >> 32)))
if (is_shared)
{
addr = addr & 0xffff;
}
if (addr + size <= lock_addr || addr >= lock_addr + lock_size) [[likely]]
if (addr + size <= lock_addr || addr >= lock_addr + lock_size || ((lock_val >> 32) ^ (range_locked >> 32)) & (range_full_mask >> 32)) [[likely]]
{
// Optimistic locking
// Optimistic locking.
// Note that we store the range we will be accessing, without any clamping.
range_lock->store(begin | (u64{size} << 32));
const u64 new_lock_val = g_range_lock.load();
if (!(new_lock_val | (new_lock_val != lock_val))) [[likely]]
if (!new_lock_val || new_lock_val == lock_val) [[likely]]
{
return;
}
range_lock->release(0);
range_lock->store(0);
}
// Fallback to slow path

View File

@ -4,6 +4,7 @@
#include "GLGSRender.h"
#include "GLCompute.h"
#include "GLVertexProgram.h"
#include "Emu/Memory/vm_locking.h"
#define DUMP_VERTEX_DATA 0

View File

@ -6,6 +6,7 @@
#include "VKRenderPass.h"
#include "VKResourceManager.h"
#include "VKCommandStream.h"
#include "Emu/Memory/vm_locking.h"
namespace vk
{