From 72f5ab2ddce4fb2604d05beea24275e315b924a4 Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 21 May 2026 18:44:02 +0700 Subject: [PATCH 1/3] clang-format --- frankenphp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frankenphp.c b/frankenphp.c index 3b67fcc0e6..875488c520 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -103,7 +103,8 @@ static __thread frankenphp_server_ctx frankenphp_local_server_ctx; static inline uintptr_t frankenphp_thread_index(void) { frankenphp_server_ctx *ctx = (frankenphp_server_ctx *)SG(server_context); - /* Fall back to the OS thread's own TLS before frankenphp_update_request_context(). */ + /* Fall back to the OS thread's own TLS before + * frankenphp_update_request_context(). */ return ctx != NULL ? ctx->thread_index : thread_index; } @@ -965,8 +966,8 @@ static int frankenphp_send_headers(sapi_headers_struct *sapi_headers) { } } - bool success = - go_write_headers(frankenphp_thread_index(), status, &sapi_headers->headers); + bool success = go_write_headers(frankenphp_thread_index(), status, + &sapi_headers->headers); if (success) { return SAPI_HEADER_SENT_SUCCESSFULLY; } From 810a5e1d4e59efbec31655f46f1970d9263fea60 Mon Sep 17 00:00:00 2001 From: henderkes Date: Thu, 21 May 2026 18:48:52 +0700 Subject: [PATCH 2/3] fix #2339: propagate parent thread_index via SG(server_context) --- frankenphp.c | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/frankenphp.c b/frankenphp.c index e441a4ccd2..875488c520 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -93,6 +93,21 @@ __thread uintptr_t thread_index; __thread bool is_worker_thread = false; __thread HashTable *sandboxed_env = NULL; +/* Published via SG(server_context) so ext-parallel children, which inherit + * the parent's SG(server_context), can route SAPI callbacks back to the + * parent's thread_index instead of their zero-initialized TLS. */ +typedef struct { + uintptr_t thread_index; +} frankenphp_server_ctx; +static __thread frankenphp_server_ctx frankenphp_local_server_ctx; + +static inline uintptr_t frankenphp_thread_index(void) { + frankenphp_server_ctx *ctx = (frankenphp_server_ctx *)SG(server_context); + /* Fall back to the OS thread's own TLS before + * frankenphp_update_request_context(). */ + return ctx != NULL ? ctx->thread_index : thread_index; +} + #ifndef PHP_WIN32 static bool is_forked_child = false; static void frankenphp_fork_child(void) { is_forked_child = true; } @@ -217,7 +232,8 @@ void frankenphp_update_local_thread_context(bool is_worker) { static void frankenphp_update_request_context() { /* the server context is stored on the go side, still SG(server_context) needs * to not be NULL */ - SG(server_context) = (void *)1; + frankenphp_local_server_ctx.thread_index = thread_index; + SG(server_context) = &frankenphp_local_server_ctx; /* status It is not reset by zend engine, set it to 200. */ SG(sapi_headers).http_response_code = 200; @@ -485,14 +501,15 @@ static int frankenphp_worker_request_startup() { PHP_FUNCTION(frankenphp_finish_request) { /* {{{ */ ZEND_PARSE_PARAMETERS_NONE(); - if (go_is_context_done(thread_index)) { + uintptr_t idx = frankenphp_thread_index(); + if (go_is_context_done(idx)) { RETURN_FALSE; } php_output_end_all(); php_header(); - go_frankenphp_finish_php_request(thread_index); + go_frankenphp_finish_php_request(idx); RETURN_TRUE; } /* }}} */ @@ -587,7 +604,7 @@ PHP_FUNCTION(frankenphp_request_headers) { ZEND_PARSE_PARAMETERS_NONE(); struct go_apache_request_headers_return headers = - go_apache_request_headers(thread_index); + go_apache_request_headers(frankenphp_thread_index()); array_init_size(return_value, headers.r1); @@ -786,8 +803,8 @@ PHP_FUNCTION(mercure_publish) { RETURN_THROWS(); } - struct go_mercure_publish_return result = - go_mercure_publish(thread_index, topics, data, private, id, type, retry); + struct go_mercure_publish_return result = go_mercure_publish( + frankenphp_thread_index(), topics, data, private, id, type, retry); switch (result.r1) { case 0: @@ -819,7 +836,7 @@ PHP_FUNCTION(frankenphp_log) { ZEND_PARSE_PARAMETERS_END(); char *ret = NULL; - ret = go_log_attrs(thread_index, message, level, context); + ret = go_log_attrs(frankenphp_thread_index(), message, level, context); if (ret != NULL) { zend_throw_exception(spl_ce_RuntimeException, ret, 0); free(ret); @@ -923,7 +940,7 @@ static int frankenphp_deactivate(void) { return SUCCESS; } static size_t frankenphp_ub_write(const char *str, size_t str_length) { struct go_ub_write_return result = - go_ub_write(thread_index, (char *)str, str_length); + go_ub_write(frankenphp_thread_index(), (char *)str, str_length); if (result.r1) { php_handle_aborted_connection(); @@ -949,7 +966,8 @@ static int frankenphp_send_headers(sapi_headers_struct *sapi_headers) { } } - bool success = go_write_headers(thread_index, status, &sapi_headers->headers); + bool success = go_write_headers(frankenphp_thread_index(), status, + &sapi_headers->headers); if (success) { return SAPI_HEADER_SENT_SUCCESSFULLY; } @@ -959,17 +977,17 @@ static int frankenphp_send_headers(sapi_headers_struct *sapi_headers) { static void frankenphp_sapi_flush(void *server_context) { sapi_send_headers(); - if (go_sapi_flush(thread_index)) { + if (go_sapi_flush(frankenphp_thread_index())) { php_handle_aborted_connection(); } } static size_t frankenphp_read_post(char *buffer, size_t count_bytes) { - return go_read_post(thread_index, buffer, count_bytes); + return go_read_post(frankenphp_thread_index(), buffer, count_bytes); } static char *frankenphp_read_cookies(void) { - return go_read_cookies(thread_index); + return go_read_cookies(frankenphp_thread_index()); } /* all variables with well defined keys can safely be registered like this */ @@ -1145,14 +1163,14 @@ static void frankenphp_register_variables(zval *track_vars_array) { * environment, not values added though putenv */ /* import environment and CGI variables from the request context in go */ - go_register_server_variables(thread_index, track_vars_array); + go_register_server_variables(frankenphp_thread_index(), track_vars_array); /* Some variables are already present in SG(request_info) */ frankenphp_register_variables_from_request_info(track_vars_array); } static void frankenphp_log_message(const char *message, int syslog_type_int) { - go_log(thread_index, (char *)message, syslog_type_int); + go_log(frankenphp_thread_index(), (char *)message, syslog_type_int); } static char *frankenphp_getenv(const char *name, size_t name_len) { From 0f5a05f198cd3de9ed6ac6f510eb3933002d27be Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 22 May 2026 12:45:45 +0700 Subject: [PATCH 3/3] Update frankenphp.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kévin Dunglas Signed-off-by: Marc --- frankenphp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frankenphp.c b/frankenphp.c index 875488c520..5fa9e6ce5b 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -105,7 +105,7 @@ static inline uintptr_t frankenphp_thread_index(void) { frankenphp_server_ctx *ctx = (frankenphp_server_ctx *)SG(server_context); /* Fall back to the OS thread's own TLS before * frankenphp_update_request_context(). */ - return ctx != NULL ? ctx->thread_index : thread_index; + return ctx == NULL ? thread_index : ctx->thread_index; } #ifndef PHP_WIN32