diff options
| -rw-r--r-- | src/common/fiber.cpp | 58 | ||||
| -rw-r--r-- | src/common/fiber.h | 17 |
2 files changed, 41 insertions, 34 deletions
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 6ea314d75..f97ad433b 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp | |||
| @@ -21,7 +21,7 @@ struct Fiber::FiberImpl { | |||
| 21 | LPVOID rewind_handle = nullptr; | 21 | LPVOID rewind_handle = nullptr; |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | void Fiber::start() { | 24 | void Fiber::Start() { |
| 25 | ASSERT(previous_fiber != nullptr); | 25 | ASSERT(previous_fiber != nullptr); |
| 26 | previous_fiber->guard.unlock(); | 26 | previous_fiber->guard.unlock(); |
| 27 | previous_fiber.reset(); | 27 | previous_fiber.reset(); |
| @@ -29,7 +29,7 @@ void Fiber::start() { | |||
| 29 | UNREACHABLE(); | 29 | UNREACHABLE(); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | void Fiber::onRewind() { | 32 | void Fiber::OnRewind() { |
| 33 | ASSERT(impl->handle != nullptr); | 33 | ASSERT(impl->handle != nullptr); |
| 34 | DeleteFiber(impl->handle); | 34 | DeleteFiber(impl->handle); |
| 35 | impl->handle = impl->rewind_handle; | 35 | impl->handle = impl->rewind_handle; |
| @@ -38,14 +38,14 @@ void Fiber::onRewind() { | |||
| 38 | UNREACHABLE(); | 38 | UNREACHABLE(); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | void __stdcall Fiber::FiberStartFunc(void* fiber_parameter) { | 41 | void Fiber::FiberStartFunc(void* fiber_parameter) { |
| 42 | auto fiber = static_cast<Fiber*>(fiber_parameter); | 42 | auto fiber = static_cast<Fiber*>(fiber_parameter); |
| 43 | fiber->start(); | 43 | fiber->Start(); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void __stdcall Fiber::RewindStartFunc(void* fiber_parameter) { | 46 | void Fiber::RewindStartFunc(void* fiber_parameter) { |
| 47 | auto fiber = static_cast<Fiber*>(fiber_parameter); | 47 | auto fiber = static_cast<Fiber*>(fiber_parameter); |
| 48 | fiber->onRewind(); | 48 | fiber->OnRewind(); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) | 51 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) |
| @@ -59,8 +59,11 @@ Fiber::Fiber() { | |||
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | Fiber::~Fiber() { | 61 | Fiber::~Fiber() { |
| 62 | if (released) { | ||
| 63 | return; | ||
| 64 | } | ||
| 62 | // Make sure the Fiber is not being used | 65 | // Make sure the Fiber is not being used |
| 63 | bool locked = guard.try_lock(); | 66 | const bool locked = guard.try_lock(); |
| 64 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); | 67 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); |
| 65 | if (locked) { | 68 | if (locked) { |
| 66 | guard.unlock(); | 69 | guard.unlock(); |
| @@ -75,6 +78,7 @@ void Fiber::Exit() { | |||
| 75 | } | 78 | } |
| 76 | ConvertFiberToThread(); | 79 | ConvertFiberToThread(); |
| 77 | guard.unlock(); | 80 | guard.unlock(); |
| 81 | released = true; | ||
| 78 | } | 82 | } |
| 79 | 83 | ||
| 80 | void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) { | 84 | void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) { |
| @@ -89,22 +93,21 @@ void Fiber::Rewind() { | |||
| 89 | SwitchToFiber(impl->rewind_handle); | 93 | SwitchToFiber(impl->rewind_handle); |
| 90 | } | 94 | } |
| 91 | 95 | ||
| 92 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { | 96 | void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) { |
| 93 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); | 97 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); |
| 94 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); | 98 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); |
| 95 | to->guard.lock(); | 99 | to->guard.lock(); |
| 96 | to->previous_fiber = from; | 100 | to->previous_fiber = from; |
| 97 | SwitchToFiber(to->impl->handle); | 101 | SwitchToFiber(to->impl->handle); |
| 98 | auto previous_fiber = from->previous_fiber; | 102 | ASSERT(from->previous_fiber != nullptr); |
| 99 | ASSERT(previous_fiber != nullptr); | 103 | from->previous_fiber->guard.unlock(); |
| 100 | previous_fiber->guard.unlock(); | 104 | from->previous_fiber.reset(); |
| 101 | previous_fiber.reset(); | ||
| 102 | } | 105 | } |
| 103 | 106 | ||
| 104 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { | 107 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { |
| 105 | std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; | 108 | std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; |
| 106 | fiber->guard.lock(); | 109 | fiber->guard.lock(); |
| 107 | fiber->impl->handle = ConvertThreadToFiber(NULL); | 110 | fiber->impl->handle = ConvertThreadToFiber(nullptr); |
| 108 | fiber->is_thread_fiber = true; | 111 | fiber->is_thread_fiber = true; |
| 109 | return fiber; | 112 | return fiber; |
| 110 | } | 113 | } |
| @@ -120,7 +123,7 @@ struct Fiber::FiberImpl { | |||
| 120 | boost::context::detail::fcontext_t rewind_context; | 123 | boost::context::detail::fcontext_t rewind_context; |
| 121 | }; | 124 | }; |
| 122 | 125 | ||
| 123 | void Fiber::start(boost::context::detail::transfer_t& transfer) { | 126 | void Fiber::Start(boost::context::detail::transfer_t& transfer) { |
| 124 | ASSERT(previous_fiber != nullptr); | 127 | ASSERT(previous_fiber != nullptr); |
| 125 | previous_fiber->impl->context = transfer.fctx; | 128 | previous_fiber->impl->context = transfer.fctx; |
| 126 | previous_fiber->guard.unlock(); | 129 | previous_fiber->guard.unlock(); |
| @@ -129,7 +132,7 @@ void Fiber::start(boost::context::detail::transfer_t& transfer) { | |||
| 129 | UNREACHABLE(); | 132 | UNREACHABLE(); |
| 130 | } | 133 | } |
| 131 | 134 | ||
| 132 | void Fiber::onRewind(boost::context::detail::transfer_t& [[maybe_unused]] transfer) { | 135 | void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transfer) { |
| 133 | ASSERT(impl->context != nullptr); | 136 | ASSERT(impl->context != nullptr); |
| 134 | impl->context = impl->rewind_context; | 137 | impl->context = impl->rewind_context; |
| 135 | impl->rewind_context = nullptr; | 138 | impl->rewind_context = nullptr; |
| @@ -142,17 +145,16 @@ void Fiber::onRewind(boost::context::detail::transfer_t& [[maybe_unused]] transf | |||
| 142 | 145 | ||
| 143 | void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { | 146 | void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { |
| 144 | auto fiber = static_cast<Fiber*>(transfer.data); | 147 | auto fiber = static_cast<Fiber*>(transfer.data); |
| 145 | fiber->start(transfer); | 148 | fiber->Start(transfer); |
| 146 | } | 149 | } |
| 147 | 150 | ||
| 148 | void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { | 151 | void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { |
| 149 | auto fiber = static_cast<Fiber*>(transfer.data); | 152 | auto fiber = static_cast<Fiber*>(transfer.data); |
| 150 | fiber->onRewind(transfer); | 153 | fiber->OnRewind(transfer); |
| 151 | } | 154 | } |
| 152 | 155 | ||
| 153 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) | 156 | Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) |
| 154 | : guard{}, entry_point{std::move(entry_point_func)}, start_parameter{start_parameter}, | 157 | : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { |
| 155 | previous_fiber{} { | ||
| 156 | impl = std::make_unique<FiberImpl>(); | 158 | impl = std::make_unique<FiberImpl>(); |
| 157 | impl->stack_limit = impl->stack.data(); | 159 | impl->stack_limit = impl->stack.data(); |
| 158 | impl->rewind_stack_limit = impl->rewind_stack.data(); | 160 | impl->rewind_stack_limit = impl->rewind_stack.data(); |
| @@ -171,8 +173,11 @@ Fiber::Fiber() { | |||
| 171 | } | 173 | } |
| 172 | 174 | ||
| 173 | Fiber::~Fiber() { | 175 | Fiber::~Fiber() { |
| 176 | if (released) { | ||
| 177 | return; | ||
| 178 | } | ||
| 174 | // Make sure the Fiber is not being used | 179 | // Make sure the Fiber is not being used |
| 175 | bool locked = guard.try_lock(); | 180 | const bool locked = guard.try_lock(); |
| 176 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); | 181 | ASSERT_MSG(locked, "Destroying a fiber that's still running"); |
| 177 | if (locked) { | 182 | if (locked) { |
| 178 | guard.unlock(); | 183 | guard.unlock(); |
| @@ -180,11 +185,13 @@ Fiber::~Fiber() { | |||
| 180 | } | 185 | } |
| 181 | 186 | ||
| 182 | void Fiber::Exit() { | 187 | void Fiber::Exit() { |
| 188 | |||
| 183 | ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); | 189 | ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); |
| 184 | if (!is_thread_fiber) { | 190 | if (!is_thread_fiber) { |
| 185 | return; | 191 | return; |
| 186 | } | 192 | } |
| 187 | guard.unlock(); | 193 | guard.unlock(); |
| 194 | released = true; | ||
| 188 | } | 195 | } |
| 189 | 196 | ||
| 190 | void Fiber::Rewind() { | 197 | void Fiber::Rewind() { |
| @@ -196,17 +203,16 @@ void Fiber::Rewind() { | |||
| 196 | boost::context::detail::jump_fcontext(impl->rewind_context, this); | 203 | boost::context::detail::jump_fcontext(impl->rewind_context, this); |
| 197 | } | 204 | } |
| 198 | 205 | ||
| 199 | void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) { | 206 | void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) { |
| 200 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); | 207 | ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); |
| 201 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); | 208 | ASSERT_MSG(to != nullptr, "Next fiber is null!"); |
| 202 | to->guard.lock(); | 209 | to->guard.lock(); |
| 203 | to->previous_fiber = from; | 210 | to->previous_fiber = from; |
| 204 | auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); | 211 | auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); |
| 205 | auto previous_fiber = from->previous_fiber; | 212 | ASSERT(from->previous_fiber != nullptr); |
| 206 | ASSERT(previous_fiber != nullptr); | 213 | from->previous_fiber->impl->context = transfer.fctx; |
| 207 | previous_fiber->impl->context = transfer.fctx; | 214 | from->previous_fiber->guard.unlock(); |
| 208 | previous_fiber->guard.unlock(); | 215 | from->previous_fiber.reset(); |
| 209 | previous_fiber.reset(); | ||
| 210 | } | 216 | } |
| 211 | 217 | ||
| 212 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { | 218 | std::shared_ptr<Fiber> Fiber::ThreadToFiber() { |
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: | |||
| 46 | 46 | ||
| 47 | /// Yields control from Fiber 'from' to Fiber 'to' | 47 | /// Yields control from Fiber 'from' to Fiber 'to' |
| 48 | /// Fiber 'from' must be the currently running fiber. | 48 | /// Fiber 'from' must be the currently running fiber. |
| 49 | static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to); | 49 | static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to); |
| 50 | static std::shared_ptr<Fiber> ThreadToFiber(); | 50 | static std::shared_ptr<Fiber> ThreadToFiber(); |
| 51 | 51 | ||
| 52 | void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter); | 52 | void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter); |
| @@ -65,13 +65,13 @@ private: | |||
| 65 | Fiber(); | 65 | Fiber(); |
| 66 | 66 | ||
| 67 | #if defined(_WIN32) || defined(WIN32) | 67 | #if defined(_WIN32) || defined(WIN32) |
| 68 | void onRewind(); | 68 | void OnRewind(); |
| 69 | void start(); | 69 | void Start(); |
| 70 | static void FiberStartFunc(void* fiber_parameter); | 70 | static void FiberStartFunc(void* fiber_parameter); |
| 71 | static void RewindStartFunc(void* fiber_parameter); | 71 | static void RewindStartFunc(void* fiber_parameter); |
| 72 | #else | 72 | #else |
| 73 | void onRewind(boost::context::detail::transfer_t& transfer); | 73 | void OnRewind(boost::context::detail::transfer_t& transfer); |
| 74 | void start(boost::context::detail::transfer_t& transfer); | 74 | void Start(boost::context::detail::transfer_t& transfer); |
| 75 | static void FiberStartFunc(boost::context::detail::transfer_t transfer); | 75 | static void FiberStartFunc(boost::context::detail::transfer_t transfer); |
| 76 | static void RewindStartFunc(boost::context::detail::transfer_t transfer); | 76 | static void RewindStartFunc(boost::context::detail::transfer_t transfer); |
| 77 | #endif | 77 | #endif |
| @@ -79,13 +79,14 @@ private: | |||
| 79 | struct FiberImpl; | 79 | struct FiberImpl; |
| 80 | 80 | ||
| 81 | SpinLock guard{}; | 81 | SpinLock guard{}; |
| 82 | std::function<void(void*)> entry_point{}; | 82 | std::function<void(void*)> entry_point; |
| 83 | std::function<void(void*)> rewind_point{}; | 83 | std::function<void(void*)> rewind_point; |
| 84 | void* rewind_parameter{}; | 84 | void* rewind_parameter{}; |
| 85 | void* start_parameter{}; | 85 | void* start_parameter{}; |
| 86 | std::shared_ptr<Fiber> previous_fiber{}; | 86 | std::shared_ptr<Fiber> previous_fiber; |
| 87 | std::unique_ptr<FiberImpl> impl; | 87 | std::unique_ptr<FiberImpl> impl; |
| 88 | bool is_thread_fiber{}; | 88 | bool is_thread_fiber{}; |
| 89 | bool released{}; | ||
| 89 | }; | 90 | }; |
| 90 | 91 | ||
| 91 | } // namespace Common | 92 | } // namespace Common |