Summary
The headless backend crashes on macOS because ftruncate() on a POSIX shared memory object fails with EINVAL for the 2.4 MB double-buffered framebuffer.
Reproduction
make defconfig
# switch to headless backend in .config
make
./demo-headless
Output:
Failed to resize shared memory to 2473984 bytes: Invalid argument
ERROR src/api.c:38: Backend initialization failed (640x480)
This happens with or without CONFIG_MEM_TLSF -- it is a backend-specific issue.
Root cause
backend/headless.c:316 calls ftruncate(tx->shm_fd, tx->shm_size) on an fd from shm_open(). On macOS, ftruncate on POSIX shared memory objects has stricter constraints than Linux:
- macOS requires
shm_unlink of any stale object before shm_open with O_CREAT, or the existing object's size conflicts with the new truncation.
- macOS may also reject
ftruncate if the requested size exceeds per-process POSIX shm limits (kern.sysv.shmmax).
The current code at backend/headless.c:305 opens with O_CREAT | O_RDWR but does not shm_unlink before opening, so a leftover object from a previous crashed run causes ftruncate to fail.
Suggested fix
Call shm_unlink(TWIN_HEADLESS_SHM_NAME) before shm_open() to remove any stale object, matching the cleanup already done in _twin_headless_exit() at line 372. Alternatively, open with O_CREAT | O_EXCL and fall back to unlink + retry if EEXIST.
Summary
The headless backend crashes on macOS because
ftruncate()on a POSIX shared memory object fails withEINVALfor the 2.4 MB double-buffered framebuffer.Reproduction
Output:
This happens with or without
CONFIG_MEM_TLSF-- it is a backend-specific issue.Root cause
backend/headless.c:316callsftruncate(tx->shm_fd, tx->shm_size)on an fd fromshm_open(). On macOS,ftruncateon POSIX shared memory objects has stricter constraints than Linux:shm_unlinkof any stale object beforeshm_openwithO_CREAT, or the existing object's size conflicts with the new truncation.ftruncateif the requested size exceeds per-process POSIX shm limits (kern.sysv.shmmax).The current code at
backend/headless.c:305opens withO_CREAT | O_RDWRbut does notshm_unlinkbefore opening, so a leftover object from a previous crashed run causesftruncateto fail.Suggested fix
Call
shm_unlink(TWIN_HEADLESS_SHM_NAME)beforeshm_open()to remove any stale object, matching the cleanup already done in_twin_headless_exit()at line 372. Alternatively, open withO_CREAT | O_EXCLand fall back to unlink + retry ifEEXIST.