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