Files
wiicompiled/runtime/src/host_context.cpp
T
theofficialgman 279ce8328f Macos support into main (#228)
* macos: add x86_64 Intel support

* (feat) Apple Silicon macOS CI building and Setup.pkg documentation (#118)

* docs(macos): document Setup.pkg installation

Add Apple Silicon macOS CI coverage for runtime configuration, substrate tests, and Setup.pkg packaging alongside the macOS installation instructions.

* macos: pin Apple Silicon deployment target

* fix(macos): restore Retro Rewind local builds

* macos: package universal setup tools

* ci: build macOS input expression tests

* runtime: Do not force 14.0 minimum anymore

new minimum is 12.0

* macos: support older libc++ algorithms

* macos: allow undefined MTLLogStateDescriptor for older SDKs

* tests: deflake input expression timing window test

* build: Fix mac tests

* translator: emit null statement after continuation labels for C++17 compatibility

* feat(macos): add MetalFX spatial upscaling

* Fix automatic music muting on macOS

Co-Authored-By: Michael G <10155689+DarthMDev@users.noreply.github.com>
Co-Authored-By: Daan Vervacke <23398694+DaanVervacke@users.noreply.github.com>

* Address CodeRabbit review comments and integrate upstream TLS cmake

* Remove version requirement for running package CI

Co-Authored-By: Michael G <10155689+DarthMDev@users.noreply.github.com>

* publish-app: fix dependency discovery from build dir, handle spaces in paths, and fail on missing deps

* publish-app: preserve subdirectory suffix during @rpath dependency lookup

* cmake: synchronize CMAKE_SYSTEM_PROCESSOR with CMAKE_OSX_ARCHITECTURES on macOS

* fix rpaths

---------

Co-authored-by: DarthM <mgracer48@yahoo.com>
Co-authored-by: Michael G <10155689+DarthMDev@users.noreply.github.com>
Co-authored-by: Daan Vervacke <23398694+DaanVervacke@users.noreply.github.com>
Co-authored-by: patchzyy <64382339+patchzyy@users.noreply.github.com>
2026-10-03 11:07:15 +02:00

271 lines
6.3 KiB
C++

#include "host_context.h"
#if defined(_WIN32)
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#elif defined(__APPLE__) && defined(__aarch64__)
#include <sys/mman.h>
#include <unistd.h>
extern "C" void mkw_co_switch(void** targetSp, void** sourceSp);
extern "C" void* mkw_co_init(void* stackTop, void (*entry)(void*), void* argument);
#elif defined(__linux__) || (defined(__APPLE__) && defined(__x86_64__))
#include <libco.h>
#include <cstdlib>
#include <unordered_map>
#else
#error "HostContext needs a supported cooperative-context backend"
#endif
namespace HostContext {
#if defined(_WIN32)
namespace {
thread_local bool g_convertedScheduler = false;
}
bool InitializeScheduler(Handle* scheduler)
{
void* context = ConvertThreadToFiber(nullptr);
g_convertedScheduler = context != nullptr;
if (!context) {
context = GetCurrentFiber();
}
*scheduler = context;
return context != nullptr;
}
void ShutdownScheduler(Handle scheduler)
{
if (scheduler && g_convertedScheduler) {
ConvertFiberToThread();
}
g_convertedScheduler = false;
}
Handle Create(std::size_t stackSize, Entry entry, void* argument)
{
return CreateFiber(stackSize, entry, argument);
}
void Destroy(Handle context)
{
if (context) {
DeleteFiber(context);
}
}
bool IsCurrent(Handle context)
{
return context != nullptr && GetCurrentFiber() == context;
}
void Switch(Handle target)
{
SwitchToFiber(target);
}
#elif defined(__APPLE__) && defined(__aarch64__)
namespace {
struct Context {
void* savedStackPointer = nullptr;
void* stack = nullptr;
std::size_t stackSize = 0;
};
// Guest scheduling is confined to the initialized main host thread. Keeping
// this as ordinary process state also avoids relying on Darwin TLS internals
// while executing on a manually managed stack.
Context* g_current = nullptr;
}
bool InitializeScheduler(Handle* scheduler)
{
auto* context = new Context();
g_current = context;
*scheduler = context;
return true;
}
void ShutdownScheduler(Handle scheduler)
{
auto* context = static_cast<Context*>(scheduler);
if (g_current == context) {
g_current = nullptr;
}
delete context;
}
Handle Create(std::size_t stackSize, Entry entry, void* argument)
{
auto* context = new Context();
const std::size_t guardSize = static_cast<std::size_t>(getpagesize());
const std::size_t totalSize = stackSize + guardSize;
context->stack = mmap(nullptr, totalSize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (context->stack == MAP_FAILED) {
delete context;
return nullptr;
}
// Fault on stack overflow instead of corrupting the preceding mapping.
if (mprotect(context->stack, guardSize, PROT_NONE) != 0) {
munmap(context->stack, totalSize);
delete context;
return nullptr;
}
context->stackSize = totalSize;
auto* stackTop = static_cast<char*>(context->stack) + totalSize;
context->savedStackPointer = mkw_co_init(stackTop, entry, argument);
return context;
}
void Destroy(Handle context)
{
auto* nativeContext = static_cast<Context*>(context);
if (!nativeContext) {
return;
}
if (nativeContext->stack) {
munmap(nativeContext->stack, nativeContext->stackSize);
}
delete nativeContext;
}
bool IsCurrent(Handle context)
{
return context != nullptr && context == g_current;
}
void Switch(Handle target)
{
auto* destination = static_cast<Context*>(target);
Context* source = g_current;
if (!destination || destination == source) {
return;
}
g_current = destination;
mkw_co_switch(&destination->savedStackPointer, &source->savedStackPointer);
g_current = source;
}
#elif defined(__linux__) || (defined(__APPLE__) && defined(__x86_64__))
namespace {
struct Context {
cothread_t native = nullptr;
Entry entry = nullptr;
void* argument = nullptr;
bool ownsNative = false;
};
thread_local Context* g_current = nullptr;
thread_local std::unordered_map<cothread_t, Context*> g_contexts;
void ContextEntry()
{
const auto found = g_contexts.find(co_active());
if (found == g_contexts.end() || !found->second || !found->second->entry) {
std::abort();
}
Context* context = found->second;
g_current = context;
context->entry(context->argument);
// A guest fiber must return through FiberProc's scheduler handoff. There
// is no valid native caller to return to from libco's entry trampoline.
std::abort();
}
} // namespace
bool InitializeScheduler(Handle* scheduler)
{
auto* context = new Context();
context->native = co_active();
if (!context->native) {
delete context;
return false;
}
g_current = context;
g_contexts.emplace(context->native, context);
*scheduler = context;
return true;
}
void ShutdownScheduler(Handle scheduler)
{
auto* context = static_cast<Context*>(scheduler);
if (!context) {
return;
}
g_contexts.erase(context->native);
if (g_current == context) {
g_current = nullptr;
}
delete context;
}
Handle Create(std::size_t stackSize, Entry entry, void* argument)
{
auto* context = new Context();
context->entry = entry;
context->argument = argument;
context->native = co_create(static_cast<unsigned int>(stackSize), ContextEntry);
context->ownsNative = context->native != nullptr;
if (!context->native) {
delete context;
return nullptr;
}
g_contexts.emplace(context->native, context);
return context;
}
void Destroy(Handle context)
{
auto* nativeContext = static_cast<Context*>(context);
if (!nativeContext) {
return;
}
g_contexts.erase(nativeContext->native);
if (nativeContext->ownsNative) {
co_delete(nativeContext->native);
}
delete nativeContext;
}
bool IsCurrent(Handle context)
{
return context != nullptr && context == g_current;
}
void Switch(Handle target)
{
auto* destination = static_cast<Context*>(target);
Context* source = g_current;
if (!destination || destination == source) {
return;
}
g_current = destination;
co_switch(destination->native);
g_current = source;
}
#endif
} // namespace HostContext