early-access version 3130

This commit is contained in:
pineappleEA 2022-11-19 12:44:30 +01:00
parent dba1deb4a5
commit cd9434a867
7 changed files with 165 additions and 54 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access
=============
This is the source code for early-access 3129.
This is the source code for early-access 3130.
## Legal Notice

View file

@ -265,8 +265,20 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
}
}
void SinkStream::Stall() {}
void SinkStream::Stall() {
if (stalled) {
return;
}
stalled = true;
system.StallProcesses();
}
void SinkStream::Unstall() {}
void SinkStream::Unstall() {
if (!stalled) {
return;
}
system.UnstallProcesses();
stalled = false;
}
} // namespace AudioCore::Sink

View file

@ -1,41 +1,133 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <mutex>
#include "common/assert.h"
#include "common/fiber.h"
#include "common/virtual_buffer.h"
#include "common/spin_lock.h"
#if defined(_WIN32) || defined(WIN32)
#include <windows.h>
#else
#include <boost/context/detail/fcontext.hpp>
#endif
namespace Common {
constexpr std::size_t default_stack_size = 512 * 1024;
struct Fiber::FiberImpl {
FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {}
VirtualBuffer<u8> stack;
VirtualBuffer<u8> rewind_stack;
std::mutex guard;
SpinLock guard{};
std::function<void()> entry_point;
std::function<void()> rewind_point;
void* rewind_parameter{};
std::shared_ptr<Fiber> previous_fiber;
bool is_thread_fiber{};
bool released{};
u8* stack_limit{};
u8* rewind_stack_limit{};
boost::context::detail::fcontext_t context{};
boost::context::detail::fcontext_t rewind_context{};
#if defined(_WIN32) || defined(WIN32)
LPVOID handle = nullptr;
LPVOID rewind_handle = nullptr;
#else
alignas(64) std::array<u8, default_stack_size> stack;
alignas(64) std::array<u8, default_stack_size> rewind_stack;
u8* stack_limit;
u8* rewind_stack_limit;
boost::context::detail::fcontext_t context;
boost::context::detail::fcontext_t rewind_context;
#endif
};
void Fiber::SetRewindPoint(std::function<void()>&& rewind_func) {
impl->rewind_point = std::move(rewind_func);
}
#if defined(_WIN32) || defined(WIN32)
void Fiber::Start() {
ASSERT(impl->previous_fiber != nullptr);
impl->previous_fiber->impl->guard.unlock();
impl->previous_fiber.reset();
impl->entry_point();
UNREACHABLE();
}
void Fiber::OnRewind() {
ASSERT(impl->handle != nullptr);
DeleteFiber(impl->handle);
impl->handle = impl->rewind_handle;
impl->rewind_handle = nullptr;
impl->rewind_point();
UNREACHABLE();
}
void Fiber::FiberStartFunc(void* fiber_parameter) {
auto* fiber = static_cast<Fiber*>(fiber_parameter);
fiber->Start();
}
void Fiber::RewindStartFunc(void* fiber_parameter) {
auto* fiber = static_cast<Fiber*>(fiber_parameter);
fiber->OnRewind();
}
Fiber::Fiber(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} {
impl->entry_point = std::move(entry_point_func);
impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this);
}
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
Fiber::~Fiber() {
if (impl->released) {
return;
}
// Make sure the Fiber is not being used
const bool locked = impl->guard.try_lock();
ASSERT_MSG(locked, "Destroying a fiber that's still running");
if (locked) {
impl->guard.unlock();
}
DeleteFiber(impl->handle);
}
void Fiber::Exit() {
ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
if (!impl->is_thread_fiber) {
return;
}
ConvertFiberToThread();
impl->guard.unlock();
impl->released = true;
}
void Fiber::Rewind() {
ASSERT(impl->rewind_point);
ASSERT(impl->rewind_handle == nullptr);
impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this);
SwitchToFiber(impl->rewind_handle);
}
void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
ASSERT_MSG(to != nullptr, "Next fiber is null!");
to->impl->guard.lock();
to->impl->previous_fiber = from;
SwitchToFiber(to->impl->handle);
ASSERT(from->impl->previous_fiber != nullptr);
from->impl->previous_fiber->impl->guard.unlock();
from->impl->previous_fiber.reset();
}
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
fiber->impl->guard.lock();
fiber->impl->handle = ConvertThreadToFiber(nullptr);
fiber->impl->is_thread_fiber = true;
return fiber;
}
#else
void Fiber::Start(boost::context::detail::transfer_t& transfer) {
ASSERT(impl->previous_fiber != nullptr);
impl->previous_fiber->impl->context = transfer.fctx;
@ -107,22 +199,16 @@ void Fiber::Rewind() {
boost::context::detail::jump_fcontext(impl->rewind_context, this);
}
void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) {
to.impl->guard.lock();
to.impl->previous_fiber = weak_from.lock();
auto transfer = boost::context::detail::jump_fcontext(to.impl->context, &to);
// "from" might no longer be valid if the thread was killed
if (auto from = weak_from.lock()) {
if (from->impl->previous_fiber == nullptr) {
ASSERT_MSG(false, "previous_fiber is nullptr!");
return;
}
void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
ASSERT_MSG(to != nullptr, "Next fiber is null!");
to->impl->guard.lock();
to->impl->previous_fiber = from;
auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get());
ASSERT(from->impl->previous_fiber != nullptr);
from->impl->previous_fiber->impl->context = transfer.fctx;
from->impl->previous_fiber->impl->guard.unlock();
from->impl->previous_fiber.reset();
}
}
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
@ -132,4 +218,5 @@ std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
return fiber;
}
#endif
} // namespace Common

View file

@ -6,9 +6,11 @@
#include <functional>
#include <memory>
#if !defined(_WIN32) && !defined(WIN32)
namespace boost::context::detail {
struct transfer_t;
}
#endif
namespace Common {
@ -40,7 +42,7 @@ public:
/// Yields control from Fiber 'from' to Fiber 'to'
/// Fiber 'from' must be the currently running fiber.
static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to);
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
void SetRewindPoint(std::function<void()>&& rewind_func);
@ -50,13 +52,23 @@ public:
/// Only call from main thread's fiber
void Exit();
/// Changes the start parameter of the fiber. Has no effect if the fiber already started
void SetStartParameter(void* new_parameter);
private:
Fiber();
#if defined(_WIN32) || defined(WIN32)
void OnRewind();
void Start();
static void FiberStartFunc(void* fiber_parameter);
static void RewindStartFunc(void* fiber_parameter);
#else
void OnRewind(boost::context::detail::transfer_t& transfer);
void Start(boost::context::detail::transfer_t& transfer);
static void FiberStartFunc(boost::context::detail::transfer_t transfer);
static void RewindStartFunc(boost::context::detail::transfer_t transfer);
#endif
struct FiberImpl;
std::unique_ptr<FiberImpl> impl;

View file

@ -180,7 +180,7 @@ void CpuManager::ShutdownThread() {
auto* thread = kernel.GetCurrentEmuThread();
auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0;
Common::Fiber::YieldTo(thread->GetHostContext(), *core_data[core].host_context);
Common::Fiber::YieldTo(thread->GetHostContext(), core_data[core].host_context);
UNREACHABLE();
}
@ -217,7 +217,7 @@ void CpuManager::RunThread(std::size_t core) {
auto* thread = scheduler.GetSchedulerCurrentThread();
Kernel::SetCurrentThread(kernel, thread);
Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
Common::Fiber::YieldTo(data.host_context, thread->GetHostContext());
}
} // namespace Core

View file

@ -116,7 +116,7 @@ void KScheduler::PreemptSingleCore() {
auto& previous_scheduler = kernel.Scheduler(thread->GetCurrentCore());
previous_scheduler.Unload(thread);
Common::Fiber::YieldTo(thread->GetHostContext(), *m_switch_fiber);
Common::Fiber::YieldTo(thread->GetHostContext(), m_switch_fiber);
GetCurrentThread(kernel).EnableDispatch();
}
@ -411,7 +411,7 @@ void KScheduler::ScheduleImpl() {
m_switch_cur_thread = cur_thread;
m_switch_highest_priority_thread = highest_priority_thread;
m_switch_from_schedule = true;
Common::Fiber::YieldTo(cur_thread->host_context, *m_switch_fiber);
Common::Fiber::YieldTo(cur_thread->host_context, m_switch_fiber);
// Returning from ScheduleImpl occurs after this thread has been scheduled again.
}
@ -489,7 +489,7 @@ void KScheduler::ScheduleImplFiber() {
Reload(highest_priority_thread);
// Reload the host thread.
Common::Fiber::YieldTo(m_switch_fiber, *highest_priority_thread->host_context);
Common::Fiber::YieldTo(m_switch_fiber, highest_priority_thread->host_context);
}
void KScheduler::Unload(KThread* thread) {

View file

@ -50,7 +50,7 @@ public:
value++;
}
results[id] = value;
Fiber::YieldTo(work_fibers[id], *thread_fibers[id]);
Fiber::YieldTo(work_fibers[id], thread_fibers[id]);
}
void ExecuteThread(u32 id);
@ -68,7 +68,7 @@ void TestControl1::ExecuteThread(u32 id) {
thread_fibers[id] = thread_fiber;
work_fibers[id] = std::make_shared<Fiber>([this] { DoWork(); });
items[id] = rand() % 256;
Fiber::YieldTo(thread_fibers[id], *work_fibers[id]);
Fiber::YieldTo(thread_fibers[id], work_fibers[id]);
thread_fibers[id]->Exit();
}
@ -105,11 +105,11 @@ public:
for (u32 i = 0; i < 12000; i++) {
value1 += i;
}
Fiber::YieldTo(fiber1, *fiber3);
Fiber::YieldTo(fiber1, fiber3);
const u32 id = thread_ids.Get();
assert1 = id == 1;
value2 += 5000;
Fiber::YieldTo(fiber1, *thread_fibers[id]);
Fiber::YieldTo(fiber1, thread_fibers[id]);
}
void DoWork2() {
@ -117,7 +117,7 @@ public:
;
value2 = 2000;
trap = false;
Fiber::YieldTo(fiber2, *fiber1);
Fiber::YieldTo(fiber2, fiber1);
assert3 = false;
}
@ -125,19 +125,19 @@ public:
const u32 id = thread_ids.Get();
assert2 = id == 0;
value1 += 1000;
Fiber::YieldTo(fiber3, *thread_fibers[id]);
Fiber::YieldTo(fiber3, thread_fibers[id]);
}
void ExecuteThread(u32 id);
void CallFiber1() {
const u32 id = thread_ids.Get();
Fiber::YieldTo(thread_fibers[id], *fiber1);
Fiber::YieldTo(thread_fibers[id], fiber1);
}
void CallFiber2() {
const u32 id = thread_ids.Get();
Fiber::YieldTo(thread_fibers[id], *fiber2);
Fiber::YieldTo(thread_fibers[id], fiber2);
}
void Exit();
@ -207,23 +207,23 @@ public:
void DoWork1() {
value1 += 1;
Fiber::YieldTo(fiber1, *fiber2);
Fiber::YieldTo(fiber1, fiber2);
const u32 id = thread_ids.Get();
value3 += 1;
Fiber::YieldTo(fiber1, *thread_fibers[id]);
Fiber::YieldTo(fiber1, thread_fibers[id]);
}
void DoWork2() {
value2 += 1;
const u32 id = thread_ids.Get();
Fiber::YieldTo(fiber2, *thread_fibers[id]);
Fiber::YieldTo(fiber2, thread_fibers[id]);
}
void ExecuteThread(u32 id);
void CallFiber1() {
const u32 id = thread_ids.Get();
Fiber::YieldTo(thread_fibers[id], *fiber1);
Fiber::YieldTo(thread_fibers[id], fiber1);
}
void Exit();
@ -283,7 +283,7 @@ public:
void Execute() {
thread_fiber = Fiber::ThreadToFiber();
Fiber::YieldTo(thread_fiber, *fiber1);
Fiber::YieldTo(thread_fiber, fiber1);
thread_fiber->Exit();
}
@ -291,7 +291,7 @@ public:
fiber1->SetRewindPoint([this] { DoWork(); });
if (rewinded) {
goal_reached = true;
Fiber::YieldTo(fiber1, *thread_fiber);
Fiber::YieldTo(fiber1, thread_fiber);
}
rewinded = true;
fiber1->Rewind();