Commit 8bce0676 by Antonio Maiorano

Subzero: replace Win32 fibers with Marl for couroutines

* This change was authored by bclayton@, with some modifications. * Replaces Win32 fiber implementation with marl tasks, making coroutines work on all marl-supported platforms. Bug: b/145754674 Change-Id: Ic3de82afc69549e1d56688c6faf8077a6f446ee0 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/41788 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarBen Clayton <bclayton@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Tested-by: 's avatarAntonio Maiorano <amaiorano@google.com>
parent b8bae186
...@@ -1549,6 +1549,25 @@ if(LINUX) ...@@ -1549,6 +1549,25 @@ if(LINUX)
target_link_libraries(llvm dl) target_link_libraries(llvm dl)
endif() endif()
###########################################################
# marl
###########################################################
if(BUILD_MARL)
set(MARL_THIRD_PARTY_DIR ${THIRD_PARTY_DIR})
add_subdirectory(third_party/marl)
endif()
###########################################################
# cppdap
###########################################################
if(SWIFTSHADER_BUILD_CPPDAP)
set(CPPDAP_THIRD_PARTY_DIR ${THIRD_PARTY_DIR})
add_subdirectory(${CPPDAP_DIR})
endif()
########################################################### ###########################################################
# Subzero # Subzero
########################################################### ###########################################################
...@@ -1696,6 +1715,8 @@ if(${REACTOR_BACKEND} STREQUAL "Subzero") ...@@ -1696,6 +1715,8 @@ if(${REACTOR_BACKEND} STREQUAL "Subzero")
) )
target_link_libraries(ReactorSubzero SubzeroDependencies) target_link_libraries(ReactorSubzero SubzeroDependencies)
target_link_libraries(ReactorSubzero marl)
if(WIN32) if(WIN32)
target_compile_definitions(ReactorSubzero PRIVATE SUBZERO_USE_MICROSOFT_ABI) target_compile_definitions(ReactorSubzero PRIVATE SUBZERO_USE_MICROSOFT_ABI)
endif() endif()
...@@ -2157,16 +2178,6 @@ if(SWIFTSHADER_BUILD_GLES_CM) ...@@ -2157,16 +2178,6 @@ if(SWIFTSHADER_BUILD_GLES_CM)
) )
endif(SWIFTSHADER_BUILD_GLES_CM) endif(SWIFTSHADER_BUILD_GLES_CM)
if(BUILD_MARL)
set(MARL_THIRD_PARTY_DIR ${THIRD_PARTY_DIR})
add_subdirectory(third_party/marl)
endif()
if(SWIFTSHADER_BUILD_CPPDAP)
set(CPPDAP_THIRD_PARTY_DIR ${THIRD_PARTY_DIR})
add_subdirectory(${CPPDAP_DIR})
endif()
if(SWIFTSHADER_BUILD_VULKAN) if(SWIFTSHADER_BUILD_VULKAN)
add_library(vk_swiftshader SHARED ${VULKAN_LIST}) add_library(vk_swiftshader SHARED ${VULKAN_LIST})
...@@ -2322,9 +2333,9 @@ if(SWIFTSHADER_BUILD_TESTS) ...@@ -2322,9 +2333,9 @@ if(SWIFTSHADER_BUILD_TESTS)
) )
if(NOT WIN32 AND ${REACTOR_BACKEND} STREQUAL "Subzero") if(NOT WIN32 AND ${REACTOR_BACKEND} STREQUAL "Subzero")
target_link_libraries(ReactorUnitTests ${Reactor} pthread dl) target_link_libraries(ReactorUnitTests ${Reactor} marl pthread dl)
else() else()
target_link_libraries(ReactorUnitTests ${Reactor}) target_link_libraries(ReactorUnitTests ${Reactor} marl)
endif() endif()
set(GLES_UNITTESTS_LIST set(GLES_UNITTESTS_LIST
...@@ -2390,7 +2401,7 @@ if(SWIFTSHADER_BUILD_BENCHMARKS) ...@@ -2390,7 +2401,7 @@ if(SWIFTSHADER_BUILD_BENCHMARKS)
) )
add_executable(ReactorBenchmarks ${REACTOR_BENCHMARK_LIST}) add_executable(ReactorBenchmarks ${REACTOR_BENCHMARK_LIST})
target_link_libraries(ReactorBenchmarks benchmark::benchmark ${Reactor}) target_link_libraries(ReactorBenchmarks benchmark::benchmark marl ${Reactor})
set_target_properties(ReactorBenchmarks PROPERTIES set_target_properties(ReactorBenchmarks PROPERTIES
COMPILE_OPTIONS "${SWIFTSHADER_COMPILE_OPTIONS};${WARNINGS_AS_ERRORS}" COMPILE_OPTIONS "${SWIFTSHADER_COMPILE_OPTIONS};${WARNINGS_AS_ERRORS}"
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "marl/defer.h"
#include "marl/scheduler.h"
#include <array> #include <array>
#include <cmath> #include <cmath>
#include <thread> #include <thread>
...@@ -155,6 +158,38 @@ std::vector<std::string> split(const std::string &s) ...@@ -155,6 +158,38 @@ std::vector<std::string> split(const std::string &s)
return result; return result;
} }
static const std::vector<int> fibonacci = {
0,
1,
1,
2,
3,
5,
8,
13,
21,
34,
55,
89,
144,
233,
377,
610,
987,
1597,
2584,
4181,
6765,
10946,
17711,
28657,
46368,
75025,
121393,
196418,
317811,
};
TEST(ReactorUnitTests, PrintPrimitiveTypes) TEST(ReactorUnitTests, PrintPrimitiveTypes)
{ {
#if defined(ENABLE_RR_PRINT) && !defined(ENABLE_RR_EMIT_PRINT_LOCATION) #if defined(ENABLE_RR_PRINT) && !defined(ENABLE_RR_EMIT_PRINT_LOCATION)
...@@ -2070,6 +2105,30 @@ TYPED_TEST(GEPTest, PtrOffsets) ...@@ -2070,6 +2105,30 @@ TYPED_TEST(GEPTest, PtrOffsets)
} }
} }
TEST(ReactorUnitTests, Fibonacci)
{
FunctionT<int(int)> function;
{
Int n = function.Arg<0>();
Int current = 0;
Int next = 1;
For(Int i = 0, i < n, i++)
{
auto tmp = current + next;
current = next;
next = tmp;
}
Return(current);
}
auto routine = function("one");
for(size_t i = 0; i < fibonacci.size(); i++)
{
EXPECT_EQ(routine(i), fibonacci[i]);
}
}
TEST(ReactorUnitTests, Coroutines_Fibonacci) TEST(ReactorUnitTests, Coroutines_Fibonacci)
{ {
if(!rr::Caps.CoroutinesSupported) if(!rr::Caps.CoroutinesSupported)
...@@ -2078,6 +2137,11 @@ TEST(ReactorUnitTests, Coroutines_Fibonacci) ...@@ -2078,6 +2137,11 @@ TEST(ReactorUnitTests, Coroutines_Fibonacci)
return; return;
} }
marl::Scheduler scheduler;
scheduler.setWorkerThreadCount(8);
scheduler.bind();
defer(scheduler.unbind());
Coroutine<int()> function; Coroutine<int()> function;
{ {
Yield(Int(0)); Yield(Int(0));
...@@ -2095,45 +2159,11 @@ TEST(ReactorUnitTests, Coroutines_Fibonacci) ...@@ -2095,45 +2159,11 @@ TEST(ReactorUnitTests, Coroutines_Fibonacci)
auto coroutine = function(); auto coroutine = function();
int32_t expected[] = { for(size_t i = 0; i < fibonacci.size(); i++)
0,
1,
1,
2,
3,
5,
8,
13,
21,
34,
55,
89,
144,
233,
377,
610,
987,
1597,
2584,
4181,
6765,
10946,
17711,
28657,
46368,
75025,
121393,
196418,
317811,
};
auto count = sizeof(expected) / sizeof(expected[0]);
for(size_t i = 0; i < count; i++)
{ {
int out = 0; int out = 0;
EXPECT_EQ(coroutine->await(out), true); EXPECT_EQ(coroutine->await(out), true);
EXPECT_EQ(out, expected[i]); EXPECT_EQ(out, fibonacci[i]);
} }
} }
...@@ -2145,6 +2175,11 @@ TEST(ReactorUnitTests, Coroutines_Parameters) ...@@ -2145,6 +2175,11 @@ TEST(ReactorUnitTests, Coroutines_Parameters)
return; return;
} }
marl::Scheduler scheduler;
scheduler.setWorkerThreadCount(8);
scheduler.bind();
defer(scheduler.unbind());
Coroutine<uint8_t(uint8_t * data, int count)> function; Coroutine<uint8_t(uint8_t * data, int count)> function;
{ {
Pointer<Byte> data = function.Arg<0>(); Pointer<Byte> data = function.Arg<0>();
...@@ -2186,6 +2221,11 @@ TEST(ReactorUnitTests, Coroutines_Vectors) ...@@ -2186,6 +2221,11 @@ TEST(ReactorUnitTests, Coroutines_Vectors)
return; return;
} }
marl::Scheduler scheduler;
scheduler.setWorkerThreadCount(8);
scheduler.bind();
defer(scheduler.unbind());
Coroutine<int()> function; Coroutine<int()> function;
{ {
Int4 a{ 1, 2, 3, 4 }; Int4 a{ 1, 2, 3, 4 };
...@@ -2220,6 +2260,11 @@ TEST(ReactorUnitTests, Coroutines_NoYield) ...@@ -2220,6 +2260,11 @@ TEST(ReactorUnitTests, Coroutines_NoYield)
return; return;
} }
marl::Scheduler scheduler;
scheduler.setWorkerThreadCount(8);
scheduler.bind();
defer(scheduler.unbind());
for(int i = 0; i < 2; ++i) for(int i = 0; i < 2; ++i)
{ {
Coroutine<int()> function; Coroutine<int()> function;
...@@ -2244,6 +2289,11 @@ TEST(ReactorUnitTests, Coroutines_Parallel) ...@@ -2244,6 +2289,11 @@ TEST(ReactorUnitTests, Coroutines_Parallel)
return; return;
} }
marl::Scheduler scheduler;
scheduler.setWorkerThreadCount(8);
//scheduler.bind();
//defer(scheduler.unbind());
Coroutine<int()> function; Coroutine<int()> function;
{ {
Yield(Int(0)); Yield(Int(0));
...@@ -2262,53 +2312,22 @@ TEST(ReactorUnitTests, Coroutines_Parallel) ...@@ -2262,53 +2312,22 @@ TEST(ReactorUnitTests, Coroutines_Parallel)
// Must call on same thread that creates the coroutine // Must call on same thread that creates the coroutine
function.finalize(); function.finalize();
constexpr int32_t expected[] = {
0,
1,
1,
2,
3,
5,
8,
13,
21,
34,
55,
89,
144,
233,
377,
610,
987,
1597,
2584,
4181,
6765,
10946,
17711,
28657,
46368,
75025,
121393,
196418,
317811,
};
constexpr auto count = sizeof(expected) / sizeof(expected[0]);
std::vector<std::thread> threads; std::vector<std::thread> threads;
const size_t numThreads = 100; const size_t numThreads = 100;
for(size_t t = 0; t < numThreads; ++t) for(size_t t = 0; t < numThreads; ++t)
{ {
threads.emplace_back([&] { threads.emplace_back([&] {
scheduler.bind();
defer(scheduler.unbind());
auto coroutine = function(); auto coroutine = function();
for(size_t i = 0; i < count; i++) for(size_t i = 0; i < fibonacci.size(); i++)
{ {
int out = 0; int out = 0;
EXPECT_EQ(coroutine->await(out), true); EXPECT_EQ(coroutine->await(out), true);
EXPECT_EQ(out, expected[i]); EXPECT_EQ(out, fibonacci[i]);
} }
}); });
} }
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_os_ostream.h" #include "llvm/Support/raw_os_ostream.h"
#include "marl/event.h"
#if __has_feature(memory_sanitizer) #if __has_feature(memory_sanitizer)
# include <sanitizer/msan_interface.h> # include <sanitizer/msan_interface.h>
#endif #endif
...@@ -380,11 +382,7 @@ std::string BackendName() ...@@ -380,11 +382,7 @@ std::string BackendName()
} }
const Capabilities Caps = { const Capabilities Caps = {
#if defined(_WIN32)
true, // CoroutinesSupported true, // CoroutinesSupported
#else
false, // CoroutinesSupported
#endif
}; };
enum EmulatedType enum EmulatedType
...@@ -4464,19 +4462,15 @@ void FlushDebug() {} ...@@ -4464,19 +4462,15 @@ void FlushDebug() {}
namespace { namespace {
namespace coro { namespace coro {
using FiberHandle = void *;
// Instance data per generated coroutine // Instance data per generated coroutine
// This is the "handle" type used for Coroutine functions // This is the "handle" type used for Coroutine functions
// Lifetime: from yield to when CoroutineEntryDestroy generated function is called. // Lifetime: from yield to when CoroutineEntryDestroy generated function is called.
struct CoroutineData struct CoroutineData
{ {
FiberHandle mainFiber{}; marl::Event suspended; // the coroutine is suspended on a yield()
FiberHandle routineFiber{}; marl::Event resumed; // the caller is suspended on an await()
bool convertedFiber = false; marl::Event done{ marl::Event::Mode::Manual }; // the coroutine should stop at the next yield()
marl::Event terminated{ marl::Event::Mode::Manual }; // the coroutine has finished.
// Variables used by coroutines
bool done = false;
void *promisePtr = nullptr; void *promisePtr = nullptr;
}; };
...@@ -4490,108 +4484,36 @@ void destroyCoroutineData(CoroutineData *coroData) ...@@ -4490,108 +4484,36 @@ void destroyCoroutineData(CoroutineData *coroData)
delete coroData; delete coroData;
} }
void convertThreadToMainFiber(Nucleus::CoroutineHandle handle) // suspend() pauses execution of the coroutine, and resumes execution from the
{ // caller's call to await().
#if defined(_WIN32) // Returns true if await() is called again, or false if coroutine_destroy()
auto *coroData = reinterpret_cast<CoroutineData *>(handle); // is called.
bool suspend(Nucleus::CoroutineHandle handle)
coroData->mainFiber = ::ConvertThreadToFiber(nullptr);
if(coroData->mainFiber)
{
coroData->convertedFiber = true;
}
else
{
// We're probably already on a fiber, so just grab it and remember that we didn't
// convert it, so not to convert back to thread.
coroData->mainFiber = GetCurrentFiber();
coroData->convertedFiber = false;
}
ASSERT(coroData->mainFiber);
#else
UNIMPLEMENTED_NO_BUG("convertThreadToMainFiber not implemented for current platform");
#endif
}
void convertMainFiberToThread(Nucleus::CoroutineHandle handle)
{
#if defined(_WIN32)
auto *coroData = reinterpret_cast<CoroutineData *>(handle);
ASSERT(coroData->mainFiber);
if(coroData->convertedFiber)
{
::ConvertFiberToThread();
coroData->mainFiber = nullptr;
}
#else
UNIMPLEMENTED_NO_BUG("convertMainFiberToThread not implemented for current platform");
#endif
}
using FiberFunc = std::function<void()>;
void createRoutineFiber(Nucleus::CoroutineHandle handle, FiberFunc *fiberFunc)
{
#if defined(_WIN32)
struct Invoker
{
FiberFunc func;
static VOID __stdcall fiberEntry(LPVOID lpParameter)
{
auto *func = reinterpret_cast<FiberFunc *>(lpParameter);
(*func)();
}
};
auto *coroData = reinterpret_cast<CoroutineData *>(handle);
constexpr SIZE_T StackSize = 2 * 1024 * 1024;
coroData->routineFiber = ::CreateFiber(StackSize, &Invoker::fiberEntry, fiberFunc);
ASSERT(coroData->routineFiber);
#else
UNIMPLEMENTED_NO_BUG("createRoutineFiber not implemented for current platform");
#endif
}
void deleteRoutineFiber(Nucleus::CoroutineHandle handle)
{ {
#if defined(_WIN32) auto *data = reinterpret_cast<CoroutineData *>(handle);
auto *coroData = reinterpret_cast<CoroutineData *>(handle); data->suspended.signal();
ASSERT(coroData->routineFiber); data->resumed.wait();
::DeleteFiber(coroData->routineFiber); return !data->done.test();
coroData->routineFiber = nullptr;
#else
UNIMPLEMENTED_NO_BUG("deleteRoutineFiber not implemented for current platform");
#endif
} }
void switchToMainFiber(Nucleus::CoroutineHandle handle) // resume() is called by await(), blocking until the coroutine calls yield()
// or the coroutine terminates.
void resume(Nucleus::CoroutineHandle handle)
{ {
#if defined(_WIN32) auto *data = reinterpret_cast<CoroutineData *>(handle);
auto *coroData = reinterpret_cast<CoroutineData *>(handle); data->resumed.signal();
data->suspended.wait();
// Win32
ASSERT(coroData->mainFiber);
::SwitchToFiber(coroData->mainFiber);
#else
UNIMPLEMENTED_NO_BUG("switchToMainFiber not implemented for current platform");
#endif
} }
void switchToRoutineFiber(Nucleus::CoroutineHandle handle) // stop() is called by coroutine_destroy(), signalling that it's done, then blocks
// until the coroutine ends, and deletes the coroutine data.
void stop(Nucleus::CoroutineHandle handle)
{ {
#if defined(_WIN32)
auto *coroData = reinterpret_cast<CoroutineData *>(handle); auto *coroData = reinterpret_cast<CoroutineData *>(handle);
coroData->done.signal(); // signal that the coroutine should stop at next (or current) yield.
// Win32 coroData->resumed.signal(); // wake the coroutine if blocked on a yield.
ASSERT(coroData->routineFiber); coroData->terminated.wait(); // wait for the coroutine to return.
::SwitchToFiber(coroData->routineFiber); coro::destroyCoroutineData(coroData); // free the coroutine data.
#else
UNIMPLEMENTED_NO_BUG("switchToRoutineFiber not implemented for current platform");
#endif
} }
namespace detail { namespace detail {
...@@ -4612,17 +4534,10 @@ Nucleus::CoroutineHandle getHandleParam() ...@@ -4612,17 +4534,10 @@ Nucleus::CoroutineHandle getHandleParam()
return handle; return handle;
} }
void setDone(Nucleus::CoroutineHandle handle)
{
auto *coroData = reinterpret_cast<CoroutineData *>(handle);
ASSERT(!coroData->done); // Should be called once
coroData->done = true;
}
bool isDone(Nucleus::CoroutineHandle handle) bool isDone(Nucleus::CoroutineHandle handle)
{ {
auto *coroData = reinterpret_cast<CoroutineData *>(handle); auto *coroData = reinterpret_cast<CoroutineData *>(handle);
return coroData->done; return coroData->done.test();
} }
void setPromisePtr(Nucleus::CoroutineHandle handle, void *promisePtr) void setPromisePtr(Nucleus::CoroutineHandle handle, void *promisePtr)
...@@ -4697,30 +4612,27 @@ public: ...@@ -4697,30 +4612,27 @@ public:
// ... <REACTOR CODE> ... // ... <REACTOR CODE> ...
// //
// promise = val; // promise = val;
// coro::switchToMainFiber(handle); // if (!coro::suspend(handle)) {
// return false; // coroutine has been stopped by the caller.
// }
// //
// ... <REACTOR CODE> ... // ... <REACTOR CODE> ...
// promise = val;
Nucleus::createStore(val, V(this->promise), ::coroYieldType); Nucleus::createStore(val, V(this->promise), ::coroYieldType);
sz::Call(::function, ::basicBlock, coro::switchToMainFiber, this->handle);
}
// Adds instructions at the end of the current main coroutine function to end the coroutine. // if (!coro::suspend(handle)) {
void generateCoroutineEnd() auto result = sz::Call(::function, ::basicBlock, coro::suspend, this->handle);
{ auto doneBlock = Nucleus::createBasicBlock();
// ... <REACTOR CODE> ... auto resumeBlock = Nucleus::createBasicBlock();
// Nucleus::createCondBr(V(result), resumeBlock, doneBlock);
// coro::setDone(handle);
// coro::switchToMainFiber();
// // Unreachable
// }
//
sz::Call(::function, ::basicBlock, coro::setDone, this->handle); // return false; // coroutine has been stopped by the caller.
::basicBlock = doneBlock;
Nucleus::createRetVoid(); // coroutine return value is ignored.
// A Win32 Fiber function must not end, otherwise it tears down the thread it's running on. // ... <REACTOR CODE> ...
// So we add code to switch back to the main thread. ::basicBlock = resumeBlock;
sz::Call(::function, ::basicBlock, coro::switchToMainFiber, this->handle);
} }
using FunctionUniquePtr = std::unique_ptr<Ice::Cfg>; using FunctionUniquePtr = std::unique_ptr<Ice::Cfg>;
...@@ -4739,7 +4651,7 @@ public: ...@@ -4739,7 +4651,7 @@ public:
// { // {
// YieldType* promise = coro::getPromisePtr(handle); // YieldType* promise = coro::getPromisePtr(handle);
// *out = *promise; // *out = *promise;
// coro::switchToRoutineFiber(handle); // coro::resume(handle);
// return true; // return true;
// } // }
// } // }
...@@ -4776,8 +4688,8 @@ public: ...@@ -4776,8 +4688,8 @@ public:
auto store = Ice::InstStore::create(awaitFunc, promiseVal, outPtr); auto store = Ice::InstStore::create(awaitFunc, promiseVal, outPtr);
resumeBlock->appendInst(store); resumeBlock->appendInst(store);
// coro::switchToRoutineFiber(handle); // coro::resume(handle);
sz::Call(awaitFunc, resumeBlock, coro::switchToRoutineFiber, handle); sz::Call(awaitFunc, resumeBlock, coro::resume, handle);
// return true; // return true;
Ice::InstRet *ret = Ice::InstRet::create(awaitFunc, ::context->getConstantInt32(1)); Ice::InstRet *ret = Ice::InstRet::create(awaitFunc, ::context->getConstantInt32(1));
...@@ -4806,9 +4718,7 @@ public: ...@@ -4806,9 +4718,7 @@ public:
{ {
// void coroutine_destroy(Nucleus::CoroutineHandle handle) // void coroutine_destroy(Nucleus::CoroutineHandle handle)
// { // {
// coro::convertMainFiberToThread(coroData); // coro::stop(handle); // signal and wait for coroutine to stop, and delete coroutine data
// coro::deleteRoutineFiber(handle);
// coro::destroyCoroutineData(handle);
// return; // return;
// } // }
...@@ -4822,14 +4732,8 @@ public: ...@@ -4822,14 +4732,8 @@ public:
auto *bb = destroyFunc->getEntryNode(); auto *bb = destroyFunc->getEntryNode();
// coro::convertMainFiberToThread(coroData); // coro::stop(handle); // signal and wait for coroutine to stop, and delete coroutine data
sz::Call(destroyFunc, bb, coro::convertMainFiberToThread, handle); sz::Call(destroyFunc, bb, coro::stop, handle);
// coro::deleteRoutineFiber(handle);
sz::Call(destroyFunc, bb, coro::deleteRoutineFiber, handle);
// coro::destroyCoroutineData(handle);
sz::Call(destroyFunc, bb, coro::destroyCoroutineData, handle);
// return; // return;
Ice::InstRet *ret = Ice::InstRet::create(destroyFunc); Ice::InstRet *ret = Ice::InstRet::create(destroyFunc);
...@@ -4848,26 +4752,19 @@ static Nucleus::CoroutineHandle invokeCoroutineBegin(std::function<Nucleus::Coro ...@@ -4848,26 +4752,19 @@ static Nucleus::CoroutineHandle invokeCoroutineBegin(std::function<Nucleus::Coro
// This doubles up as our coroutine handle // This doubles up as our coroutine handle
auto coroData = coro::createCoroutineData(); auto coroData = coro::createCoroutineData();
// Convert current thread to a fiber so we can create new fibers and switch to them marl::schedule([=] {
coro::convertThreadToMainFiber(coroData);
coro::FiberFunc fiberFunc = [&]() {
// Store handle in TLS so that the coroutine can grab it right away, before // Store handle in TLS so that the coroutine can grab it right away, before
// any fiber switch occurs. // any fiber switch occurs.
coro::setHandleParam(coroData); coro::setHandleParam(coroData);
// Invoke the begin function in the context of the routine fiber
beginFunc(); beginFunc();
// Either it yielded, or finished. In either case, we switch back to the main fiber. coroData->done.signal(); // coroutine is done.
// We don't ever return from this function, or the current thread will be destroyed. coroData->suspended.signal(); // resume any blocking await() call.
coro::switchToMainFiber(coroData); coroData->terminated.signal(); // signal that the coroutine data is ready for freeing.
}; });
coro::createRoutineFiber(coroData, &fiberFunc);
// Fiber will now start running, executing the saved beginFunc coroData->suspended.wait(); // block until the first yield or coroutine end
coro::switchToRoutineFiber(coroData);
return coroData; return coroData;
} }
...@@ -4914,7 +4811,6 @@ std::shared_ptr<Routine> Nucleus::acquireCoroutine(const char *name, const Confi ...@@ -4914,7 +4811,6 @@ std::shared_ptr<Routine> Nucleus::acquireCoroutine(const char *name, const Confi
// Finish generating coroutine functions // Finish generating coroutine functions
{ {
Ice::CfgLocalAllocatorScope scopedAlloc{ ::function }; Ice::CfgLocalAllocatorScope scopedAlloc{ ::function };
::coroGen->generateCoroutineEnd();
createRetVoidIfNoRet(); createRetVoidIfNoRet();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment