diff options
Diffstat (limited to 'src/common/fiber.cpp')
| -rw-r--r-- | src/common/fiber.cpp | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index f61479e13..6ea314d75 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp | |||
| @@ -113,7 +113,11 @@ std::shared_ptr<Fiber> Fiber::ThreadToFiber() { | |||
| 113 | 113 | ||
| 114 | struct Fiber::FiberImpl { | 114 | struct Fiber::FiberImpl { |
| 115 | alignas(64) std::array<u8, default_stack_size> stack; | 115 | alignas(64) std::array<u8, default_stack_size> stack; |
| 116 | u8* stack_limit; | ||
| 117 | alignas(64) std::array<u8, default_stack_size> rewind_stack; | ||
| 118 | u8* rewind_stack_limit; | ||
| 116 | boost::context::detail::fcontext_t context; | 119 | boost::context::detail::fcontext_t context; |
| 120 | boost::context::detail::fcontext_t rewind_context; | ||
| 117 | }; | 121 | }; |
| 118 | 122 | ||
| 119 | void Fiber::start(boost::context::detail::transfer_t& transfer) { | 123 | void Fiber::start(boost::context::detail::transfer_t& transfer) { |
| @@ -125,21 +129,43 @@ void Fiber::start(boost::context::detail::transfer_t& transfer) { | |||
| 125 | UNREACHABLE(); | 129 | UNREACHABLE(); |
| 126 | } | 130 | } |
| 127 | 131 | ||
| 132 | void Fiber::onRewind(boost::context::detail::transfer_t& [[maybe_unused]] transfer) { | ||
| 133 | ASSERT(impl->context != nullptr); | ||
| 134 | impl->context = impl->rewind_context; | ||
| 135 | impl->rewind_context = nullptr; | ||
| 136 | u8* tmp = impl->stack_limit; | ||
| 137 | impl->stack_limit = impl->rewind_stack_limit; | ||
| 138 | impl->rewind_stack_limit = tmp; | ||
| 139 | rewind_point(rewind_parameter); | ||
| 140 | UNREACHABLE(); | ||
| 141 | } | ||
| 142 | |||
| 128 | void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { | 143 | void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { |
| 129 | auto fiber = static_cast<Fiber*>(transfer.data); | 144 | auto fiber = static_cast<Fiber*>(transfer.data); |
| 130 | fiber->start(transfer); | 145 | fiber->start(transfer); |
| 131 | } | 146 | } |
| 132 | 147 | ||
| 148 | void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { | ||
| 149 | auto fiber = static_cast<Fiber*>(transfer.data); | ||
| 150 | fiber->onRewind(transfer); | ||
| 151 | } | ||
| 152 | |||
| 133 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) | 153 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) |
| 134 | : guard{}, entry_point{std::move(entry_point_func)}, start_parameter{start_parameter}, | 154 | : guard{}, entry_point{std::move(entry_point_func)}, start_parameter{start_parameter}, |
| 135 | previous_fiber{} { | 155 | previous_fiber{} { |
| 136 | impl = std::make_unique<FiberImpl>(); | 156 | impl = std::make_unique<FiberImpl>(); |
| 137 | u8* stack_limit = impl->stack.data(); | 157 | impl->stack_limit = impl->stack.data(); |
| 138 | u8* stack_base = stack_limit + default_stack_size; | 158 | impl->rewind_stack_limit = impl->rewind_stack.data(); |
| 159 | u8* stack_base = impl->stack_limit + default_stack_size; | ||
| 139 | impl->context = | 160 | impl->context = |
| 140 | boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc); | 161 | boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc); |
| 141 | } | 162 | } |
| 142 | 163 | ||
| 164 | void 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 | |||
| 143 | Fiber::Fiber() { | 169 | Fiber::Fiber() { |
| 144 | impl = std::make_unique<FiberImpl>(); | 170 | impl = std::make_unique<FiberImpl>(); |
| 145 | } | 171 | } |
| @@ -161,6 +187,15 @@ void Fiber::Exit() { | |||
| 161 | guard.unlock(); | 187 | guard.unlock(); |
| 162 | } | 188 | } |
| 163 | 189 | ||
| 190 | void Fiber::Rewind() { | ||
| 191 | ASSERT(rewind_point); | ||
| 192 | ASSERT(impl->rewind_context == nullptr); | ||
| 193 | u8* stack_base = impl->rewind_stack_limit + default_stack_size; | ||
| 194 | impl->rewind_context = | ||
| 195 | boost::context::detail::make_fcontext(stack_base, impl->stack.size(), RewindStartFunc); | ||
| 196 | boost::context::detail::jump_fcontext(impl->rewind_context, this); | ||
| 197 | } | ||
| 198 | |||
| 164 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { | 199 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { |
| 165 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); | 200 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); |
| 166 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); | 201 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); |