early-access version 2814

This commit is contained in:
pineappleEA 2022-07-03 10:24:53 +02:00
parent dc2419801a
commit b45f33b6ff
35 changed files with 12094 additions and 8178 deletions

View File

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

864
dist/languages/ca.ts vendored

File diff suppressed because it is too large Load Diff

925
dist/languages/cs.ts vendored

File diff suppressed because it is too large Load Diff

864
dist/languages/da.ts vendored

File diff suppressed because it is too large Load Diff

864
dist/languages/de.ts vendored

File diff suppressed because it is too large Load Diff

864
dist/languages/el.ts vendored

File diff suppressed because it is too large Load Diff

868
dist/languages/es.ts vendored

File diff suppressed because it is too large Load Diff

868
dist/languages/fr.ts vendored

File diff suppressed because it is too large Load Diff

864
dist/languages/id.ts vendored

File diff suppressed because it is too large Load Diff

864
dist/languages/it.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

864
dist/languages/nb.ts vendored

File diff suppressed because it is too large Load Diff

864
dist/languages/nl.ts vendored

File diff suppressed because it is too large Load Diff

864
dist/languages/pl.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

864
dist/languages/sv.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

864
dist/languages/vi.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -20,10 +20,8 @@ struct Fiber::FiberImpl {
VirtualBuffer<u8> rewind_stack; VirtualBuffer<u8> rewind_stack;
std::mutex guard; std::mutex guard;
std::function<void(void*)> entry_point; std::function<void()> entry_point;
std::function<void(void*)> rewind_point; std::function<void()> rewind_point;
void* rewind_parameter{};
void* start_parameter{};
std::shared_ptr<Fiber> previous_fiber; std::shared_ptr<Fiber> previous_fiber;
bool is_thread_fiber{}; bool is_thread_fiber{};
bool released{}; bool released{};
@ -34,13 +32,8 @@ struct Fiber::FiberImpl {
boost::context::detail::fcontext_t rewind_context{}; boost::context::detail::fcontext_t rewind_context{};
}; };
void Fiber::SetStartParameter(void* new_parameter) { void Fiber::SetRewindPoint(std::function<void()>&& rewind_func) {
impl->start_parameter = new_parameter;
}
void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
impl->rewind_point = std::move(rewind_func); impl->rewind_point = std::move(rewind_func);
impl->rewind_parameter = rewind_param;
} }
void Fiber::Start(boost::context::detail::transfer_t& transfer) { void Fiber::Start(boost::context::detail::transfer_t& transfer) {
@ -48,7 +41,7 @@ void Fiber::Start(boost::context::detail::transfer_t& transfer) {
impl->previous_fiber->impl->context = transfer.fctx; impl->previous_fiber->impl->context = transfer.fctx;
impl->previous_fiber->impl->guard.unlock(); impl->previous_fiber->impl->guard.unlock();
impl->previous_fiber.reset(); impl->previous_fiber.reset();
impl->entry_point(impl->start_parameter); impl->entry_point();
UNREACHABLE(); UNREACHABLE();
} }
@ -59,7 +52,7 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf
u8* tmp = impl->stack_limit; u8* tmp = impl->stack_limit;
impl->stack_limit = impl->rewind_stack_limit; impl->stack_limit = impl->rewind_stack_limit;
impl->rewind_stack_limit = tmp; impl->rewind_stack_limit = tmp;
impl->rewind_point(impl->rewind_parameter); impl->rewind_point();
UNREACHABLE(); UNREACHABLE();
} }
@ -73,10 +66,8 @@ void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) {
fiber->OnRewind(transfer); fiber->OnRewind(transfer);
} }
Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) Fiber::Fiber(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} {
: impl{std::make_unique<FiberImpl>()} {
impl->entry_point = std::move(entry_point_func); impl->entry_point = std::move(entry_point_func);
impl->start_parameter = start_parameter;
impl->stack_limit = impl->stack.data(); impl->stack_limit = impl->stack.data();
impl->rewind_stack_limit = impl->rewind_stack.data(); impl->rewind_stack_limit = impl->rewind_stack.data();
u8* stack_base = impl->stack_limit + default_stack_size; u8* stack_base = impl->stack_limit + default_stack_size;

View File

@ -29,7 +29,7 @@ namespace Common {
*/ */
class Fiber { class Fiber {
public: public:
Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter); Fiber(std::function<void()>&& entry_point_func);
~Fiber(); ~Fiber();
Fiber(const Fiber&) = delete; Fiber(const Fiber&) = delete;
@ -43,16 +43,13 @@ public:
static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to); static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param); void SetRewindPoint(std::function<void()>&& rewind_func);
void Rewind(); void Rewind();
/// Only call from main thread's fiber /// Only call from main thread's fiber
void Exit(); void Exit();
/// Changes the start parameter of the fiber. Has no effect if the fiber already started
void SetStartParameter(void* new_parameter);
private: private:
Fiber(); Fiber();

View File

@ -61,9 +61,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {}; const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {};
ev_lost = CreateEvent("_lost_event", empty_timed_callback); ev_lost = CreateEvent("_lost_event", empty_timed_callback);
if (is_multicore) { if (is_multicore) {
const auto hardware_concurrency = std::thread::hardware_concurrency(); worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0);
size_t id = 0;
worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
} }
} }

View File

@ -32,7 +32,6 @@ struct EventType {
TimedCallback callback; TimedCallback callback;
/// A pointer to the name of the event. /// A pointer to the name of the event.
const std::string name; const std::string name;
mutable std::mutex guard;
}; };
/** /**
@ -157,7 +156,6 @@ private:
std::condition_variable wait_pause_cv; std::condition_variable wait_pause_cv;
std::condition_variable wait_signal_cv; std::condition_variable wait_signal_cv;
mutable std::mutex event_mutex; mutable std::mutex event_mutex;
mutable std::mutex sequence_mutex;
std::atomic<bool> paused_state{}; std::atomic<bool> paused_state{};
bool is_paused{}; bool is_paused{};

View File

@ -41,51 +41,32 @@ void CpuManager::Shutdown() {
} }
} }
std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() { void CpuManager::GuestThreadFunction() {
return GuestThreadFunction; if (is_multicore) {
} MultiCoreRunGuestThread();
std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
return IdleThreadFunction;
}
std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() {
return ShutdownThreadFunction;
}
void CpuManager::GuestThreadFunction(void* cpu_manager_) {
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
if (cpu_manager->is_multicore) {
cpu_manager->MultiCoreRunGuestThread();
} else { } else {
cpu_manager->SingleCoreRunGuestThread(); SingleCoreRunGuestThread();
} }
} }
void CpuManager::GuestRewindFunction(void* cpu_manager_) { void CpuManager::GuestRewindFunction() {
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); if (is_multicore) {
if (cpu_manager->is_multicore) { MultiCoreRunGuestLoop();
cpu_manager->MultiCoreRunGuestLoop();
} else { } else {
cpu_manager->SingleCoreRunGuestLoop(); SingleCoreRunGuestLoop();
} }
} }
void CpuManager::IdleThreadFunction(void* cpu_manager_) { void CpuManager::IdleThreadFunction() {
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); if (is_multicore) {
if (cpu_manager->is_multicore) { MultiCoreRunIdleThread();
cpu_manager->MultiCoreRunIdleThread();
} else { } else {
cpu_manager->SingleCoreRunIdleThread(); SingleCoreRunIdleThread();
} }
} }
void CpuManager::ShutdownThreadFunction(void* cpu_manager) { void CpuManager::ShutdownThreadFunction() {
static_cast<CpuManager*>(cpu_manager)->ShutdownThread(); ShutdownThread();
}
void* CpuManager::GetStartFuncParameter() {
return this;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -97,7 +78,7 @@ void CpuManager::MultiCoreRunGuestThread() {
kernel.CurrentScheduler()->OnThreadStart(); kernel.CurrentScheduler()->OnThreadStart();
auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread(); auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
auto& host_context = thread->GetHostContext(); auto& host_context = thread->GetHostContext();
host_context->SetRewindPoint(GuestRewindFunction, this); host_context->SetRewindPoint([this] { GuestRewindFunction(); });
MultiCoreRunGuestLoop(); MultiCoreRunGuestLoop();
} }
@ -134,7 +115,7 @@ void CpuManager::SingleCoreRunGuestThread() {
kernel.CurrentScheduler()->OnThreadStart(); kernel.CurrentScheduler()->OnThreadStart();
auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread(); auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
auto& host_context = thread->GetHostContext(); auto& host_context = thread->GetHostContext();
host_context->SetRewindPoint(GuestRewindFunction, this); host_context->SetRewindPoint([this] { GuestRewindFunction(); });
SingleCoreRunGuestLoop(); SingleCoreRunGuestLoop();
} }

View File

@ -50,10 +50,15 @@ public:
void Initialize(); void Initialize();
void Shutdown(); void Shutdown();
static std::function<void(void*)> GetGuestThreadStartFunc(); std::function<void()> GetGuestThreadStartFunc() {
static std::function<void(void*)> GetIdleThreadStartFunc(); return [this] { GuestThreadFunction(); };
static std::function<void(void*)> GetShutdownThreadStartFunc(); }
void* GetStartFuncParameter(); std::function<void()> GetIdleThreadStartFunc() {
return [this] { IdleThreadFunction(); };
}
std::function<void()> GetShutdownThreadStartFunc() {
return [this] { ShutdownThreadFunction(); };
}
void PreemptSingleCore(bool from_running_enviroment = true); void PreemptSingleCore(bool from_running_enviroment = true);
@ -62,10 +67,10 @@ public:
} }
private: private:
static void GuestThreadFunction(void* cpu_manager); void GuestThreadFunction();
static void GuestRewindFunction(void* cpu_manager); void GuestRewindFunction();
static void IdleThreadFunction(void* cpu_manager); void IdleThreadFunction();
static void ShutdownThreadFunction(void* cpu_manager); void ShutdownThreadFunction();
void MultiCoreRunGuestThread(); void MultiCoreRunGuestThread();
void MultiCoreRunGuestLoop(); void MultiCoreRunGuestLoop();

View File

@ -622,7 +622,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
} }
KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} { KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} {
switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this); switch_fiber = std::make_shared<Common::Fiber>([this] { SwitchToCurrent(); });
state.needs_scheduling.store(true); state.needs_scheduling.store(true);
state.interrupt_task_thread_runnable = false; state.interrupt_task_thread_runnable = false;
state.should_count_idle = false; state.should_count_idle = false;
@ -778,11 +778,6 @@ void KScheduler::ScheduleImpl() {
next_scheduler.SwitchContextStep2(); next_scheduler.SwitchContextStep2();
} }
void KScheduler::OnSwitch(void* this_scheduler) {
KScheduler* sched = static_cast<KScheduler*>(this_scheduler);
sched->SwitchToCurrent();
}
void KScheduler::SwitchToCurrent() { void KScheduler::SwitchToCurrent() {
while (true) { while (true) {
{ {

View File

@ -170,7 +170,6 @@ private:
*/ */
void UpdateLastContextSwitchTime(KThread* thread, KProcess* process); void UpdateLastContextSwitchTime(KThread* thread, KProcess* process);
static void OnSwitch(void* this_scheduler);
void SwitchToCurrent(); void SwitchToCurrent();
KThread* prev_thread{}; KThread* prev_thread{};

View File

@ -246,14 +246,12 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
VAddr user_stack_top, s32 prio, s32 core, KProcess* owner, VAddr user_stack_top, s32 prio, s32 core, KProcess* owner,
ThreadType type, std::function<void(void*)>&& init_func, ThreadType type, std::function<void()>&& init_func) {
void* init_func_parameter) {
// Initialize the thread. // Initialize the thread.
R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
// Initialize emulation parameters. // Initialize emulation parameters.
thread->host_context = thread->host_context = std::make_shared<Common::Fiber>(std::move(init_func));
std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter);
thread->is_single_core = !Settings::values.use_multi_core.GetValue(); thread->is_single_core = !Settings::values.use_multi_core.GetValue();
return ResultSuccess; return ResultSuccess;
@ -265,15 +263,13 @@ Result KThread::InitializeDummyThread(KThread* thread) {
Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main, return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
Core::CpuManager::GetIdleThreadStartFunc(), system.GetCpuManager().GetIdleThreadStartFunc());
system.GetCpuManager().GetStartFuncParameter());
} }
Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread, Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
KThreadFunction func, uintptr_t arg, s32 virt_core) { KThreadFunction func, uintptr_t arg, s32 virt_core) {
return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority, return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
Core::CpuManager::GetShutdownThreadStartFunc(), system.GetCpuManager().GetShutdownThreadStartFunc());
system.GetCpuManager().GetStartFuncParameter());
} }
Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func, Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func,
@ -281,8 +277,7 @@ Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThr
KProcess* owner) { KProcess* owner) {
system.Kernel().GlobalSchedulerContext().AddThread(thread); system.Kernel().GlobalSchedulerContext().AddThread(thread);
return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner, return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(), ThreadType::User, system.GetCpuManager().GetGuestThreadStartFunc());
system.GetCpuManager().GetStartFuncParameter());
} }
void KThread::PostDestroy(uintptr_t arg) { void KThread::PostDestroy(uintptr_t arg) {

View File

@ -729,8 +729,7 @@ private:
[[nodiscard]] static Result InitializeThread(KThread* thread, KThreadFunction func, [[nodiscard]] static Result InitializeThread(KThread* thread, KThreadFunction func,
uintptr_t arg, VAddr user_stack_top, s32 prio, uintptr_t arg, VAddr user_stack_top, s32 prio,
s32 core, KProcess* owner, ThreadType type, s32 core, KProcess* owner, ThreadType type,
std::function<void(void*)>&& init_func, std::function<void()>&& init_func);
void* init_func_parameter);
static void RestorePriority(KernelCore& kernel_ctx, KThread* thread); static void RestorePriority(KernelCore& kernel_ctx, KThread* thread);

View File

@ -43,7 +43,15 @@ class TestControl1 {
public: public:
TestControl1() = default; TestControl1() = default;
void DoWork(); void DoWork() {
const u32 id = thread_ids.Get();
u32 value = items[id];
for (u32 i = 0; i < id; i++) {
value++;
}
results[id] = value;
Fiber::YieldTo(work_fibers[id], *thread_fibers[id]);
}
void ExecuteThread(u32 id); void ExecuteThread(u32 id);
@ -54,35 +62,16 @@ public:
std::vector<u32> results; std::vector<u32> results;
}; };
static void WorkControl1(void* control) {
auto* test_control = static_cast<TestControl1*>(control);
test_control->DoWork();
}
void TestControl1::DoWork() {
const u32 id = thread_ids.Get();
u32 value = items[id];
for (u32 i = 0; i < id; i++) {
value++;
}
results[id] = value;
Fiber::YieldTo(work_fibers[id], *thread_fibers[id]);
}
void TestControl1::ExecuteThread(u32 id) { void TestControl1::ExecuteThread(u32 id) {
thread_ids.Register(id); thread_ids.Register(id);
auto thread_fiber = Fiber::ThreadToFiber(); auto thread_fiber = Fiber::ThreadToFiber();
thread_fibers[id] = thread_fiber; thread_fibers[id] = thread_fiber;
work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this); work_fibers[id] = std::make_shared<Fiber>([this] { DoWork(); });
items[id] = rand() % 256; items[id] = rand() % 256;
Fiber::YieldTo(thread_fibers[id], *work_fibers[id]); Fiber::YieldTo(thread_fibers[id], *work_fibers[id]);
thread_fibers[id]->Exit(); thread_fibers[id]->Exit();
} }
static void ThreadStart1(u32 id, TestControl1& test_control) {
test_control.ExecuteThread(id);
}
/** This test checks for fiber setup configuration and validates that fibers are /** This test checks for fiber setup configuration and validates that fibers are
* doing all the work required. * doing all the work required.
*/ */
@ -95,7 +84,7 @@ TEST_CASE("Fibers::Setup", "[common]") {
test_control.results.resize(num_threads, 0); test_control.results.resize(num_threads, 0);
std::vector<std::thread> threads; std::vector<std::thread> threads;
for (u32 i = 0; i < num_threads; i++) { for (u32 i = 0; i < num_threads; i++) {
threads.emplace_back(ThreadStart1, i, std::ref(test_control)); threads.emplace_back([&test_control, i] { test_control.ExecuteThread(i); });
} }
for (u32 i = 0; i < num_threads; i++) { for (u32 i = 0; i < num_threads; i++) {
threads[i].join(); threads[i].join();
@ -167,21 +156,6 @@ public:
std::shared_ptr<Common::Fiber> fiber3; std::shared_ptr<Common::Fiber> fiber3;
}; };
static void WorkControl2_1(void* control) {
auto* test_control = static_cast<TestControl2*>(control);
test_control->DoWork1();
}
static void WorkControl2_2(void* control) {
auto* test_control = static_cast<TestControl2*>(control);
test_control->DoWork2();
}
static void WorkControl2_3(void* control) {
auto* test_control = static_cast<TestControl2*>(control);
test_control->DoWork3();
}
void TestControl2::ExecuteThread(u32 id) { void TestControl2::ExecuteThread(u32 id) {
thread_ids.Register(id); thread_ids.Register(id);
auto thread_fiber = Fiber::ThreadToFiber(); auto thread_fiber = Fiber::ThreadToFiber();
@ -193,18 +167,6 @@ void TestControl2::Exit() {
thread_fibers[id]->Exit(); thread_fibers[id]->Exit();
} }
static void ThreadStart2_1(u32 id, TestControl2& test_control) {
test_control.ExecuteThread(id);
test_control.CallFiber1();
test_control.Exit();
}
static void ThreadStart2_2(u32 id, TestControl2& test_control) {
test_control.ExecuteThread(id);
test_control.CallFiber2();
test_control.Exit();
}
/** This test checks for fiber thread exchange configuration and validates that fibers are /** This test checks for fiber thread exchange configuration and validates that fibers are
* that a fiber has been successfully transferred from one thread to another and that the TLS * that a fiber has been successfully transferred from one thread to another and that the TLS
* region of the thread is kept while changing fibers. * region of the thread is kept while changing fibers.
@ -212,14 +174,19 @@ static void ThreadStart2_2(u32 id, TestControl2& test_control) {
TEST_CASE("Fibers::InterExchange", "[common]") { TEST_CASE("Fibers::InterExchange", "[common]") {
TestControl2 test_control{}; TestControl2 test_control{};
test_control.thread_fibers.resize(2); test_control.thread_fibers.resize(2);
test_control.fiber1 = test_control.fiber1 = std::make_shared<Fiber>([&test_control] { test_control.DoWork1(); });
std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_1}, &test_control); test_control.fiber2 = std::make_shared<Fiber>([&test_control] { test_control.DoWork2(); });
test_control.fiber2 = test_control.fiber3 = std::make_shared<Fiber>([&test_control] { test_control.DoWork3(); });
std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_2}, &test_control); std::thread thread1{[&test_control] {
test_control.fiber3 = test_control.ExecuteThread(0);
std::make_shared<Fiber>(std::function<void(void*)>{WorkControl2_3}, &test_control); test_control.CallFiber1();
std::thread thread1(ThreadStart2_1, 0, std::ref(test_control)); test_control.Exit();
std::thread thread2(ThreadStart2_2, 1, std::ref(test_control)); }};
std::thread thread2{[&test_control] {
test_control.ExecuteThread(1);
test_control.CallFiber2();
test_control.Exit();
}};
thread1.join(); thread1.join();
thread2.join(); thread2.join();
REQUIRE(test_control.assert1); REQUIRE(test_control.assert1);
@ -270,16 +237,6 @@ public:
std::shared_ptr<Common::Fiber> fiber2; std::shared_ptr<Common::Fiber> fiber2;
}; };
static void WorkControl3_1(void* control) {
auto* test_control = static_cast<TestControl3*>(control);
test_control->DoWork1();
}
static void WorkControl3_2(void* control) {
auto* test_control = static_cast<TestControl3*>(control);
test_control->DoWork2();
}
void TestControl3::ExecuteThread(u32 id) { void TestControl3::ExecuteThread(u32 id) {
thread_ids.Register(id); thread_ids.Register(id);
auto thread_fiber = Fiber::ThreadToFiber(); auto thread_fiber = Fiber::ThreadToFiber();
@ -291,12 +248,6 @@ void TestControl3::Exit() {
thread_fibers[id]->Exit(); thread_fibers[id]->Exit();
} }
static void ThreadStart3(u32 id, TestControl3& test_control) {
test_control.ExecuteThread(id);
test_control.CallFiber1();
test_control.Exit();
}
/** This test checks for one two threads racing for starting the same fiber. /** This test checks for one two threads racing for starting the same fiber.
* It checks execution occurred in an ordered manner and by no time there were * It checks execution occurred in an ordered manner and by no time there were
* two contexts at the same time. * two contexts at the same time.
@ -304,12 +255,15 @@ static void ThreadStart3(u32 id, TestControl3& test_control) {
TEST_CASE("Fibers::StartRace", "[common]") { TEST_CASE("Fibers::StartRace", "[common]") {
TestControl3 test_control{}; TestControl3 test_control{};
test_control.thread_fibers.resize(2); test_control.thread_fibers.resize(2);
test_control.fiber1 = test_control.fiber1 = std::make_shared<Fiber>([&test_control] { test_control.DoWork1(); });
std::make_shared<Fiber>(std::function<void(void*)>{WorkControl3_1}, &test_control); test_control.fiber2 = std::make_shared<Fiber>([&test_control] { test_control.DoWork2(); });
test_control.fiber2 = const auto race_function{[&test_control](u32 id) {
std::make_shared<Fiber>(std::function<void(void*)>{WorkControl3_2}, &test_control); test_control.ExecuteThread(id);
std::thread thread1(ThreadStart3, 0, std::ref(test_control)); test_control.CallFiber1();
std::thread thread2(ThreadStart3, 1, std::ref(test_control)); test_control.Exit();
}};
std::thread thread1([&] { race_function(0); });
std::thread thread2([&] { race_function(1); });
thread1.join(); thread1.join();
thread2.join(); thread2.join();
REQUIRE(test_control.value1 == 1); REQUIRE(test_control.value1 == 1);
@ -319,12 +273,10 @@ TEST_CASE("Fibers::StartRace", "[common]") {
class TestControl4; class TestControl4;
static void WorkControl4(void* control);
class TestControl4 { class TestControl4 {
public: public:
TestControl4() { TestControl4() {
fiber1 = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl4}, this); fiber1 = std::make_shared<Fiber>([this] { DoWork(); });
goal_reached = false; goal_reached = false;
rewinded = false; rewinded = false;
} }
@ -336,7 +288,7 @@ public:
} }
void DoWork() { void DoWork() {
fiber1->SetRewindPoint(std::function<void(void*)>{WorkControl4}, this); fiber1->SetRewindPoint([this] { DoWork(); });
if (rewinded) { if (rewinded) {
goal_reached = true; goal_reached = true;
Fiber::YieldTo(fiber1, *thread_fiber); Fiber::YieldTo(fiber1, *thread_fiber);
@ -351,11 +303,6 @@ public:
bool rewinded; bool rewinded;
}; };
static void WorkControl4(void* control) {
auto* test_control = static_cast<TestControl4*>(control);
test_control->DoWork();
}
TEST_CASE("Fibers::Rewind", "[common]") { TEST_CASE("Fibers::Rewind", "[common]") {
TestControl4 test_control{}; TestControl4 test_control{};
test_control.Execute(); test_control.Execute();