Refactor SDL/FreeRTOS implementation to support macOS simulator properly (#653)

- Run SDL from main() and place FreeRTOS in separate thread. This fixes macOS support.
- Updated GitHub Actions to publish macOS simulator build for testing, updated amd64 to x86_64 for consistent naming.
This commit is contained in:
Ken Van Hoeylandt
2026-09-20 23:12:42 +02:00
committed by Adolfo Reyna
parent 89e8baf517
commit 72089f74f3
25 changed files with 748 additions and 373 deletions
@@ -2,20 +2,15 @@
#include <stddef.h>
/**
* Linked in with -Wl,--wrap=pthread_attr_setstack (see Tactility/CMakeLists.txt).
* FreeRTOS's POSIX port hands every task a stack carved from its own heap (pvPortMalloc) via this call.
* pthread_attr_setstack requires page alignment that pvPortMalloc doesn't guarantee.
* When it succeeds anyway, the task's real pthread stack ends up living inside that small FreeRTOS heap region,
* where a thread doing heavier stack work (e.g. Mesa GL shader compilation) can silently corrupt adjacent heap_4 objects.
* No-op'ing the call instead leaves every task's pthread_attr_t at its pthread_attr_init() default,
* so pthread_create() gives it a real, properly sized stack.
*
* FreeRTOS's POSIX port (Libraries/FreeRTOS-Kernel/portable/ThirdParty/GCC/Posix/port.c)
* hands every task a stack carved out of its own heap (pvPortMalloc) via this call.
* pthread_attr_setstack requires page alignment, which pvPortMalloc doesn't guarantee;
* when it happens to succeed anyway (allocator alignment can vary run to run), the
* task's real pthread stack ends up living inside that small FreeRTOS heap region -
* fine for typical embedded task code, but a desktop GL driver doing on-the-fly shader
* compilation on that thread (e.g. Mesa on first frame present) can overflow it and
* silently corrupt adjacent heap_4 objects.
*
* Wrapping the call out entirely (rather than patching the vendored port.c) leaves every
* task's pthread_attr_t at its pthread_attr_init() default, so pthread_create() always
* gives it a real, properly allocated default-size stack instead.
* Linked via -Wl,--wrap=pthread_attr_setstack (this module's own CMakeLists.txt) on non-Apple
* platforms; reused as a dyld interpose target below on Apple platforms, whose linker lacks --wrap.
*/
int __wrap_pthread_attr_setstack(pthread_attr_t* attr, void* stackaddr, size_t stacksize) {
(void)attr;
@@ -23,3 +18,17 @@ int __wrap_pthread_attr_setstack(pthread_attr_t* attr, void* stackaddr, size_t s
(void)stacksize;
return 0;
}
#ifdef __APPLE__
// <mach-o/dyld-interposing.h> isn't a public SDK header (it ships with dyld's own source, not
// Xcode/Command Line Tools), so this reimplements its DYLD_INTERPOSE macro locally.
#define TT_DYLD_INTERPOSE(replacement, replacee) \
__attribute__((used)) static struct { const void* replacement; const void* replacee; } \
tt_interpose_##replacee __attribute__((section("__DATA,__interpose"))) = { \
(const void*)(unsigned long)&(replacement), (const void*)(unsigned long)&(replacee) \
};
TT_DYLD_INTERPOSE(__wrap_pthread_attr_setstack, pthread_attr_setstack)
#endif