1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

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 "sync.h"
#include "util/logs.hpp" #include "util/logs.hpp"
#include "Emu/Memory/vm_locking.h"
LOG_CHANNEL(sig_log, "SIG"); LOG_CHANNEL(sig_log, "SIG");
LOG_CHANNEL(sys_log, "SYS"); LOG_CHANNEL(sys_log, "SYS");

View File

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Memory/vm_ptr.h" #include "Emu/Memory/vm_ptr.h"
#include "Emu/Memory/vm_locking.h"
#include "Emu/Cell/PPUFunction.h" #include "Emu/Cell/PPUFunction.h"
#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/ErrorCodes.h"
@ -1114,6 +1115,26 @@ DECLARE(lv2_obj::g_waiting);
thread_local DECLARE(lv2_obj::g_to_awake); 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) void lv2_obj::sleep_unlocked(cpu_thread& thread, u64 timeout)
{ {
const u64 start_time = get_guest_system_time(); const u64 start_time = get_guest_system_time();

View File

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

View File

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

View File

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

View File

@ -166,29 +166,29 @@ namespace vm
for (u64 i = 0;; i++) for (u64 i = 0;; i++)
{ {
const u64 lock_val = g_range_lock.load(); 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 u64 lock_addr = static_cast<u32>(lock_val); // -> u64
const u32 lock_size = static_cast<u32>(lock_val >> 35); const u32 lock_size = static_cast<u32>(lock_val >> 35);
u64 addr = begin; u64 addr = begin;
// See range_lock() if (is_shared)
if (g_shareable[begin >> 16] | (((lock_val >> 32) & (range_full_mask >> 32)) ^ (range_locked >> 32)))
{ {
addr = addr & 0xffff; 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)); range_lock->store(begin | (u64{size} << 32));
const u64 new_lock_val = g_range_lock.load(); 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; break;
} }
range_lock->release(0); range_lock->store(0);
} }
std::shared_lock lock(g_mutex, std::try_to_lock); 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) FORCE_INLINE void range_lock(atomic_t<u64, 64>* range_lock, u32 begin, u32 size)
{ {
const u64 lock_val = g_range_lock.load(); 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 u64 lock_addr = static_cast<u32>(lock_val); // -> u64
const u32 lock_size = static_cast<u32>(lock_val >> 35); 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 // 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 // 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; 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)); range_lock->store(begin | (u64{size} << 32));
const u64 new_lock_val = g_range_lock.load(); 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; return;
} }
range_lock->release(0); range_lock->store(0);
} }
// Fallback to slow path // Fallback to slow path

View File

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

View File

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