summaryrefslogtreecommitdiff
path: root/src/common/fiber.cpp
diff options
context:
space:
mode:
authorGravatar Levi2021-01-10 22:09:56 -0700
committerGravatar Levi2021-01-10 22:09:56 -0700
commit7a3c884e39fccfbb498b855080bffabc9ce2e7f1 (patch)
tree5056f9406dec188439cb0deb87603498243a9412 /src/common/fiber.cpp
parentMore forgetting... duh (diff)
parentMerge pull request #5229 from Morph1984/fullscreen-opt (diff)
downloadyuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.gz
yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.xz
yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.zip
Merge remote-tracking branch 'upstream/master' into int-flags
Diffstat (limited to 'src/common/fiber.cpp')
-rw-r--r--src/common/fiber.cpp194
1 files changed, 55 insertions, 139 deletions
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp
index 1c1d09ccb..3c1eefcb7 100644
--- a/src/common/fiber.cpp
+++ b/src/common/fiber.cpp
@@ -4,129 +4,51 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/fiber.h" 6#include "common/fiber.h"
7#if defined(_WIN32) || defined(WIN32) 7#include "common/spin_lock.h"
8#include <windows.h> 8#include "common/virtual_buffer.h"
9#else 9
10#include <boost/context/detail/fcontext.hpp> 10#include <boost/context/detail/fcontext.hpp>
11#endif
12 11
13namespace Common { 12namespace Common {
14 13
15constexpr std::size_t default_stack_size = 256 * 1024; // 256kb 14constexpr std::size_t default_stack_size = 256 * 1024;
16
17#if defined(_WIN32) || defined(WIN32)
18 15
19struct Fiber::FiberImpl { 16struct Fiber::FiberImpl {
20 LPVOID handle = nullptr; 17 FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {}
21 LPVOID rewind_handle = nullptr; 18
19 VirtualBuffer<u8> stack;
20 VirtualBuffer<u8> rewind_stack;
21
22 SpinLock guard{};
23 std::function<void(void*)> entry_point;
24 std::function<void(void*)> rewind_point;
25 void* rewind_parameter{};
26 void* start_parameter{};
27 std::shared_ptr<Fiber> previous_fiber;
28 bool is_thread_fiber{};
29 bool released{};
30
31 u8* stack_limit{};
32 u8* rewind_stack_limit{};
33 boost::context::detail::fcontext_t context{};
34 boost::context::detail::fcontext_t rewind_context{};
22}; 35};
23 36
24void Fiber::Start() { 37void Fiber::SetStartParameter(void* new_parameter) {
25 ASSERT(previous_fiber != nullptr); 38 impl->start_parameter = new_parameter;
26 previous_fiber->guard.unlock();
27 previous_fiber.reset();
28 entry_point(start_parameter);
29 UNREACHABLE();
30}
31
32void Fiber::OnRewind() {
33 ASSERT(impl->handle != nullptr);
34 DeleteFiber(impl->handle);
35 impl->handle = impl->rewind_handle;
36 impl->rewind_handle = nullptr;
37 rewind_point(rewind_parameter);
38 UNREACHABLE();
39}
40
41void Fiber::FiberStartFunc(void* fiber_parameter) {
42 auto fiber = static_cast<Fiber*>(fiber_parameter);
43 fiber->Start();
44}
45
46void Fiber::RewindStartFunc(void* fiber_parameter) {
47 auto fiber = static_cast<Fiber*>(fiber_parameter);
48 fiber->OnRewind();
49}
50
51Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
52 : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} {
53 impl = std::make_unique<FiberImpl>();
54 impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this);
55}
56
57Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
58
59Fiber::~Fiber() {
60 if (released) {
61 return;
62 }
63 // Make sure the Fiber is not being used
64 const bool locked = guard.try_lock();
65 ASSERT_MSG(locked, "Destroying a fiber that's still running");
66 if (locked) {
67 guard.unlock();
68 }
69 DeleteFiber(impl->handle);
70}
71
72void Fiber::Exit() {
73 ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber");
74 if (!is_thread_fiber) {
75 return;
76 }
77 ConvertFiberToThread();
78 guard.unlock();
79 released = true;
80}
81
82void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) {
83 rewind_point = std::move(rewind_func);
84 rewind_parameter = start_parameter;
85}
86
87void Fiber::Rewind() {
88 ASSERT(rewind_point);
89 ASSERT(impl->rewind_handle == nullptr);
90 impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this);
91 SwitchToFiber(impl->rewind_handle);
92}
93
94void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) {
95 ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
96 ASSERT_MSG(to != nullptr, "Next fiber is null!");
97 to->guard.lock();
98 to->previous_fiber = from;
99 SwitchToFiber(to->impl->handle);
100 ASSERT(from->previous_fiber != nullptr);
101 from->previous_fiber->guard.unlock();
102 from->previous_fiber.reset();
103} 39}
104 40
105std::shared_ptr<Fiber> Fiber::ThreadToFiber() { 41void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
106 std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; 42 impl->rewind_point = std::move(rewind_func);
107 fiber->guard.lock(); 43 impl->rewind_parameter = rewind_param;
108 fiber->impl->handle = ConvertThreadToFiber(nullptr);
109 fiber->is_thread_fiber = true;
110 return fiber;
111} 44}
112 45
113#else
114
115struct Fiber::FiberImpl {
116 alignas(64) std::array<u8, default_stack_size> stack;
117 alignas(64) std::array<u8, default_stack_size> rewind_stack;
118 u8* stack_limit;
119 u8* rewind_stack_limit;
120 boost::context::detail::fcontext_t context;
121 boost::context::detail::fcontext_t rewind_context;
122};
123
124void Fiber::Start(boost::context::detail::transfer_t& transfer) { 46void Fiber::Start(boost::context::detail::transfer_t& transfer) {
125 ASSERT(previous_fiber != nullptr); 47 ASSERT(impl->previous_fiber != nullptr);
126 previous_fiber->impl->context = transfer.fctx; 48 impl->previous_fiber->impl->context = transfer.fctx;
127 previous_fiber->guard.unlock(); 49 impl->previous_fiber->impl->guard.unlock();
128 previous_fiber.reset(); 50 impl->previous_fiber.reset();
129 entry_point(start_parameter); 51 impl->entry_point(impl->start_parameter);
130 UNREACHABLE(); 52 UNREACHABLE();
131} 53}
132 54
@@ -137,23 +59,24 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf
137 u8* tmp = impl->stack_limit; 59 u8* tmp = impl->stack_limit;
138 impl->stack_limit = impl->rewind_stack_limit; 60 impl->stack_limit = impl->rewind_stack_limit;
139 impl->rewind_stack_limit = tmp; 61 impl->rewind_stack_limit = tmp;
140 rewind_point(rewind_parameter); 62 impl->rewind_point(impl->rewind_parameter);
141 UNREACHABLE(); 63 UNREACHABLE();
142} 64}
143 65
144void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { 66void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) {
145 auto fiber = static_cast<Fiber*>(transfer.data); 67 auto* fiber = static_cast<Fiber*>(transfer.data);
146 fiber->Start(transfer); 68 fiber->Start(transfer);
147} 69}
148 70
149void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { 71void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) {
150 auto fiber = static_cast<Fiber*>(transfer.data); 72 auto* fiber = static_cast<Fiber*>(transfer.data);
151 fiber->OnRewind(transfer); 73 fiber->OnRewind(transfer);
152} 74}
153 75
154Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) 76Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
155 : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { 77 : impl{std::make_unique<FiberImpl>()} {
156 impl = std::make_unique<FiberImpl>(); 78 impl->entry_point = std::move(entry_point_func);
79 impl->start_parameter = start_parameter;
157 impl->stack_limit = impl->stack.data(); 80 impl->stack_limit = impl->stack.data();
158 impl->rewind_stack_limit = impl->rewind_stack.data(); 81 impl->rewind_stack_limit = impl->rewind_stack.data();
159 u8* stack_base = impl->stack_limit + default_stack_size; 82 u8* stack_base = impl->stack_limit + default_stack_size;
@@ -161,37 +84,31 @@ Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_paramete
161 boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc); 84 boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc);
162} 85}
163 86
164void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) {
165 rewind_point = std::move(rewind_func);
166 rewind_parameter = start_parameter;
167}
168
169Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} 87Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
170 88
171Fiber::~Fiber() { 89Fiber::~Fiber() {
172 if (released) { 90 if (impl->released) {
173 return; 91 return;
174 } 92 }
175 // Make sure the Fiber is not being used 93 // Make sure the Fiber is not being used
176 const bool locked = guard.try_lock(); 94 const bool locked = impl->guard.try_lock();
177 ASSERT_MSG(locked, "Destroying a fiber that's still running"); 95 ASSERT_MSG(locked, "Destroying a fiber that's still running");
178 if (locked) { 96 if (locked) {
179 guard.unlock(); 97 impl->guard.unlock();
180 } 98 }
181} 99}
182 100
183void Fiber::Exit() { 101void Fiber::Exit() {
184 102 ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
185 ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); 103 if (!impl->is_thread_fiber) {
186 if (!is_thread_fiber) {
187 return; 104 return;
188 } 105 }
189 guard.unlock(); 106 impl->guard.unlock();
190 released = true; 107 impl->released = true;
191} 108}
192 109
193void Fiber::Rewind() { 110void Fiber::Rewind() {
194 ASSERT(rewind_point); 111 ASSERT(impl->rewind_point);
195 ASSERT(impl->rewind_context == nullptr); 112 ASSERT(impl->rewind_context == nullptr);
196 u8* stack_base = impl->rewind_stack_limit + default_stack_size; 113 u8* stack_base = impl->rewind_stack_limit + default_stack_size;
197 impl->rewind_context = 114 impl->rewind_context =
@@ -199,24 +116,23 @@ void Fiber::Rewind() {
199 boost::context::detail::jump_fcontext(impl->rewind_context, this); 116 boost::context::detail::jump_fcontext(impl->rewind_context, this);
200} 117}
201 118
202void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) { 119void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
203 ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); 120 ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
204 ASSERT_MSG(to != nullptr, "Next fiber is null!"); 121 ASSERT_MSG(to != nullptr, "Next fiber is null!");
205 to->guard.lock(); 122 to->impl->guard.lock();
206 to->previous_fiber = from; 123 to->impl->previous_fiber = from;
207 auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); 124 auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get());
208 ASSERT(from->previous_fiber != nullptr); 125 ASSERT(from->impl->previous_fiber != nullptr);
209 from->previous_fiber->impl->context = transfer.fctx; 126 from->impl->previous_fiber->impl->context = transfer.fctx;
210 from->previous_fiber->guard.unlock(); 127 from->impl->previous_fiber->impl->guard.unlock();
211 from->previous_fiber.reset(); 128 from->impl->previous_fiber.reset();
212} 129}
213 130
214std::shared_ptr<Fiber> Fiber::ThreadToFiber() { 131std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
215 std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; 132 std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
216 fiber->guard.lock(); 133 fiber->impl->guard.lock();
217 fiber->is_thread_fiber = true; 134 fiber->impl->is_thread_fiber = true;
218 return fiber; 135 return fiber;
219} 136}
220 137
221#endif
222} // namespace Common 138} // namespace Common