early-access version 2668
This commit is contained in:
parent
ad215e0fc7
commit
61801c3602
12 changed files with 109 additions and 24 deletions
|
@ -1,7 +1,7 @@
|
|||
yuzu emulator early access
|
||||
=============
|
||||
|
||||
This is the source code for early-access 2667.
|
||||
This is the source code for early-access 2668.
|
||||
|
||||
## Legal Notice
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/fiber.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
|
||||
#include <boost/context/detail/fcontext.hpp>
|
||||
|
@ -20,7 +19,7 @@ struct Fiber::FiberImpl {
|
|||
VirtualBuffer<u8> stack;
|
||||
VirtualBuffer<u8> rewind_stack;
|
||||
|
||||
std::mutex guard;
|
||||
SpinLock guard{};
|
||||
std::function<void(void*)> entry_point;
|
||||
std::function<void(void*)> rewind_point;
|
||||
void* rewind_parameter{};
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "common/thread.h"
|
||||
#include "common/wall_clock.h"
|
||||
|
||||
|
@ -149,8 +149,8 @@ private:
|
|||
std::shared_ptr<EventType> ev_lost;
|
||||
Common::Event event{};
|
||||
Common::Event pause_event{};
|
||||
std::mutex basic_lock;
|
||||
std::mutex advance_lock;
|
||||
Common::SpinLock basic_lock{};
|
||||
Common::SpinLock advance_lock{};
|
||||
std::unique_ptr<std::thread> timer_thread;
|
||||
std::atomic<bool> paused{};
|
||||
std::atomic<bool> paused_set{};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/hardware_properties.h"
|
||||
#include "core/hle/kernel/k_priority_queue.h"
|
||||
#include "core/hle/kernel/k_scheduler_lock.h"
|
||||
|
@ -79,7 +80,7 @@ private:
|
|||
|
||||
/// Lists all thread ids that aren't deleted/etc.
|
||||
std::vector<KThread*> thread_list;
|
||||
std::mutex global_list_guard;
|
||||
Common::SpinLock global_list_guard{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -405,6 +405,9 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli
|
|||
} else {
|
||||
RescheduleCores(kernel, cores_needing_scheduling);
|
||||
}
|
||||
|
||||
// Special case to ensure dummy threads that are waiting block.
|
||||
current_thread->IfDummyThreadTryWait();
|
||||
}
|
||||
|
||||
u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
|
||||
|
@ -702,7 +705,7 @@ void KScheduler::Unload(KThread* thread) {
|
|||
prev_thread = nullptr;
|
||||
}
|
||||
|
||||
thread->context_guard.unlock();
|
||||
thread->context_guard.Unlock();
|
||||
}
|
||||
|
||||
void KScheduler::Reload(KThread* thread) {
|
||||
|
@ -791,13 +794,13 @@ void KScheduler::SwitchToCurrent() {
|
|||
do {
|
||||
auto next_thread = current_thread.load();
|
||||
if (next_thread != nullptr) {
|
||||
const auto locked = next_thread->context_guard.try_lock();
|
||||
const auto locked = next_thread->context_guard.TryLock();
|
||||
if (state.needs_scheduling.load()) {
|
||||
next_thread->context_guard.unlock();
|
||||
next_thread->context_guard.Unlock();
|
||||
break;
|
||||
}
|
||||
if (next_thread->GetActiveCore() != core_id) {
|
||||
next_thread->context_guard.unlock();
|
||||
next_thread->context_guard.Unlock();
|
||||
break;
|
||||
}
|
||||
if (!locked) {
|
||||
|
|
|
@ -4,18 +4,51 @@
|
|||
|
||||
#include "core/hle/kernel/k_spin_lock.h"
|
||||
|
||||
#if _MSC_VER
|
||||
#include <intrin.h>
|
||||
#if _M_AMD64
|
||||
#define __x86_64__ 1
|
||||
#endif
|
||||
#if _M_ARM64
|
||||
#define __aarch64__ 1
|
||||
#endif
|
||||
#else
|
||||
#if __x86_64__
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
void ThreadPause() {
|
||||
#if __x86_64__
|
||||
_mm_pause();
|
||||
#elif __aarch64__ && _MSC_VER
|
||||
__yield();
|
||||
#elif __aarch64__
|
||||
asm("yield");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
void KSpinLock::Lock() {
|
||||
lck.lock();
|
||||
while (lck.test_and_set(std::memory_order_acquire)) {
|
||||
ThreadPause();
|
||||
}
|
||||
}
|
||||
|
||||
void KSpinLock::Unlock() {
|
||||
lck.unlock();
|
||||
lck.clear(std::memory_order_release);
|
||||
}
|
||||
|
||||
bool KSpinLock::TryLock() {
|
||||
return lck.try_lock();
|
||||
if (lck.test_and_set(std::memory_order_acquire)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
#include "core/hle/kernel/k_scoped_lock.h"
|
||||
|
||||
|
@ -25,7 +25,7 @@ public:
|
|||
[[nodiscard]] bool TryLock();
|
||||
|
||||
private:
|
||||
std::mutex lck;
|
||||
std::atomic_flag lck = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
|
||||
// TODO(bunnei): Alias for now, in case we want to implement these accurately in the future.
|
||||
|
|
|
@ -1070,12 +1070,46 @@ ResultCode KThread::Sleep(s64 timeout) {
|
|||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void KThread::IfDummyThreadTryWait() {
|
||||
if (!IsDummyThread()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetState() != ThreadState::Waiting) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Block until we can grab the lock.
|
||||
KScopedSpinLock lk{dummy_wait_lock};
|
||||
}
|
||||
|
||||
void KThread::IfDummyThreadBeginWait() {
|
||||
if (!IsDummyThread()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the thread will block when IfDummyThreadTryWait is called.
|
||||
dummy_wait_lock.Lock();
|
||||
}
|
||||
|
||||
void KThread::IfDummyThreadEndWait() {
|
||||
if (!IsDummyThread()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the thread will no longer block.
|
||||
dummy_wait_lock.Unlock();
|
||||
}
|
||||
|
||||
void KThread::BeginWait(KThreadQueue* queue) {
|
||||
// Set our state as waiting.
|
||||
SetState(ThreadState::Waiting);
|
||||
|
||||
// Set our wait queue.
|
||||
wait_queue = queue;
|
||||
|
||||
// Special case for dummy threads to ensure they block.
|
||||
IfDummyThreadBeginWait();
|
||||
}
|
||||
|
||||
void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) {
|
||||
|
@ -1101,6 +1135,9 @@ void KThread::EndWait(ResultCode wait_result_) {
|
|||
}
|
||||
|
||||
wait_queue->EndWait(this, wait_result_);
|
||||
|
||||
// Special case for dummy threads to wakeup if necessary.
|
||||
IfDummyThreadEndWait();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#include "common/common_types.h"
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/hle/kernel/k_affinity_mask.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
|
@ -638,6 +637,14 @@ public:
|
|||
return condvar_key;
|
||||
}
|
||||
|
||||
// Dummy threads (used for HLE host threads) cannot wait based on the guest scheduler, and
|
||||
// therefore will not block on guest kernel synchronization primitives. These methods handle
|
||||
// blocking as needed.
|
||||
|
||||
void IfDummyThreadTryWait();
|
||||
void IfDummyThreadBeginWait();
|
||||
void IfDummyThreadEndWait();
|
||||
|
||||
private:
|
||||
static constexpr size_t PriorityInheritanceCountMax = 10;
|
||||
union SyncObjectBuffer {
|
||||
|
@ -755,7 +762,7 @@ private:
|
|||
s8 priority_inheritance_count{};
|
||||
bool resource_limit_release_hint{};
|
||||
StackParameters stack_parameters{};
|
||||
Common::SpinLock context_guard{};
|
||||
KSpinLock context_guard{};
|
||||
KSpinLock dummy_wait_lock{};
|
||||
|
||||
// For emulation
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/arm/cpu_interrupt_handler.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
||||
|
@ -15,7 +16,7 @@ namespace Kernel {
|
|||
PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
|
||||
Core::CPUInterrupts& interrupts_)
|
||||
: core_index{core_index_}, system{system_}, scheduler{scheduler_},
|
||||
interrupts{interrupts_}, guard{std::make_unique<std::mutex>()} {
|
||||
interrupts{interrupts_}, guard{std::make_unique<Common::SpinLock>()} {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
// TODO(bunnei): Initialization relies on a core being available. We may later replace this with
|
||||
// a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "core/arm/arm_interface.h"
|
||||
|
||||
namespace Common {
|
||||
class SpinLock;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KScheduler;
|
||||
} // namespace Kernel
|
||||
|
@ -88,7 +91,7 @@ private:
|
|||
Core::System& system;
|
||||
Kernel::KScheduler& scheduler;
|
||||
Core::CPUInterrupts& interrupts;
|
||||
std::unique_ptr<std::mutex> guard;
|
||||
std::unique_ptr<Common::SpinLock> guard;
|
||||
std::unique_ptr<Core::ARM_Interface> arm_interface;
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <string>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -89,7 +90,7 @@ protected:
|
|||
using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
|
||||
|
||||
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||
[[nodiscard]] std::scoped_lock<std::mutex> LockService() {
|
||||
[[nodiscard]] std::scoped_lock<Common::SpinLock> LockService() {
|
||||
return std::scoped_lock{lock_service};
|
||||
}
|
||||
|
||||
|
@ -134,7 +135,7 @@ private:
|
|||
boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
|
||||
|
||||
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||
std::mutex lock_service;
|
||||
Common::SpinLock lock_service;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue