make it run on 8.2 again

This commit is contained in:
henderkes
2026-03-15 09:35:15 +07:00
parent d88821a8d0
commit 45d49c1a65
5 changed files with 24 additions and 56 deletions

View File

@@ -16,7 +16,6 @@ import (
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddytest"
"github.com/dunglas/frankenphp"
"github.com/dunglas/frankenphp/internal/fastabs"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
@@ -1545,9 +1544,6 @@ func TestDd(t *testing.T) {
// test to force the opcache segfault race condition under concurrency (~1.7s)
func TestOpcacheReset(t *testing.T) {
if frankenphp.Version().VersionID < 80300 {
t.Skip("opcache reset test requires PHP 8.3+")
}
tester := caddytest.NewTester(t)
tester.InitServer(`
{

View File

@@ -87,7 +87,6 @@ __thread uintptr_t thread_index;
__thread bool is_worker_thread = false;
__thread HashTable *sandboxed_env = NULL;
#if PHP_VERSION_ID >= 80300
/* Forward declaration */
PHP_FUNCTION(frankenphp_opcache_reset);
zif_handler orig_opcache_reset;
@@ -107,7 +106,6 @@ static void frankenphp_override_opcache_reset(void) {
ZEND_FN(frankenphp_opcache_reset);
}
}
#endif
void frankenphp_update_local_thread_context(bool is_worker) {
is_worker_thread = is_worker;
@@ -479,14 +477,12 @@ PHP_FUNCTION(frankenphp_getenv) {
}
} /* }}} */
#if PHP_VERSION_ID >= 80300
/* {{{ thread-safe opcache reset */
PHP_FUNCTION(frankenphp_opcache_reset) {
go_schedule_opcache_reset(thread_index);
RETVAL_TRUE;
} /* }}} */
#endif
/* {{{ Fetch all HTTP request headers */
PHP_FUNCTION(frankenphp_request_headers) {
@@ -746,10 +742,9 @@ PHP_MINIT_FUNCTION(frankenphp) {
php_error(E_WARNING, "Failed to find built-in getenv function");
}
#if PHP_VERSION_ID >= 80300
// Override opcache_reset (may not be available yet if opcache loads after us)
// Override opcache_reset (may not be available yet if opcache loads as a
// shared extension in PHP 8.4 and below)
frankenphp_override_opcache_reset();
#endif
return SUCCESS;
}
@@ -770,10 +765,10 @@ static int frankenphp_startup(sapi_module_struct *sapi_module) {
php_import_environment_variables = get_full_env;
int result = php_module_startup(sapi_module, &frankenphp_module);
#if PHP_VERSION_ID >= 80300 && PHP_VERSION_ID < 80500
#if PHP_VERSION_ID < 80500
if (result == SUCCESS) {
/* All extensions are now loaded. Override opcache_reset if opcache
* was not yet available during our MINIT (shared extension load order). */
/* Override opcache here again if loaded as a shared extension
* (php 8.4 and under) */
frankenphp_override_opcache_reset();
}
#endif
@@ -1240,9 +1235,9 @@ bool frankenphp_new_php_thread(uintptr_t thread_index) {
static int frankenphp_request_startup() {
frankenphp_update_request_context();
if (php_request_startup() == SUCCESS) {
#if PHP_VERSION_ID >= 80300 && PHP_VERSION_ID < 80500
/* for php 8.5+ opcache is always compiled statically, so it's already
* hooked in main request startup */
#if PHP_VERSION_ID < 80500
/* Override opcache here again if loaded as a shared extension
* (php 8.4 and under) */
frankenphp_override_opcache_reset();
#endif
return SUCCESS;
@@ -1444,20 +1439,12 @@ int frankenphp_execute_script_cli(char *script, int argc, char **argv,
}
int frankenphp_reset_opcache(void) {
#if PHP_VERSION_ID >= 80300
zend_execute_data execute_data;
zval retval;
memset(&execute_data, 0, sizeof(execute_data));
ZVAL_UNDEF(&retval);
orig_opcache_reset(&execute_data, &retval);
zval_ptr_dtor(&retval);
#else
zend_function *opcache_reset =
zend_hash_str_find_ptr(CG(function_table), ZEND_STRL("opcache_reset"));
if (opcache_reset) {
zend_call_known_function(opcache_reset, NULL, NULL, NULL, 0, NULL, NULL);
}
#endif
return 0;
}

View File

@@ -777,18 +777,15 @@ func restartThreadsAndOpcacheReset(withRegularThreads bool) {
threadsToRestart := drainThreads(withRegularThreads)
// on 8.2 opcache_reset() segfaults, skip it entirely
if Version().VersionID >= 80300 {
opcacheResetOnce = sync.Once{}
opcacheResetWg := sync.WaitGroup{}
for _, thread := range threadsToRestart {
thread.state.Set(state.OpcacheResetting)
opcacheResetWg.Go(func() {
thread.state.WaitFor(state.OpcacheResettingDone)
})
}
opcacheResetWg.Wait()
opcacheResetOnce = sync.Once{}
opcacheResetWg := sync.WaitGroup{}
for _, thread := range threadsToRestart {
thread.state.Set(state.OpcacheResetting)
opcacheResetWg.Go(func() {
thread.state.WaitFor(state.OpcacheResettingDone)
})
}
opcacheResetWg.Wait()
for _, thread := range threadsToRestart {
thread.drainChan = make(chan struct{})

View File

@@ -50,11 +50,9 @@ func (handler *regularThread) beforeScriptExecution() string {
return handler.waitForRequest()
case state.Restarting:
handler.state.Set(state.Yielding)
if Version().VersionID >= 80300 {
handler.state.WaitFor(state.OpcacheResetting)
scheduleOpcacheReset(handler.thread)
handler.state.Set(state.OpcacheResettingDone)
}
handler.state.WaitFor(state.OpcacheResetting)
scheduleOpcacheReset(handler.thread)
handler.state.Set(state.OpcacheResettingDone)
handler.state.WaitFor(state.Ready, state.ShuttingDown)
return handler.beforeScriptExecution()
case state.Ready:

View File

@@ -51,11 +51,9 @@ func (handler *workerThread) beforeScriptExecution() string {
handler.worker.onThreadShutdown(handler.thread.threadIndex)
}
handler.state.Set(state.Yielding)
if Version().VersionID >= 80300 {
handler.state.WaitFor(state.OpcacheResetting)
scheduleOpcacheReset(handler.thread)
handler.state.Set(state.OpcacheResettingDone)
}
handler.state.WaitFor(state.OpcacheResetting)
scheduleOpcacheReset(handler.thread)
handler.state.Set(state.OpcacheResettingDone)
handler.state.WaitFor(state.Ready, state.ShuttingDown)
return handler.beforeScriptExecution()
case state.Ready, state.TransitionComplete:
@@ -75,9 +73,9 @@ func (handler *workerThread) beforeScriptExecution() string {
// signal to stop
return ""
default:
panic("unexpected state: " + handler.state.Name())
}
panic("unexpected state: " + handler.state.Name())
}
func (handler *workerThread) afterScriptExecution(exitStatus int) {
@@ -229,14 +227,6 @@ func (handler *workerThread) waitForWorkerRequest() (bool, any) {
globalLogger.LogAttrs(globalCtx, slog.LevelDebug, "shutting down", slog.String("worker", handler.worker.name), slog.Int("thread", handler.thread.threadIndex))
}
if Version().VersionID < 80300 {
// flush the opcache when restarting due to watcher or admin api
// note: this is done right before frankenphp_handle_request() returns 'false'
if handler.state.Is(state.Restarting) {
C.frankenphp_reset_opcache()
}
}
return false, nil
case requestCH = <-handler.thread.requestChan:
case requestCH = <-handler.worker.requestChan: