Por boost range lock implementation

This commit is contained in:
Lander Gallastegi 2025-06-26 00:06:10 +02:00
parent ff99ad694a
commit 22a974b08a
3 changed files with 106 additions and 8 deletions

View File

@ -679,6 +679,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/path_util.h
src/common/object_pool.h
src/common/polyfill_thread.h
src/common/range_lock.h
src/common/rdtsc.cpp
src/common/rdtsc.h
src/common/recursive_lock.cpp

101
src/common/range_lock.h Normal file
View File

@ -0,0 +1,101 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <iterator>
#include <mutex>
namespace Common {
// From boost thread locking
template <typename Iterator>
struct RangeLockGuard {
Iterator begin;
Iterator end;
RangeLockGuard(Iterator begin_, Iterator end_) : begin(begin_), end(end_) {
LockRange(begin, end);
}
void release() {
begin = end;
}
~RangeLockGuard() {
for (; begin != end; ++begin) {
begin->unlock();
}
}
};
template <typename Iterator>
Iterator TryLockRange(Iterator begin, Iterator end) {
using LockType = typename std::iterator_traits<Iterator>::value_type;
if (begin == end) {
return end;
}
std::unique_lock<LockType> guard(*begin, std::try_to_lock);
if (!guard.owns_lock()) {
return begin;
}
Iterator failed = TryLockRange(++begin, end);
if (failed == end) {
guard.release();
}
return failed;
}
template <typename Iterator>
void LockRange(Iterator begin, Iterator end) {
using LockType = typename std::iterator_traits<Iterator>::value_type;
if (begin == end) {
return;
}
bool start_with_begin = true;
Iterator second = begin;
++second;
Iterator next = second;
while (true) {
std::unique_lock<LockType> begin_lock(*begin, std::defer_lock);
if (start_with_begin) {
begin_lock.lock();
const Iterator failed_lock = TryLockRange(next, end);
if (failed_lock == end) {
begin_lock.release();
return;
}
start_with_begin = false;
next = failed_lock;
} else {
RangeLockGuard<Iterator> guard(next, end);
if (begin_lock.try_lock()) {
const Iterator failed_lock = TryLockRange(second, next);
if (failed_lock == next) {
begin_lock.release();
guard.release();
return;
}
start_with_begin = false;
next = failed_lock;
} else {
start_with_begin = true;
next = second;
}
}
}
}
} // namespace Common

View File

@ -2,9 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <boost/container/small_vector.hpp>
#include <boost/thread/lock_algorithms.hpp>
#include "common/assert.h"
#include "common/debug.h"
#include "common/range_lock.h"
#include "common/signal_context.h"
#include "core/memory.h"
#include "core/signals.h"
@ -196,13 +196,9 @@ struct PageManager::Impl {
const u64 page_end = Common::DivCeil(addr + size, PAGE_SIZE);
// Acquire locks for the range of pages
size_t lock_start = page / PAGES_PER_LOCK;
const size_t lock_end = Common::DivCeil(page_end, PAGES_PER_LOCK);
boost::container::small_vector<std::unique_lock<LockType>, 8> unique_locks;
for (; lock_start < lock_end; ++lock_start) {
unique_locks.emplace_back(locks[lock_start], std::defer_lock);
}
boost::lock(unique_locks.begin(), unique_locks.end());
const auto lock_start = locks.begin() + (page / PAGES_PER_LOCK);
const auto lock_end = locks.begin() + Common::DivCeil(page_end, PAGES_PER_LOCK);
Common::RangeLockGuard lk(lock_start, lock_end);
auto perms = cached_pages[page].Perm();
u64 range_begin = 0;