diff --git a/lib/inc/drogon/utils/coroutine.h b/lib/inc/drogon/utils/coroutine.h index 09148897..d7eae9cd 100644 --- a/lib/inc/drogon/utils/coroutine.h +++ b/lib/inc/drogon/utils/coroutine.h @@ -697,6 +697,19 @@ struct [[nodiscard]] LoopAwaiter : CallbackAwaiter std::function taskFunc_; }; +struct [[nodiscard]] SwitchThreadAwaiter : CallbackAwaiter +{ + explicit SwitchThreadAwaiter(trantor::EventLoop *loop) : loop_(loop) + { + } + void await_suspend(std::coroutine_handle<> handle) + { + loop_->runInLoop([handle]() { handle.resume(); }); + } + + private: + trantor::EventLoop *loop_; +}; struct [[nodiscard]] EndAwaiter : CallbackAwaiter { EndAwaiter(trantor::EventLoop *loop) : loop_(loop) @@ -738,6 +751,13 @@ inline internal::LoopAwaiter queueInLoopCoro( return {workLoop, std::move(taskFunc), resumeLoop}; } +inline internal::SwitchThreadAwaiter switchThreadCoro( + trantor::EventLoop *loop) noexcept +{ + assert(loop); + return internal::SwitchThreadAwaiter{loop}; +} + inline internal::EndAwaiter untilQuit(trantor::EventLoop *loop) { assert(loop); diff --git a/lib/tests/unittests/CoroutineTest.cc b/lib/tests/unittests/CoroutineTest.cc index f0cc3141..2b63a3f4 100644 --- a/lib/tests/unittests/CoroutineTest.cc +++ b/lib/tests/unittests/CoroutineTest.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include using namespace drogon; @@ -185,3 +186,20 @@ DROGON_TEST(AsyncWaitLifetime) CHECK(ptr2.use_count() == 1); })); } + +DROGON_TEST(SwitchThread) +{ + thread_local int num{0}; + trantor::EventLoopThread thread; + thread.run(); + thread.getLoop()->queueInLoop([]() { num = 100; }); + + auto switch_thread = [TEST_CTX, &thread]() -> Task<> { + CHECK(num == 0); + co_await switchThreadCoro(thread.getLoop()); + CHECK(num == 100); + thread.getLoop()->quit(); + }; + sync_wait(switch_thread()); + thread.wait(); +}