From fea93fdf5abdc8f9a681d33cf0ff301796ff9d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 5 Nov 2026 13:21:34 +0100 Subject: [PATCH 1/2] fix: support PHP 8.7 PHP 8.7 removed zend_atomic.h in favor of C11 atomics and dropped the terminate_process member from sapi_module_struct. --- frankenphp.c | 14 ++++++++------ frankenphp.h | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/frankenphp.c b/frankenphp.c index 588864a991..f5bfd447c3 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -288,7 +288,7 @@ static pthread_once_t kill_signal_handler_installed = PTHREAD_ONCE_INIT; * pthread_kill when this is false, so a sigaction failure (invalid * signal number, exhausted handler slots, etc.) can't deliver the * signal with its default action (process termination). */ -static zend_atomic_bool kill_signal_handler_active; +static frankenphp_atomic_bool kill_signal_handler_active; static void install_kill_signal_handler(void) { /* No SA_RESTART so syscalls return EINTR rather than being restarted. * SA_ONSTACK guards against an accidental process-level delivery to a @@ -299,7 +299,7 @@ static void install_kill_signal_handler(void) { sigemptyset(&sa.sa_mask); sa.sa_flags = SA_ONSTACK; if (sigaction(FRANKENPHP_KILL_SIGNAL, &sa, NULL) == 0) { - zend_atomic_bool_store(&kill_signal_handler_active, true); + frankenphp_atomic_bool_store(&kill_signal_handler_active, true); } } #endif @@ -333,14 +333,14 @@ void frankenphp_force_kill_thread(force_kill_slot slot) { /* Atomic stores first: by the time the thread wakes (signal-driven or * natural) the VM sees them and bails through zend_timeout(). */ - zend_atomic_bool_store(slot.timed_out, true); - zend_atomic_bool_store(slot.vm_interrupt, true); + frankenphp_atomic_bool_store(slot.timed_out, true); + frankenphp_atomic_bool_store(slot.vm_interrupt, true); #ifdef FRANKENPHP_HAS_KILL_SIGNAL /* ESRCH (thread already exited) / EINVAL are both benign here. * Skip if sigaction() failed at install time: delivering an unhandled * SIGRTMIN+3 would terminate the process. */ - if (zend_atomic_bool_load(&kill_signal_handler_active)) { + if (frankenphp_atomic_bool_load(&kill_signal_handler_active)) { pthread_kill(slot.tid, FRANKENPHP_KILL_SIGNAL); } #elif defined(PHP_WIN32) @@ -1736,7 +1736,9 @@ sapi_module_struct frankenphp_sapi_module = { frankenphp_register_variables, /* register server variables */ frankenphp_log_message, /* Log message */ NULL, /* Get request time */ - NULL, /* Child terminate */ +#if PHP_VERSION_ID < 80700 + NULL, /* Child terminate */ +#endif STANDARD_SAPI_MODULE_PROPERTIES}; diff --git a/frankenphp.h b/frankenphp.h index 2ecd5fc3a1..fba2078305 100644 --- a/frankenphp.h +++ b/frankenphp.h @@ -32,9 +32,21 @@ #define FRANKENPHP_KILL_SIGNAL (SIGRTMIN + 3) #endif +#if PHP_VERSION_ID >= 80700 +typedef atomic_bool frankenphp_atomic_bool; +#define frankenphp_atomic_bool_load(obj) atomic_load(obj) +#define frankenphp_atomic_bool_store(obj, desired) atomic_store(obj, desired) +#else +#include +typedef zend_atomic_bool frankenphp_atomic_bool; +#define frankenphp_atomic_bool_load(obj) zend_atomic_bool_load(obj) +#define frankenphp_atomic_bool_store(obj, desired) \ + zend_atomic_bool_store(obj, desired) +#endif + typedef struct { - zend_atomic_bool *vm_interrupt; - zend_atomic_bool *timed_out; + frankenphp_atomic_bool *vm_interrupt; + frankenphp_atomic_bool *timed_out; #ifdef FRANKENPHP_HAS_KILL_SIGNAL pthread_t tid; #elif defined(PHP_WIN32) From 79430e0b141086be7876fbab071296fb9fe760d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 5 Nov 2026 13:28:17 +0100 Subject: [PATCH 2/2] refactor: use C11 atomic_bool for the kill signal handler flag --- frankenphp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frankenphp.c b/frankenphp.c index f5bfd447c3..c79bcf580a 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -288,7 +289,7 @@ static pthread_once_t kill_signal_handler_installed = PTHREAD_ONCE_INIT; * pthread_kill when this is false, so a sigaction failure (invalid * signal number, exhausted handler slots, etc.) can't deliver the * signal with its default action (process termination). */ -static frankenphp_atomic_bool kill_signal_handler_active; +static atomic_bool kill_signal_handler_active; static void install_kill_signal_handler(void) { /* No SA_RESTART so syscalls return EINTR rather than being restarted. * SA_ONSTACK guards against an accidental process-level delivery to a @@ -299,7 +300,7 @@ static void install_kill_signal_handler(void) { sigemptyset(&sa.sa_mask); sa.sa_flags = SA_ONSTACK; if (sigaction(FRANKENPHP_KILL_SIGNAL, &sa, NULL) == 0) { - frankenphp_atomic_bool_store(&kill_signal_handler_active, true); + atomic_store(&kill_signal_handler_active, true); } } #endif @@ -340,7 +341,7 @@ void frankenphp_force_kill_thread(force_kill_slot slot) { /* ESRCH (thread already exited) / EINVAL are both benign here. * Skip if sigaction() failed at install time: delivering an unhandled * SIGRTMIN+3 would terminate the process. */ - if (frankenphp_atomic_bool_load(&kill_signal_handler_active)) { + if (atomic_load(&kill_signal_handler_active)) { pthread_kill(slot.tid, FRANKENPHP_KILL_SIGNAL); } #elif defined(PHP_WIN32)