diff --git a/CMakeLists.txt b/CMakeLists.txt index 644032ce..ecb68964 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,6 +154,9 @@ find_package(CURL REQUIRED) find_package(pugixml REQUIRED) find_package(RapidJSON REQUIRED) find_package(Boost COMPONENTS program_options filesystem nowide REQUIRED) +if(ANDROID) + find_package(Boost COMPONENTS context REQUIRED) +endif() find_package(libzip REQUIRED) find_package(glslang REQUIRED) find_package(ZLIB REQUIRED) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index a23754ef..5705825d 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -74,7 +74,12 @@ if(WIN32) target_sources(CemuUtil PRIVATE MemMapper/MemMapperWin.cpp) target_sources(CemuUtil PRIVATE SystemInfo/SystemInfoWin.cpp) elseif(UNIX) - target_sources(CemuUtil PRIVATE Fiber/FiberUnix.cpp) + if(ANDROID) + target_sources(CemuUtil PRIVATE Fiber/FiberFContext.cpp) + target_link_libraries(CemuUtil PRIVATE Boost::context) + else() + target_sources(CemuUtil PRIVATE Fiber/FiberUContext.cpp) + endif() target_sources(CemuUtil PRIVATE MemMapper/MemMapperUnix.cpp) target_sources(CemuUtil PRIVATE SystemInfo/SystemInfoUnix.cpp) if(NOT APPLE) diff --git a/src/util/Fiber/Fiber.h b/src/util/Fiber/Fiber.h index c72c62fc..b4ee323c 100644 --- a/src/util/Fiber/Fiber.h +++ b/src/util/Fiber/Fiber.h @@ -1,22 +1,9 @@ #pragma once -#if BOOST_OS_WINDOWS - +#if BOOST_PLAT_ANDROID +#include "FiberFContext.h" +#elif BOOST_OS_WINDOWS +#include "FiberWin.h" +#else +#include "FiberUContext.h" #endif - -class Fiber -{ -public: - Fiber(void(*FiberEntryPoint)(void* userParam), void* userParam, void* privateData); - ~Fiber(); - - static Fiber* PrepareCurrentThread(void* privateData = nullptr); - static void Switch(Fiber& targetFiber); - static void* GetFiberPrivateData(); -private: - Fiber(void* privateData); // fiber from current thread - - void* m_implData{nullptr}; - void* m_privateData; - void* m_stackPtr{ nullptr }; -}; \ No newline at end of file diff --git a/src/util/Fiber/FiberFContext.cpp b/src/util/Fiber/FiberFContext.cpp new file mode 100644 index 00000000..75c59e44 --- /dev/null +++ b/src/util/Fiber/FiberFContext.cpp @@ -0,0 +1,55 @@ +#include "FiberFContext.h" + +thread_local Fiber* sCurrentFiber = nullptr; + +using namespace boost::context::detail; + +Fiber::Fiber(void (*fiberEntryPoint)(void* userParam), void* userParam, void* privateData) + : m_entryPoint(fiberEntryPoint), + m_userParam(userParam), + m_privateData(privateData) +{ + const size_t stackSize = 2 * 1024 * 1024; + m_stackPtr = malloc(stackSize); + m_context = make_fcontext(static_cast(m_stackPtr) + stackSize, stackSize, Fiber::Start); +} + +Fiber::Fiber(void* privateData) : m_privateData(privateData) +{ +} + +void Fiber::Start(transfer_t transfer) +{ + auto fiber = static_cast(transfer.data); + fiber->m_prevFiber->m_context = transfer.fctx; + fiber->m_entryPoint(fiber->m_userParam); +} + +Fiber::~Fiber() +{ + if (m_stackPtr) + free(m_stackPtr); +} + +Fiber* Fiber::PrepareCurrentThread(void* privateData) +{ + sCurrentFiber = new Fiber(privateData); + return sCurrentFiber; +} + +void Fiber::Switch(Fiber& targetFiber) +{ + if (&targetFiber == sCurrentFiber) + return; + + Fiber* thisFiber = sCurrentFiber; + sCurrentFiber = &targetFiber; + targetFiber.m_prevFiber = thisFiber; + transfer_t transfer = jump_fcontext(targetFiber.m_context, &targetFiber); + thisFiber->m_prevFiber->m_context = transfer.fctx; +} + +void* Fiber::GetFiberPrivateData() +{ + return sCurrentFiber->m_privateData; +} diff --git a/src/util/Fiber/FiberFContext.h b/src/util/Fiber/FiberFContext.h new file mode 100644 index 00000000..f3621d27 --- /dev/null +++ b/src/util/Fiber/FiberFContext.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +class Fiber +{ + public: + Fiber(void (*FiberEntryPoint)(void* userParam), void* userParam, void* privateData); + ~Fiber(); + + static Fiber* PrepareCurrentThread(void* privateData = nullptr); + static void Switch(Fiber& targetFiber); + static void* GetFiberPrivateData(); + + private: + static void Start(boost::context::detail::transfer_t transfer); + Fiber(void* privateData); // fiber from current thread + + boost::context::detail::fcontext_t m_context{}; + + void (*m_entryPoint)(void* userParam){}; + void* m_userParam{}; + + void* m_privateData; + + void* m_stackPtr{}; + + Fiber* m_prevFiber{}; +}; \ No newline at end of file diff --git a/src/util/Fiber/FiberUnix.cpp b/src/util/Fiber/FiberUContext.cpp similarity index 60% rename from src/util/Fiber/FiberUnix.cpp rename to src/util/Fiber/FiberUContext.cpp index 36430449..8f7d0001 100644 --- a/src/util/Fiber/FiberUnix.cpp +++ b/src/util/Fiber/FiberUContext.cpp @@ -1,34 +1,30 @@ -#include "Fiber.h" -#include -#include +#include "FiberUContext.h" thread_local Fiber* sCurrentFiber{}; Fiber::Fiber(void(*FiberEntryPoint)(void* userParam), void* userParam, void* privateData) : m_privateData(privateData) { - ucontext_t* ctx = (ucontext_t*)malloc(sizeof(ucontext_t)); + m_ctx = (ucontext_t*)malloc(sizeof(ucontext_t)); const size_t stackSize = 2 * 1024 * 1024; m_stackPtr = malloc(stackSize); - getcontext(ctx); - ctx->uc_stack.ss_sp = m_stackPtr; - ctx->uc_stack.ss_size = stackSize; - ctx->uc_link = &ctx[0]; + getcontext(m_ctx); + m_ctx->uc_stack.ss_sp = m_stackPtr; + m_ctx->uc_stack.ss_size = stackSize; + m_ctx->uc_link = &m_ctx[0]; #ifdef __arm64__ // https://www.man7.org/linux/man-pages/man3/makecontext.3.html#NOTES - makecontext(ctx, (void(*)())FiberEntryPoint, 2, (uint64) userParam >> 32, userParam); + makecontext(m_ctx, (void(*)())FiberEntryPoint, 2, (uint64) userParam >> 32, userParam); #else - makecontext(ctx, (void(*)())FiberEntryPoint, 1, userParam); + makecontext(m_ctx, (void(*)())FiberEntryPoint, 1, userParam); #endif - this->m_implData = (void*)ctx; } Fiber::Fiber(void* privateData) : m_privateData(privateData) { - ucontext_t* ctx = (ucontext_t*)malloc(sizeof(ucontext_t)); - getcontext(ctx); - this->m_implData = (void*)ctx; + m_ctx = (ucontext_t*)malloc(sizeof(ucontext_t)); + getcontext(m_ctx); m_stackPtr = nullptr; } @@ -36,7 +32,7 @@ Fiber::~Fiber() { if(m_stackPtr) free(m_stackPtr); - free(m_implData); + free(m_ctx); } Fiber* Fiber::PrepareCurrentThread(void* privateData) @@ -51,7 +47,7 @@ void Fiber::Switch(Fiber& targetFiber) Fiber* leavingFiber = sCurrentFiber; sCurrentFiber = &targetFiber; std::atomic_thread_fence(std::memory_order_seq_cst); - swapcontext((ucontext_t*)(leavingFiber->m_implData), (ucontext_t*)(targetFiber.m_implData)); + swapcontext(leavingFiber->m_ctx, targetFiber.m_ctx); std::atomic_thread_fence(std::memory_order_seq_cst); } diff --git a/src/util/Fiber/FiberUContext.h b/src/util/Fiber/FiberUContext.h new file mode 100644 index 00000000..38178243 --- /dev/null +++ b/src/util/Fiber/FiberUContext.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +class Fiber +{ +public: + Fiber(void(*FiberEntryPoint)(void* userParam), void* userParam, void* privateData); + ~Fiber(); + + static Fiber* PrepareCurrentThread(void* privateData = nullptr); + static void Switch(Fiber& targetFiber); + static void* GetFiberPrivateData(); +private: + Fiber(void* privateData); // fiber from current thread + + ucontext_t* m_ctx{nullptr}; + void* m_privateData; + void* m_stackPtr{ nullptr }; +}; \ No newline at end of file diff --git a/src/util/Fiber/FiberWin.cpp b/src/util/Fiber/FiberWin.cpp index ae5da517..6831e5f1 100644 --- a/src/util/Fiber/FiberWin.cpp +++ b/src/util/Fiber/FiberWin.cpp @@ -1,23 +1,20 @@ -#include "Fiber.h" -#include +#include "FiberWin.h" thread_local Fiber* sCurrentFiber{}; Fiber::Fiber(void(*FiberEntryPoint)(void* userParam), void* userParam, void* privateData) : m_privateData(privateData) { - HANDLE fiberHandle = CreateFiber(2 * 1024 * 1024, (LPFIBER_START_ROUTINE)FiberEntryPoint, userParam); - this->m_implData = (void*)fiberHandle; + m_handle = CreateFiber(2 * 1024 * 1024, (LPFIBER_START_ROUTINE)FiberEntryPoint, userParam); } Fiber::Fiber(void* privateData) : m_privateData(privateData) { - this->m_implData = (void*)ConvertThreadToFiber(nullptr); - this->m_stackPtr = nullptr; + m_handle = ConvertThreadToFiber(nullptr); } Fiber::~Fiber() { - DeleteFiber((HANDLE)m_implData); + DeleteFiber(m_handle); } Fiber* Fiber::PrepareCurrentThread(void* privateData) @@ -31,7 +28,7 @@ Fiber* Fiber::PrepareCurrentThread(void* privateData) void Fiber::Switch(Fiber& targetFiber) { sCurrentFiber = &targetFiber; - SwitchToFiber((HANDLE)targetFiber.m_implData); + SwitchToFiber(targetFiber.m_handle); } void* Fiber::GetFiberPrivateData() diff --git a/src/util/Fiber/FiberWin.h b/src/util/Fiber/FiberWin.h new file mode 100644 index 00000000..fb7a8c18 --- /dev/null +++ b/src/util/Fiber/FiberWin.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +class Fiber +{ +public: + Fiber(void(*FiberEntryPoint)(void* userParam), void* userParam, void* privateData); + ~Fiber(); + + static Fiber* PrepareCurrentThread(void* privateData = nullptr); + static void Switch(Fiber& targetFiber); + static void* GetFiberPrivateData(); +private: + Fiber(void* privateData); // fiber from current thread + + HANDLE m_handle{nullptr}; + void* m_privateData; +}; \ No newline at end of file diff --git a/vcpkg.json b/vcpkg.json index 3687d2b3..37591e2a 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -27,6 +27,10 @@ "boost-ptr-container", "boost-property-tree", "boost-static-string", + { + "name": "boost-context", + "platform": "android" + }, "boost-random", { "name": "fmt",