diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index b5134705b375..52ba347b8486 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -60,6 +60,9 @@ PHP 8.7 INTERNALS UPGRADE NOTES - The ZTS symbols compiler_globals_offset and executor_globals_offset have been removed: CG()/EG() now reach the globals through a __thread struct. - Removed zend_error_noreturn_unchecked(). +- Added the zend_accel_restart_hook callback, which OPcache calls once a + scheduled restart has been carried out, on the thread that carried it out, + with the same reason as the zend_accel_schedule_restart_hook callback. ======================== 2. Build system changes diff --git a/Zend/zend.c b/Zend/zend.c index 3e489d8d3804..e6c58dc2b4c3 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -98,6 +98,7 @@ ZEND_API zend_string *(*zend_resolve_path)(zend_string *filename); ZEND_API zend_result (*zend_post_startup_cb)(void) = NULL; ZEND_API void (*zend_post_shutdown_cb)(void) = NULL; ZEND_API void (*zend_accel_schedule_restart_hook)(int reason) = NULL; +ZEND_API void (*zend_accel_restart_hook)(int reason) = NULL; ZEND_ATTRIBUTE_NONNULL ZEND_API zend_result (*zend_random_bytes)(void *bytes, size_t size, char *errstr, size_t errstr_size) = NULL; ZEND_ATTRIBUTE_NONNULL ZEND_API void (*zend_random_bytes_insecure)(zend_random_bytes_insecure_state *state, void *bytes, size_t size) = NULL; diff --git a/Zend/zend.h b/Zend/zend.h index 2bbf0283991d..29863fba687c 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -384,7 +384,10 @@ extern ZEND_ATTRIBUTE_NONNULL ZEND_API void (*zend_random_bytes_insecure)( extern ZEND_API zend_result (*zend_post_startup_cb)(void); extern ZEND_API void (*zend_post_shutdown_cb)(void); +/* Called by opcache when a restart is scheduled, with a zend_accel_restart_reason */ extern ZEND_API void (*zend_accel_schedule_restart_hook)(int reason); +/* Called by opcache once a scheduled restart has been carried out and the SHM lock is released, with the same reason */ +extern ZEND_API void (*zend_accel_restart_hook)(int reason); ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); ZEND_NORETURN ZEND_API ZEND_COLD void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index a328552cebc3..f221282136dd 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -2974,6 +2974,9 @@ ZEND_RINIT_FUNCTION(zend_accelerator) ZCG(counted) = false; } + bool restarted = false; + zend_accel_restart_reason restart_reason = ACCEL_RESTART_OOM; + if (ZCSG(restart_pending)) { zend_shared_alloc_lock(); if (ZCSG(restart_pending)) { /* check again, to ensure that the cache wasn't already cleaned by another process */ @@ -3019,6 +3022,9 @@ ZEND_RINIT_FUNCTION(zend_accelerator) ZCSG(last_restart_time)++; } accel_restart_leave(); + + restarted = true; + restart_reason = ZCSG(restart_reason); } } zend_shared_alloc_unlock(); @@ -3029,6 +3035,11 @@ ZEND_RINIT_FUNCTION(zend_accelerator) SHM_PROTECT(); HANDLE_UNBLOCK_INTERRUPTIONS(); + /* Called once the SHM lock is released and the memory is protected again */ + if (UNEXPECTED(restarted) && zend_accel_restart_hook) { + zend_accel_restart_hook(restart_reason); + } + if (ZCG(accelerator_enabled) && ZCSG(last_restart_time) != ZCG(last_restart_time)) { /* SHM was reinitialized. */ ZCG(last_restart_time) = ZCSG(last_restart_time);