fiber.h 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright 2020 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <functional>
  6. #include <memory>
  7. #include "common/common_types.h"
  8. #include "common/spin_lock.h"
  9. #if !defined(_WIN32) && !defined(WIN32)
  10. namespace boost::context::detail {
  11. struct transfer_t;
  12. }
  13. #endif
  14. namespace Common {
  15. /**
  16. * Fiber class
  17. * a fiber is a userspace thread with it's own context. They can be used to
  18. * implement coroutines, emulated threading systems and certain asynchronous
  19. * patterns.
  20. *
  21. * This class implements fibers at a low level, thus allowing greater freedom
  22. * to implement such patterns. This fiber class is 'threadsafe' only one fiber
  23. * can be running at a time and threads will be locked while trying to yield to
  24. * a running fiber until it yields. WARNING exchanging two running fibers between
  25. * threads will cause a deadlock. In order to prevent a deadlock, each thread should
  26. * have an intermediary fiber, you switch to the intermediary fiber of the current
  27. * thread and then from it switch to the expected fiber. This way you can exchange
  28. * 2 fibers within 2 different threads.
  29. */
  30. class Fiber {
  31. public:
  32. Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter);
  33. ~Fiber();
  34. Fiber(const Fiber&) = delete;
  35. Fiber& operator=(const Fiber&) = delete;
  36. Fiber(Fiber&&) = default;
  37. Fiber& operator=(Fiber&&) = default;
  38. /// Yields control from Fiber 'from' to Fiber 'to'
  39. /// Fiber 'from' must be the currently running fiber.
  40. static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to);
  41. [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
  42. void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param);
  43. void Rewind();
  44. /// Only call from main thread's fiber
  45. void Exit();
  46. /// Changes the start parameter of the fiber. Has no effect if the fiber already started
  47. void SetStartParameter(void* new_parameter) {
  48. start_parameter = new_parameter;
  49. }
  50. private:
  51. Fiber();
  52. #if defined(_WIN32) || defined(WIN32)
  53. void OnRewind();
  54. void Start();
  55. static void FiberStartFunc(void* fiber_parameter);
  56. static void RewindStartFunc(void* fiber_parameter);
  57. #else
  58. void OnRewind(boost::context::detail::transfer_t& transfer);
  59. void Start(boost::context::detail::transfer_t& transfer);
  60. static void FiberStartFunc(boost::context::detail::transfer_t transfer);
  61. static void RewindStartFunc(boost::context::detail::transfer_t transfer);
  62. #endif
  63. struct FiberImpl;
  64. SpinLock guard{};
  65. std::function<void(void*)> entry_point;
  66. std::function<void(void*)> rewind_point;
  67. void* rewind_parameter{};
  68. void* start_parameter{};
  69. std::shared_ptr<Fiber> previous_fiber;
  70. std::unique_ptr<FiberImpl> impl;
  71. bool is_thread_fiber{};
  72. bool released{};
  73. };
  74. } // namespace Common