Advertisement
zhangsongcui

Yield V3.5, highly experimental Android support using SJLJ

Jun 8th, 2018
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.20 KB | None | 0 0
  1. #ifdef _WIN32
  2. #   ifdef _WIN32_WINNT
  3. #       if _WIN32_WINNT < 0x0601
  4. #           error 需要 Windows 7 以上系统支持
  5. #       endif
  6. #   else
  7. #       define _WIN32_WINNT 0x0601
  8. #   endif
  9. #   ifdef WIN32_LEAD_AND_MEAN
  10. #       include <Windows.h>
  11. #   else
  12. #       define WIN32_LEAD_AND_MEAN 1
  13. #       include <Windows.h>
  14. #       undef WIN32_LEAD_AND_MEAN
  15. #   endif
  16. #elif !defined(__ANDROID__) && __has_include(<ucontext.h>)
  17. #   if defined(__APPLE__)
  18. #       define _XOPEN_SOURCE
  19. #   endif
  20. #   include <ucontext.h>
  21. #   define USE_UCONTEXT 1
  22. #else
  23. #   include <setjmp.h>
  24. #   include <signal.h>
  25. #   include <unistd.h>
  26. #   define USE_SJLJ 1
  27. #endif
  28.  
  29. #include <functional>
  30. #include <cassert>
  31. #include <iterator>
  32. #include <iostream>
  33. #include <array>
  34. #include <memory>
  35. #include <algorithm>
  36. #if __has_include(<optional>)
  37. #   include <optional>
  38. #else
  39. #   include <experimental/optional>
  40. namespace std {
  41.     using ::std::experimental::optional;
  42.     using ::std::experimental::nullopt;
  43. }
  44. #endif
  45.  
  46. namespace FiberSpace {
  47.     enum class FiberStatus {
  48.         unstarted = -1,
  49.         running = 1,
  50.         suspended = 2,
  51.         closed = 0,
  52.     };
  53.  
  54.  
  55.     /** \brief 主纤程类析构异常类
  56.      *
  57.      * \warning 用户代码吃掉此异常可导致未定义行为。如果捕获到此异常,请转抛出去。
  58.      */
  59.     struct FiberReturn {
  60.         template <typename YieldValueType>
  61.         friend class Fiber;
  62.  
  63.     private:
  64.         FiberReturn() = default;
  65.     };
  66.  
  67.     /** \brief 主纤程类
  68.      *
  69.      * \warning 线程安全(?)
  70.      * \tparam YieldValueType 子纤程返回类型
  71.      */
  72.     template <typename YieldValueType>
  73.     class Fiber {
  74.         Fiber(const Fiber &) = delete;
  75.         Fiber& operator =(const Fiber &) = delete;
  76.  
  77.         typedef std::function<void(Fiber& fiber)> FuncType;
  78.  
  79.         /// \brief 子纤程返回值
  80.         std::optional<YieldValueType> yieldedValue;
  81.         /// \brief 存储子纤程抛出的异常
  82.         std::exception_ptr eptr = nullptr;
  83.         /// \brief 子纤程是否结束
  84.         FiberStatus status = FiberStatus::unstarted;
  85.         /// \brief 真子纤程入口,第一个参数传入纤程对象的引用
  86.         FuncType func;
  87.  
  88.         /// \brief 纤程信息
  89. #ifdef _WIN32
  90.         PVOID pMainFiber, pNewFiber;
  91.         bool isFormerAThread;
  92. #elif USE_UCONTEXT
  93.         ::ucontext_t ctx_main, ctx_fnew;
  94.         const std::unique_ptr<std::array<uint8_t, SIGSTKSZ>> fnew_stack = std::make_unique<std::array<uint8_t, SIGSTKSZ>>();
  95. #elif USE_SJLJ
  96.         ::sigjmp_buf buf_main, buf_new;
  97.         const std::unique_ptr<std::array<uint8_t, SIGSTKSZ>> fnew_stack = std::make_unique<std::array<uint8_t, SIGSTKSZ>>();
  98.         struct sigaction old_sa;
  99.         static Fiber *that;
  100. #endif
  101.  
  102.     public:
  103.         /** \brief 构造函数
  104.          *
  105.          * 把主线程转化为纤程,并创建一个子纤程
  106.          *
  107.          * \param f 子纤程入口
  108.          */
  109.         explicit Fiber(FuncType f) : func(std::move(f)) {
  110. #ifdef _WIN32
  111.             this->isFormerAThread = !IsThreadAFiber();
  112.             if (this->isFormerAThread) {
  113.                 this->pMainFiber = ::ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH);
  114.             } else {
  115.                 this->pMainFiber = ::GetCurrentFiber();
  116.             }
  117.             // default stack size
  118.             this->pNewFiber = ::CreateFiberEx(0, 0, FIBER_FLAG_FLOAT_SWITCH, (void(*)(void *))&fEntry, this);
  119. #elif USE_UCONTEXT
  120.             ::getcontext(&this->ctx_fnew);
  121.             this->ctx_fnew.uc_stack.ss_sp = this->fnew_stack.get();
  122.             this->ctx_fnew.uc_stack.ss_size = this->fnew_stack->size();
  123.             this->ctx_fnew.uc_link = &this->ctx_main;
  124.             ::makecontext(&this->ctx_fnew, (void(*)())&fEntry, 1, this);
  125. #elif USE_SJLJ
  126.             ::stack_t sigstk, oldstk;
  127.             sigstk.ss_sp = this->fnew_stack.get();
  128.             sigstk.ss_size = this->fnew_stack->size();
  129.             sigstk.ss_flags = 0;
  130.             assert(::sigaltstack(&sigstk, &oldstk) == 0 && "Error while set sigstk");
  131.  
  132.             struct sigaction sa;
  133.             sa.sa_flags = SA_ONSTACK;
  134.             sa.sa_handler = fEntry;
  135.             sigemptyset(&sa.sa_mask);
  136.             assert(::sigaction(SIGUSR2, &sa, &this->old_sa) == 0 && "Error while installing a signal handler");
  137.  
  138.             if (!sigsetjmp(this->buf_main, 0)) {
  139.                 Fiber::that = this; // Android doesn't support sigqueue,
  140.                 assert(::raise(SIGUSR2) == 0 && "Failed to queue the signal");
  141.             }
  142.             assert(::sigaltstack(&oldstk, nullptr) == 0 && "Error while reset sigstk");
  143.  
  144.             ::sigset_t sa_mask;
  145.             sigemptyset(&sa_mask);
  146.             sigaddset(&sa_mask, SIGUSR2);
  147.             ::sigprocmask(SIG_UNBLOCK, &sa_mask, nullptr);
  148. #endif
  149.         }
  150.  
  151.         template <class Fp, class ...Args,
  152.             class = typename std::enable_if
  153.                 <
  154.                     (sizeof...(Args) > 0)
  155.                 >::type
  156.             >
  157.             explicit Fiber(Fp&& f, Args&&... args) : Fiber(std::bind(std::forward<Fp>(f), std::placeholders::_1, std::forward<Args>(args)...)) {}
  158.  
  159.         /** \brief 析构函数
  160.          *
  161.          * 删除子纤程,并将主纤程转回线程
  162.          *
  163.          * \warning 主类析构时如子纤程尚未结束(return),则会在子纤程中抛出 FiberReturn 来确保子纤程函数内所有对象都被正确析构
  164.          */
  165.         ~Fiber() noexcept {
  166.             if (!isFinished()) {
  167.                 return_();
  168.             }
  169.  
  170. #ifdef _WIN32
  171.             ::DeleteFiber(this->pNewFiber);
  172.             if (this->isFormerAThread) {
  173.                 ::ConvertFiberToThread();
  174.             }
  175. #endif
  176.         }
  177.  
  178.         /** \brief 调用子纤程
  179.          *
  180.          * 程序流程转入子纤程
  181.          *
  182.          * \warning 子纤程必须尚未结束
  183.          * \return 返回子纤程是否尚未结束
  184.          */
  185.         bool next() {
  186.             assert(!isFinished());
  187. #ifdef _WIN32
  188.             assert(GetCurrentFiber() != this->pNewFiber && "如果你想递归自己,请创建一个新纤程");
  189.             ::SwitchToFiber(this->pNewFiber);
  190. #elif USE_UCONTEXT
  191.             ::swapcontext(&this->ctx_main, &this->ctx_fnew);
  192. #elif USE_SJLJ
  193.             if (!::sigsetjmp(this->buf_main, 0)) {
  194.                 ::siglongjmp(this->buf_new, 1);
  195.             }
  196. #endif
  197.             if (this->eptr) {
  198.                 std::rethrow_exception(std::exchange(this->eptr, nullptr));
  199.             }
  200.  
  201.             return !isFinished();
  202.         }
  203.  
  204.         /** \brief 向子纤程内部抛出异常
  205.          *
  206.          * 程序流程转入子纤程,并在子纤程内部抛出异常
  207.          *
  208.          * \param eptr 需抛出异常的指针(可以通过 std::make_exception_ptr 获取)
  209.          * \warning 子纤程必须尚未结束
  210.          * \return 返回子纤程是否尚未结束
  211.          */
  212.         bool throw_(std::exception_ptr&& eptr) {
  213.             assert(!isFinished());
  214.             this->eptr = std::exchange(eptr, nullptr);
  215.             return next();
  216.         }
  217.  
  218.         /** \brief 强制退出子纤程
  219.          *
  220.          * 向子纤程内部抛出 FiberReturn 异常,以强制退出子纤程,并确保子纤程函数中所有对象都正确析构
  221.          *
  222.          * \warning 子纤程必须尚未结束
  223.          */
  224.         void return_() {
  225.             assert(!isFinished());
  226.             throw_(std::make_exception_ptr(FiberReturn()));
  227.             assert(isFinished() && "请勿吃掉 FiberReturn 异常!!!");
  228.         }
  229.  
  230.         /** \brief 获得子纤程返回的值
  231.          * \return 子纤程返回的值。如果子纤程没有启动,则返回默认构造值
  232.          */
  233.         const YieldValueType& current() const {
  234.             return *this->yieldedValue;
  235.         }
  236.  
  237.         /** \brief 判断子纤程是否结束
  238.          * \return 子纤程已经结束(return)返回true,否则false
  239.          */
  240.         bool isFinished() const noexcept {
  241.             return this->status == FiberStatus::closed;
  242.         }
  243.  
  244.         /** \brief 转回主纤程并输出值
  245.          *
  246.          * \warning 必须由子纤程调用
  247.          *          参数类型必须与子纤程返回值相同,无类型安全
  248.          * \param value 输出到主纤程的值
  249.          */
  250.         void yield(YieldValueType value) {
  251.             assert(!isFinished());
  252.             this->status = FiberStatus::suspended;
  253.             this->yieldedValue = std::move(value);
  254. #ifdef _WIN32
  255.             assert(GetCurrentFiber() != this->pMainFiber && "这虽然是游戏,但绝不是可以随便玩的");
  256.             ::SwitchToFiber(this->pMainFiber);
  257. #elif USE_UCONTEXT
  258.             ::swapcontext(&this->ctx_fnew, &this->ctx_main);
  259. #else
  260.             if (!::sigsetjmp(this->buf_new, 0)) {
  261.                 ::siglongjmp(this->buf_main, 1);
  262.             }
  263. #endif
  264.             this->status = FiberStatus::running;
  265.  
  266.             if (this->eptr) {
  267.                 std::rethrow_exception(std::exchange(this->eptr, nullptr));
  268.             }
  269.         }
  270.  
  271.         /** \brief 输出子纤程的所有值
  272.          * \param fiber 另一子纤程
  273.          */
  274.         void yieldAll(Fiber& fiber) {
  275.             assert(&fiber != this);
  276.             while (fiber.next()) {
  277.                 this->yield(fiber.current());
  278.             }
  279.         }
  280.  
  281.         void yieldAll(Fiber&& fiber) {
  282.             this->yieldAll(fiber);
  283.         }
  284.  
  285.     private:
  286.         /// \brief 子纤程入口的warpper
  287.  
  288. #ifdef _WIN32
  289.         static void WINAPI fEntry(Fiber *fiber) {
  290. #elif USE_UCONTEXT
  291.         static void fEntry(Fiber *fiber) {
  292. #elif USE_SJLJ
  293.         static void fEntry(int signo) {
  294.             Fiber *fiber = std::exchange(Fiber::that, nullptr);
  295.             assert(sigaction(signo, &fiber->old_sa, nullptr) == 0 && "Failed to reset signal handler");
  296.             if (!::sigsetjmp(fiber->buf_new, 0)) {
  297.                 ::siglongjmp(fiber->buf_main, 1);
  298.             }
  299. #endif
  300.  
  301.             if (!fiber->eptr) {
  302.                 fiber->status = FiberStatus::running;
  303.                 try {
  304.                     fiber->func(*fiber);
  305.                 }
  306.                 catch (FiberReturn &) {
  307.                     // 主 Fiber 对象正在析构
  308.                 }
  309.                 catch (...) {
  310.                     fiber->eptr = std::current_exception();
  311.                 }
  312.             }
  313.             fiber->status = FiberStatus::closed;
  314.             fiber->yieldedValue = std::nullopt;
  315. #ifdef _WIN32
  316.             ::SwitchToFiber(fiber->pMainFiber);
  317. #elif USE_SJLJ
  318.             ::siglongjmp(fiber->buf_main, 1);
  319. #endif
  320.         }
  321.     };
  322.    
  323. #if USE_SJLJ
  324.     template <typename YieldValueType>
  325.     Fiber<YieldValueType> *Fiber<YieldValueType>::that;
  326. #endif
  327.  
  328.     /** \brief 纤程迭代器类
  329.      *
  330.      * 它通过使用 yield 函数对数组或集合类执行自定义迭代。
  331.      * 用于 C++11 for (... : ...)
  332.      */
  333.     template <typename YieldValueType>
  334.     struct FiberIterator : std::iterator<std::output_iterator_tag, YieldValueType> {
  335.         /// \brief 迭代器尾
  336.         FiberIterator() noexcept : fiber(nullptr) {}
  337.         /** \brief 迭代器首
  338.          * \param _f 主线程类的引用
  339.          */
  340.         FiberIterator(Fiber<YieldValueType>& _f) : fiber(&_f) {
  341.             next();
  342.         }
  343.  
  344.         /// \brief 转入子纤程
  345.         FiberIterator& operator ++() {
  346.             next();
  347.             return *this;
  348.         }
  349.  
  350.         /// \brief 取得返回值
  351.         const YieldValueType &operator *() const {
  352.             assert(fiber != nullptr);
  353.             return fiber->current();
  354.         }
  355.  
  356.         /** \brief 比较迭代器相等
  357.          *
  358.          * 通常用于判断迭代是否结束
  359.          * 最好别干别的 ;P
  360.          */
  361.         bool operator ==(const FiberIterator& rhs) const noexcept {
  362.             return fiber == rhs.fiber;
  363.         }
  364.         bool operator !=(const FiberIterator& rhs) const noexcept {
  365.             return !(*this == rhs);
  366.         }
  367.  
  368.     private:
  369.         void next() {
  370.             assert(fiber);
  371.             if (!fiber->next()) fiber = nullptr;
  372.         }
  373.  
  374.         Fiber<YieldValueType>* fiber;
  375.     };
  376.  
  377.     /// \brief 返回迭代器首
  378.     template <typename YieldValueType>
  379.     FiberIterator<YieldValueType> begin(Fiber<YieldValueType>& fiber) {
  380.         return FiberIterator<YieldValueType>(fiber);
  381.     }
  382.  
  383.     /// \brief 返回迭代器尾
  384.     template <typename YieldValueType>
  385.     FiberIterator<YieldValueType> end(Fiber<YieldValueType>&) noexcept {
  386.         return FiberIterator<YieldValueType>();
  387.     }
  388. }
  389.  
  390. using namespace std;
  391. using FiberSpace::Fiber;
  392.  
  393. bool destructedFlag = false;
  394.  
  395. struct TestDestruct {
  396.     ~TestDestruct() {
  397.         destructedFlag = true;
  398.     }
  399. };
  400.  
  401. void foo(Fiber<bool>& fiber, int arg) {
  402.     TestDestruct test;
  403.     for (int i = 1; i < 5; i++) {
  404.         printf("goroutine :%d\n", arg + i);
  405.         fiber.yield(false);
  406.     }
  407. }
  408.  
  409. void do_permutation(Fiber<array<int, 4>>& fiber, array<int, 4> arr, int length) {
  410.     if (length) {
  411.         for (auto i = 0; i < length; ++i) {
  412.             array<int, 4> newArr(arr);
  413.             std::copy_n(arr.begin(), i, newArr.begin());
  414.             std::copy_n(arr.begin() + i + 1, arr.size() - i - 1, newArr.begin() + i);
  415.             newArr.back() = arr[i];
  416.             fiber.yieldAll(Fiber<array<int, 4>>(do_permutation, newArr, length - 1));
  417.         }
  418.     }
  419.     else {
  420.         fiber.yield(arr);
  421.     }
  422. }
  423.  
  424. void permutation(Fiber<array<int, 4>>& fiber, array<int, 4> arr) {
  425.     do_permutation(fiber, arr, (int)arr.size());
  426. }
  427.  
  428. int main() {
  429.     {
  430.         Fiber<bool> arg1Fiber(foo, 0);
  431.         arg1Fiber.next();
  432.         arg1Fiber.next();
  433.         arg1Fiber.next();
  434.     }
  435.     assert(destructedFlag);
  436.     {
  437.         Fiber<bool> arg1Fiber(foo, 0);
  438.         arg1Fiber.next();
  439.         arg1Fiber.next();
  440.         arg1Fiber.next();
  441.     }
  442.     assert(destructedFlag);
  443.     {
  444.         Fiber<bool> arg1Fiber(foo, 0);
  445.         for (auto&& result : arg1Fiber) {}
  446.     }
  447.     assert(destructedFlag);
  448.  
  449.     for (auto&& result : Fiber<array<int, 4>>(permutation, array<int, 4> { 1, 2, 3, 4 })) {
  450.         copy(result.begin(), result.end(), std::ostream_iterator<int>(cout, ","));
  451.         cout << endl;
  452.     }
  453. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement