fase 4+5: fibers cooperatius substitueixen el game thread, sense mutex ni cv
This commit is contained in:
141
source/core/system/fiber.cpp
Normal file
141
source/core/system/fiber.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "core/system/fiber.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
// ucontext_t està marcat com a obsolet a POSIX.1-2008 però continua
|
||||
// funcional a glibc Linux i macOS. Si en el futur migrem a una alternativa
|
||||
// (boost::context, makecontext personalitzat) només cal tocar aquest fitxer.
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
|
||||
namespace GameFiber {
|
||||
|
||||
namespace {
|
||||
|
||||
bool initialized_ = false;
|
||||
bool done_ = false;
|
||||
EntryFn entry_fn_ = nullptr;
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
LPVOID main_fiber_ = nullptr;
|
||||
LPVOID game_fiber_ = nullptr;
|
||||
|
||||
void __stdcall trampoline(void* /*param*/) {
|
||||
if (entry_fn_) entry_fn_();
|
||||
done_ = true;
|
||||
SwitchToFiber(main_fiber_);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
ucontext_t main_ctx_{};
|
||||
ucontext_t fiber_ctx_{};
|
||||
void* fiber_stack_ = nullptr;
|
||||
|
||||
void trampoline() {
|
||||
if (entry_fn_) entry_fn_();
|
||||
done_ = true;
|
||||
// Retornar al main: uc_link apunta a main_ctx_ en init().
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
void init(EntryFn entry, std::size_t stack_size) {
|
||||
if (initialized_) destroy();
|
||||
entry_fn_ = entry;
|
||||
done_ = false;
|
||||
|
||||
#if defined(_WIN32)
|
||||
main_fiber_ = ConvertThreadToFiber(nullptr);
|
||||
if (!main_fiber_) {
|
||||
// Ja era un fiber (no sol passar en el main thread d'una app SDL).
|
||||
main_fiber_ = GetCurrentFiber();
|
||||
}
|
||||
game_fiber_ = CreateFiber(stack_size, trampoline, nullptr);
|
||||
if (!game_fiber_) {
|
||||
std::cerr << "GameFiber::init: CreateFiber failed\n";
|
||||
return;
|
||||
}
|
||||
#else
|
||||
fiber_stack_ = std::malloc(stack_size);
|
||||
if (!fiber_stack_) {
|
||||
std::cerr << "GameFiber::init: malloc failed\n";
|
||||
return;
|
||||
}
|
||||
getcontext(&fiber_ctx_);
|
||||
fiber_ctx_.uc_stack.ss_sp = fiber_stack_;
|
||||
fiber_ctx_.uc_stack.ss_size = stack_size;
|
||||
fiber_ctx_.uc_link = &main_ctx_;
|
||||
makecontext(&fiber_ctx_, trampoline, 0);
|
||||
#endif
|
||||
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (!initialized_) return;
|
||||
#if defined(_WIN32)
|
||||
if (game_fiber_) {
|
||||
DeleteFiber(game_fiber_);
|
||||
game_fiber_ = nullptr;
|
||||
}
|
||||
// No desconvertim el main thread: SDL pot estar-ne pendent i ja no
|
||||
// tornem a crear fibers en aquesta execució. ConvertFiberToThread()
|
||||
// només cal si volguerem reutilitzar el main com a thread normal.
|
||||
#else
|
||||
if (fiber_stack_) {
|
||||
std::free(fiber_stack_);
|
||||
fiber_stack_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
initialized_ = false;
|
||||
done_ = false;
|
||||
entry_fn_ = nullptr;
|
||||
}
|
||||
|
||||
void resume() {
|
||||
if (!initialized_ || done_) return;
|
||||
#if defined(_WIN32)
|
||||
SwitchToFiber(game_fiber_);
|
||||
#else
|
||||
swapcontext(&main_ctx_, &fiber_ctx_);
|
||||
#endif
|
||||
}
|
||||
|
||||
void yield() {
|
||||
if (!initialized_) return;
|
||||
#if defined(_WIN32)
|
||||
SwitchToFiber(main_fiber_);
|
||||
#else
|
||||
swapcontext(&fiber_ctx_, &main_ctx_);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_done() { return done_; }
|
||||
bool is_initialized() { return initialized_; }
|
||||
|
||||
} // namespace GameFiber
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
Reference in New Issue
Block a user