Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: SDL3 crash recovery via sigsetjmp — no fork needed

Replace fork-based probe with signal handler + sigsetjmp/siglongjmp.
If Mesa DRI crashes during dlopen or SDL_Init, the SIGSEGV/SIGBUS
handler catches it, restores signal handlers, cleans up, and falls
back to DRM dumb buffers. No fork, no child process, no PID 1 issues.

Works as init (PID 1) and under systemd alike.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+50 -41
+50 -41
fedac/native/src/drm-display.c
··· 94 94 return 1; 95 95 } 96 96 97 - // Probe SDL3 in a child process — catches segfaults from broken DRI/GBM/Mesa 98 - static int sdl_probe_safe(void) { 99 - pid_t pid = fork(); 100 - if (pid < 0) return 0; 101 - if (pid == 0) { 102 - // Child: try full init. Crash = signal caught by parent. 103 - setenv("SDL_VIDEO_DRIVER", "kmsdrm", 0); 104 - setenv("LIBGL_DRIVERS_PATH", "/lib64/dri", 0); 105 - setenv("GBM_DRIVERS_PATH", "/lib64/dri", 0); 106 - setenv("MESA_LOADER_DRIVER_OVERRIDE", "iris", 0); 107 - void *lib = dlopen("libSDL3.so.0", RTLD_LAZY); 108 - if (!lib) _exit(2); 109 - pfn_SDL_Init fn_init = (pfn_SDL_Init)dlsym(lib, "SDL_Init"); 110 - pfn_SDL_Quit fn_quit = (pfn_SDL_Quit)dlsym(lib, "SDL_Quit"); 111 - if (!fn_init) _exit(3); 112 - int ok = fn_init(0x20) ? 0 : 1; // SDL_INIT_VIDEO = 0x20 113 - if (!ok && fn_quit) fn_quit(); 114 - dlclose(lib); 115 - _exit(ok); 116 - } 117 - int status = 0; 118 - waitpid(pid, &status, 0); 119 - if (WIFSIGNALED(status)) { 120 - ac_log("[sdl3] Probe crashed (signal %d) — falling back to DRM\n", WTERMSIG(status)); 121 - return 0; 122 - } 123 - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) return 1; 124 - ac_log("[sdl3] Probe failed (exit %d) — falling back to DRM\n", 125 - WIFEXITED(status) ? WEXITSTATUS(status) : -1); 126 - return 0; 97 + // Signal-based crash recovery for SDL3 init (no fork needed) 98 + #include <setjmp.h> 99 + static sigjmp_buf sdl_crash_jmp; 100 + static volatile int sdl_crash_sig = 0; 101 + 102 + static void sdl_crash_handler(int sig) { 103 + sdl_crash_sig = sig; 104 + siglongjmp(sdl_crash_jmp, 1); 127 105 } 128 106 129 107 static ACDisplay *sdl_init(void) { 130 - // Skip SDL when running as PID 1 (bare metal init) — the DRI/Mesa 131 - // probe can corrupt GPU state even in a child process, and fork() 132 - // from PID 1 has kernel implications. Use DRM dumb buffers instead. 133 - // SDL works fine when running under a proper init system (systemd, etc.) 134 - if (getpid() == 1) { 135 - ac_log("[sdl3] Skipping SDL3 (PID 1 — using DRM dumb buffers)\n"); 108 + // Set Mesa env vars before any dlopen 109 + setenv("LIBGL_DRIVERS_PATH", "/lib64/dri", 0); 110 + setenv("GBM_DRIVERS_PATH", "/lib64/dri", 0); 111 + setenv("MESA_LOADER_DRIVER_OVERRIDE", "iris", 0); 112 + if (getpid() == 1) setenv("SDL_VIDEO_DRIVER", "kmsdrm", 0); 113 + 114 + // Install crash handler — catches SIGSEGV/SIGBUS from Mesa DRI loading 115 + struct sigaction sa = {0}, old_segv = {0}, old_bus = {0}, old_abrt = {0}; 116 + sa.sa_handler = sdl_crash_handler; 117 + sa.sa_flags = 0; 118 + sigemptyset(&sa.sa_mask); 119 + sigaction(SIGSEGV, &sa, &old_segv); 120 + sigaction(SIGBUS, &sa, &old_bus); 121 + sigaction(SIGABRT, &sa, &old_abrt); 122 + 123 + if (sigsetjmp(sdl_crash_jmp, 1) != 0) { 124 + // Crashed during SDL init — restore handlers and fall back 125 + sigaction(SIGSEGV, &old_segv, NULL); 126 + sigaction(SIGBUS, &old_bus, NULL); 127 + sigaction(SIGABRT, &old_abrt, NULL); 128 + ac_log("[sdl3] Crashed (signal %d) during init — falling back to DRM\n", sdl_crash_sig); 129 + if (sdl_lib_handle) { dlclose(sdl_lib_handle); sdl_lib_handle = NULL; } 130 + memset(&sdl, 0, sizeof(sdl)); 136 131 return NULL; 137 132 } 138 - // Probe in child process first (catches DRI segfaults) 139 - if (!sdl_probe_safe()) return NULL; 140 - // Load SDL3 via dlopen 141 - if (!sdl_load()) return NULL; 142 133 143 - setenv("SDL_VIDEO_DRIVER", "kmsdrm", 0); 134 + // Try loading SDL3 (dlopen may trigger Mesa DRI load → potential crash) 135 + if (!sdl_load()) { 136 + sigaction(SIGSEGV, &old_segv, NULL); 137 + sigaction(SIGBUS, &old_bus, NULL); 138 + sigaction(SIGABRT, &old_abrt, NULL); 139 + return NULL; 140 + } 144 141 145 142 if (!sdl.Init(0x20)) { // SDL_INIT_VIDEO 146 143 ac_log("[sdl3] SDL_Init failed: %s\n", sdl.GetError ? sdl.GetError() : "?"); 144 + sigaction(SIGSEGV, &old_segv, NULL); 145 + sigaction(SIGBUS, &old_bus, NULL); 146 + sigaction(SIGABRT, &old_abrt, NULL); 147 147 return NULL; 148 148 } 149 + // Past the danger zone — restore handlers now 150 + sigaction(SIGSEGV, &old_segv, NULL); 151 + sigaction(SIGBUS, &old_bus, NULL); 152 + sigaction(SIGABRT, &old_abrt, NULL); 149 153 150 154 unsigned int primary = sdl.GetPrimaryDisplay(); 151 155 if (!primary) { ··· 196 200 d->sdl_tex_h = 0; 197 201 snprintf(d->sdl_renderer_name, sizeof(d->sdl_renderer_name), "%s", 198 202 ren_name ? ren_name : "unknown"); 203 + 204 + // Restore signal handlers — SDL init survived 205 + sigaction(SIGSEGV, &old_segv, NULL); 206 + sigaction(SIGBUS, &old_bus, NULL); 207 + sigaction(SIGABRT, &old_abrt, NULL); 199 208 200 209 ac_log("[sdl3] Ready (%dx%d)\n", d->width, d->height); 201 210 return d;