From bc266a9d98f38f6fd1006f1ca52bd57e6a7f37d3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 4 Feb 2020 15:06:23 -0400 Subject: Common: Implement a basic Fiber class. --- src/common/fiber.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/common/fiber.h (limited to 'src/common/fiber.h') diff --git a/src/common/fiber.h b/src/common/fiber.h new file mode 100644 index 000000000..ab44905cf --- /dev/null +++ b/src/common/fiber.h @@ -0,0 +1,55 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "common/spin_lock.h" + +namespace Common { + +class Fiber { +public: + Fiber(std::function&& entry_point_func, void* start_parameter); + ~Fiber(); + + Fiber(const Fiber&) = delete; + Fiber& operator=(const Fiber&) = delete; + + Fiber(Fiber&&) = default; + Fiber& operator=(Fiber&&) = default; + + /// Yields control from Fiber 'from' to Fiber 'to' + /// Fiber 'from' must be the currently running fiber. + static void YieldTo(std::shared_ptr from, std::shared_ptr to); + static std::shared_ptr ThreadToFiber(); + + /// Only call from main thread's fiber + void Exit(); + + /// Used internally but required to be public, Shall not be used + void _start(void* parameter); + + /// Changes the start parameter of the fiber. Has no effect if the fiber already started + void SetStartParameter(void* new_parameter) { + start_parameter = new_parameter; + } + +private: + Fiber(); + + struct FiberImpl; + + SpinLock guard; + std::function entry_point; + void* start_parameter; + std::shared_ptr previous_fiber; + std::unique_ptr impl; + bool is_thread_fiber{}; +}; + +} // namespace Common -- cgit v1.2.3 From 8d0e3c542258cc50081af93aa85e0e3cbf8900c3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 5 Feb 2020 14:13:16 -0400 Subject: Tests: Add tests for fibers and refactor/fix Fiber class --- src/common/fiber.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'src/common/fiber.h') diff --git a/src/common/fiber.h b/src/common/fiber.h index ab44905cf..812d6644a 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -10,6 +10,12 @@ #include "common/common_types.h" #include "common/spin_lock.h" +#ifndef _MSC_VER +namespace boost::context::detail { + struct transfer_t; +} +#endif + namespace Common { class Fiber { @@ -31,9 +37,6 @@ public: /// Only call from main thread's fiber void Exit(); - /// Used internally but required to be public, Shall not be used - void _start(void* parameter); - /// Changes the start parameter of the fiber. Has no effect if the fiber already started void SetStartParameter(void* new_parameter) { start_parameter = new_parameter; @@ -42,6 +45,16 @@ public: private: Fiber(); +#ifdef _MSC_VER + void start(); + static void FiberStartFunc(void* fiber_parameter); +#else + void start(boost::context::detail::transfer_t& transfer); + static void FiberStartFunc(boost::context::detail::transfer_t transfer); +#endif + + + struct FiberImpl; SpinLock guard; -- cgit v1.2.3 From be320a9e10fda32a984b12cdfe3aaf09cc67b39a Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 5 Feb 2020 15:48:20 -0400 Subject: Common: Polish Fiber class, add comments, asserts and more tests. --- src/common/fiber.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/common/fiber.h') diff --git a/src/common/fiber.h b/src/common/fiber.h index 812d6644a..89a01fdd8 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -18,6 +18,18 @@ namespace boost::context::detail { namespace Common { +/** + * Fiber class + * a fiber is a userspace thread with it's own context. They can be used to + * implement coroutines, emulated threading systems and certain asynchronous + * patterns. + * + * This class implements fibers at a low level, thus allowing greater freedom + * to implement such patterns. This fiber class is 'threadsafe' only one fiber + * can be running at a time and threads will be locked while trying to yield to + * a running fiber until it yields. WARNING exchanging two running fibers between + * threads will cause a deadlock. + */ class Fiber { public: Fiber(std::function&& entry_point_func, void* start_parameter); @@ -53,8 +65,6 @@ private: static void FiberStartFunc(boost::context::detail::transfer_t transfer); #endif - - struct FiberImpl; SpinLock guard; -- cgit v1.2.3 From 1bd706344e2381e11245b2f0bdc291429e46c634 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 10 Feb 2020 13:33:13 -0400 Subject: Common/Tests: Clang Format. --- src/common/fiber.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/common/fiber.h') diff --git a/src/common/fiber.h b/src/common/fiber.h index 89a01fdd8..b530bf4d2 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -12,7 +12,7 @@ #ifndef _MSC_VER namespace boost::context::detail { - struct transfer_t; +struct transfer_t; } #endif -- cgit v1.2.3 From 3398f701eeac63f3cfcf193f3e9c1ee2f06edb08 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 10 Feb 2020 14:21:23 -0400 Subject: Common: Make MinGW build use Windows Fibers instead of fcontext_t --- src/common/fiber.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/common/fiber.h') diff --git a/src/common/fiber.h b/src/common/fiber.h index b530bf4d2..598fe7daa 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -10,7 +10,7 @@ #include "common/common_types.h" #include "common/spin_lock.h" -#ifndef _MSC_VER +#if !defined(_WIN32) && !defined(WIN32) namespace boost::context::detail { struct transfer_t; } @@ -57,7 +57,7 @@ public: private: Fiber(); -#ifdef _MSC_VER +#if defined(_WIN32) || defined(WIN32) void start(); static void FiberStartFunc(void* fiber_parameter); #else -- cgit v1.2.3 From 1f7dd36499786d373b143a4437d4c32e077a32aa Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 10 Feb 2020 14:45:08 -0400 Subject: Common/Tests: Address Feedback --- src/common/fiber.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/common/fiber.h') diff --git a/src/common/fiber.h b/src/common/fiber.h index 598fe7daa..7e3b130a4 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -67,10 +67,10 @@ private: struct FiberImpl; - SpinLock guard; - std::function entry_point; - void* start_parameter; - std::shared_ptr previous_fiber; + SpinLock guard{}; + std::function entry_point{}; + void* start_parameter{}; + std::shared_ptr previous_fiber{}; std::unique_ptr impl; bool is_thread_fiber{}; }; -- cgit v1.2.3 From 137d862d9b275209b3d62a413396a15e9e14b4b4 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 27 Feb 2020 16:32:47 -0400 Subject: Common/Fiber: Implement Rewinding. --- src/common/fiber.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/common/fiber.h') diff --git a/src/common/fiber.h b/src/common/fiber.h index 7e3b130a4..a710df257 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -46,6 +46,10 @@ public: static void YieldTo(std::shared_ptr from, std::shared_ptr to); static std::shared_ptr ThreadToFiber(); + void SetRewindPoint(std::function&& rewind_func, void* start_parameter); + + void Rewind(); + /// Only call from main thread's fiber void Exit(); @@ -58,8 +62,10 @@ 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 start(boost::context::detail::transfer_t& transfer); static void FiberStartFunc(boost::context::detail::transfer_t transfer); @@ -69,6 +75,8 @@ private: SpinLock guard{}; std::function entry_point{}; + std::function rewind_point{}; + void* rewind_parameter{}; void* start_parameter{}; std::shared_ptr previous_fiber{}; std::unique_ptr impl; -- cgit v1.2.3 From 18f54f74862322d5a9360cbdc3541b6e3f15dce6 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 11:24:08 -0400 Subject: Common/Fiber: Document fiber interexchange. --- src/common/fiber.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/common/fiber.h') diff --git a/src/common/fiber.h b/src/common/fiber.h index a710df257..3bbd506b5 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -28,7 +28,10 @@ namespace Common { * to implement such patterns. This fiber class is 'threadsafe' only one fiber * can be running at a time and threads will be locked while trying to yield to * a running fiber until it yields. WARNING exchanging two running fibers between - * threads will cause a deadlock. + * threads will cause a deadlock. In order to prevent a deadlock, each thread should + * have an intermediary fiber, you switch to the intermediary fiber of the current + * thread and then from it switch to the expected fiber. This way you can exchange + * 2 fibers within 2 different threads. */ class Fiber { public: -- cgit v1.2.3 From b6655aa2e492e326e319b09e832c1612bf27acf4 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 1 Apr 2020 09:19:10 -0400 Subject: Common/Fiber: Implement Rewind on Boost Context. --- src/common/fiber.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/common/fiber.h') diff --git a/src/common/fiber.h b/src/common/fiber.h index 3bbd506b5..cab7bc4b5 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -70,8 +70,10 @@ private: 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; -- cgit v1.2.3 From e77ee67bfacf9a0d3b9e7cd164531a2be158adc9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 13 May 2020 13:49:36 -0400 Subject: Common/Fiber: Address Feedback and Correct Memory leaks. --- src/common/fiber.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/common/fiber.h') diff --git a/src/common/fiber.h b/src/common/fiber.h index cab7bc4b5..dafc1100e 100644 --- a/src/common/fiber.h +++ b/src/common/fiber.h @@ -46,7 +46,7 @@ public: /// Yields control from Fiber 'from' to Fiber 'to' /// Fiber 'from' must be the currently running fiber. - static void YieldTo(std::shared_ptr from, std::shared_ptr to); + static void YieldTo(std::shared_ptr& from, std::shared_ptr& to); static std::shared_ptr ThreadToFiber(); void SetRewindPoint(std::function&& rewind_func, void* start_parameter); @@ -65,13 +65,13 @@ private: Fiber(); #if defined(_WIN32) || defined(WIN32) - void onRewind(); - void start(); + 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); + 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 @@ -79,13 +79,14 @@ private: struct FiberImpl; SpinLock guard{}; - std::function entry_point{}; - std::function rewind_point{}; + std::function entry_point; + std::function rewind_point; void* rewind_parameter{}; void* start_parameter{}; - std::shared_ptr previous_fiber{}; + std::shared_ptr previous_fiber; std::unique_ptr impl; bool is_thread_fiber{}; + bool released{}; }; } // namespace Common -- cgit v1.2.3