mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-10 01:24:41 -06:00
Util: Add fcontext fiber implementation
This commit is contained in:
parent
c2e807f8a3
commit
54f043c0f2
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 };
|
||||
};
|
||||
55
src/util/Fiber/FiberFContext.cpp
Normal file
55
src/util/Fiber/FiberFContext.cpp
Normal file
@ -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<uint8*>(m_stackPtr) + stackSize, stackSize, Fiber::Start);
|
||||
}
|
||||
|
||||
Fiber::Fiber(void* privateData) : m_privateData(privateData)
|
||||
{
|
||||
}
|
||||
|
||||
void Fiber::Start(transfer_t transfer)
|
||||
{
|
||||
auto fiber = static_cast<Fiber*>(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;
|
||||
}
|
||||
29
src/util/Fiber/FiberFContext.h
Normal file
29
src/util/Fiber/FiberFContext.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/context/detail/fcontext.hpp>
|
||||
|
||||
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{};
|
||||
};
|
||||
@ -1,34 +1,30 @@
|
||||
#include "Fiber.h"
|
||||
#include <ucontext.h>
|
||||
#include <atomic>
|
||||
#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);
|
||||
}
|
||||
|
||||
20
src/util/Fiber/FiberUContext.h
Normal file
20
src/util/Fiber/FiberUContext.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <ucontext.h>
|
||||
|
||||
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 };
|
||||
};
|
||||
@ -1,23 +1,20 @@
|
||||
#include "Fiber.h"
|
||||
#include <Windows.h>
|
||||
#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()
|
||||
|
||||
19
src/util/Fiber/FiberWin.h
Normal file
19
src/util/Fiber/FiberWin.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
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;
|
||||
};
|
||||
@ -27,6 +27,10 @@
|
||||
"boost-ptr-container",
|
||||
"boost-property-tree",
|
||||
"boost-static-string",
|
||||
{
|
||||
"name": "boost-context",
|
||||
"platform": "android"
|
||||
},
|
||||
"boost-random",
|
||||
{
|
||||
"name": "fmt",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user