From 33a907061444ca77e395c7f24fa21adb8d2a95ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 12 Dec 2022 23:10:08 +0100 Subject: [PATCH 01/36] fix: support for timeouts with ZTS on Linux --- Zend/zend_execute_API.c | 70 +++++++++++++++++++++++++++++++++++++++++ Zend/zend_globals.h | 7 +++++ configure.ac | 3 ++ 3 files changed, 80 insertions(+) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 3ef2dec1036c2..324ea7bc94833 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -43,6 +43,14 @@ #ifdef HAVE_UNISTD_H #include #endif +#if defined(ZTS) && defined(HAVE_TIMER_CREATE) +#include +// Musl Libc defines this macro, glibc does not +// According to "man 2 timer_create" this field should always be available, but it's not +# ifndef sigev_notify_thread_id +# define sigev_notify_thread_id _sigev_un._tid +# endif +#endif ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data); ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value); @@ -171,6 +179,20 @@ void init_executor(void) /* {{{ */ EG(vm_interrupt) = 0; EG(timed_out) = 0; +#if defined(ZTS) && defined(HAVE_TIMER_CREATE) + struct sigevent sev; + sev.sigev_notify = SIGEV_THREAD_ID; + sev.sigev_value.sival_ptr = &EG(timer); + sev.sigev_signo = SIGIO; + sev.sigev_notify_thread_id = gettid(); + + if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) + fprintf(stderr, "error %d while creating timer on thread %d\n", errno, gettid()); +# ifdef TIMER_DEBUG + else fprintf(stderr, "timer created on thread %d\n", gettid()); +# endif +#endif + EG(exception) = NULL; EG(prev_exception) = NULL; @@ -396,6 +418,14 @@ void shutdown_executor(void) /* {{{ */ bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup); #endif +#if defined(ZTS) && defined(HAVE_TIMER_CREATE) + if (timer_delete(EG(timer)) != 0) + fprintf(stderr, "error %d while deleting timer on thread %d\n", errno, gettid()); +# ifdef TIMER_DEBUG + else fprintf(stderr, "timer deleted on thread %d\n", gettid()); +# endif +#endif + zend_try { zend_stream_shutdown(); } zend_end_try(); @@ -1314,8 +1344,18 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */ /* }}} */ #ifndef ZEND_WIN32 +#if defined(ZTS) && defined(HAVE_TIMER_CREATE) +static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ +{ + if (si->si_value.sival_ptr != &EG(timer)) { + fprintf(stderr, "ignoring timeout signal SIGIO received on thread %d\n", gettid()); + + return; + } +#else static void zend_timeout_handler(int dummy) /* {{{ */ { +#endif #ifndef ZTS if (EG(timed_out)) { /* Die on hard timeout */ @@ -1415,6 +1455,36 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ zend_error_noreturn(E_ERROR, "Could not queue new timer"); return; } +#elif defined(ZTS) && defined(HAVE_TIMER_CREATE) + timer_t timer = EG(timer); + struct itimerspec its; + + its.it_value.tv_sec = seconds; + its.it_value.tv_nsec = 0; + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + + if (timer_settime(timer, 0, &its, NULL) != 0) { + fprintf(stderr, "unable to set timer on thread %d\n", gettid()); + + return; + } +# ifdef TIMER_DEBUG + else fprintf(stderr, "timer set on thread %d (%ld seconds)\n", gettid(), seconds); +# endif + + if (reset_signals) { + sigset_t sigset; + struct sigaction act; + + act.sa_sigaction = zend_timeout_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_ONSTACK | SA_SIGINFO; + sigaction(SIGIO, &act, NULL); + sigemptyset(&sigset); + sigaddset(&sigset, SIGIO); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + } #elif defined(HAVE_SETITIMER) { struct itimerval t_r; /* timeout requested */ diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 1726dee9ac12a..c1ab9390667c6 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -22,6 +22,9 @@ #include +#if defined(ZTS) && defined(HAVE_TIMER_CREATE) +#include +#endif #include "zend_globals_macros.h" @@ -266,6 +269,10 @@ struct _zend_executor_globals { uint32_t num_errors; zend_error_info **errors; +#if defined(ZTS) && defined(HAVE_TIMER_CREATE) + timer_t timer; +#endif + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; diff --git a/configure.ac b/configure.ac index 9aa8c5caf2e2d..ee38b260cf208 100644 --- a/configure.ac +++ b/configure.ac @@ -743,6 +743,9 @@ fi dnl Check for openpty. It may require linking against libutil or libbsd. PHP_CHECK_FUNC(openpty, util, bsd) +dnl Check for timer_create +PHP_CHECK_FUNC(timer_create, rt) + dnl General settings. dnl ---------------------------------------------------------------------------- PHP_CONFIGURE_PART(General settings) From 4cf916d4b6f2374407d6f8f22be9d6fd1071e27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 20 Dec 2022 19:40:10 +0100 Subject: [PATCH 02/36] add gettid macro for old glibc --- Zend/zend_execute_API.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 324ea7bc94833..8e5ebfcaea4ce 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -50,6 +50,11 @@ # ifndef sigev_notify_thread_id # define sigev_notify_thread_id _sigev_un._tid # endif +// Old versions of glibc miss gettid() +# if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30 +# include +# define gettid() syscall(SYS_gettid) +# endif #endif ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data); From 6cc4cdc099c6114323c662bf1fc09e2dff5b7b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 20 Dec 2022 20:30:07 +0100 Subject: [PATCH 03/36] use the syscall instead of gettid() --- Zend/zend_execute_API.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 8e5ebfcaea4ce..fa77c1c00144e 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -45,16 +45,12 @@ #endif #if defined(ZTS) && defined(HAVE_TIMER_CREATE) #include +#include // Musl Libc defines this macro, glibc does not // According to "man 2 timer_create" this field should always be available, but it's not # ifndef sigev_notify_thread_id # define sigev_notify_thread_id _sigev_un._tid # endif -// Old versions of glibc miss gettid() -# if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30 -# include -# define gettid() syscall(SYS_gettid) -# endif #endif ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data); @@ -189,12 +185,12 @@ void init_executor(void) /* {{{ */ sev.sigev_notify = SIGEV_THREAD_ID; sev.sigev_value.sival_ptr = &EG(timer); sev.sigev_signo = SIGIO; - sev.sigev_notify_thread_id = gettid(); + sev.sigev_notify_thread_id = syscall(SYS_gettid); if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) - fprintf(stderr, "error %d while creating timer on thread %d\n", errno, gettid()); + fprintf(stderr, "error %d while creating timer on thread %d\n", errno, syscall(SYS_gettid)); # ifdef TIMER_DEBUG - else fprintf(stderr, "timer created on thread %d\n", gettid()); + else fprintf(stderr, "timer created on thread %d\n", syscall(SYS_gettid)); # endif #endif @@ -425,9 +421,9 @@ void shutdown_executor(void) /* {{{ */ #if defined(ZTS) && defined(HAVE_TIMER_CREATE) if (timer_delete(EG(timer)) != 0) - fprintf(stderr, "error %d while deleting timer on thread %d\n", errno, gettid()); + fprintf(stderr, "error %d while deleting timer on thread %d\n", errno, syscall(SYS_gettid)); # ifdef TIMER_DEBUG - else fprintf(stderr, "timer deleted on thread %d\n", gettid()); + else fprintf(stderr, "timer deleted on thread %d\n", syscall(SYS_gettid)); # endif #endif @@ -1353,7 +1349,7 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */ static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ { if (si->si_value.sival_ptr != &EG(timer)) { - fprintf(stderr, "ignoring timeout signal SIGIO received on thread %d\n", gettid()); + fprintf(stderr, "ignoring timeout signal SIGIO received on thread %d\n", syscall(SYS_gettid)); return; } @@ -1470,12 +1466,12 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ its.it_interval.tv_nsec = 0; if (timer_settime(timer, 0, &its, NULL) != 0) { - fprintf(stderr, "unable to set timer on thread %d\n", gettid()); + fprintf(stderr, "unable to set timer on thread %d\n", syscall(SYS_gettid)); return; } # ifdef TIMER_DEBUG - else fprintf(stderr, "timer set on thread %d (%ld seconds)\n", gettid(), seconds); + else fprintf(stderr, "timer set on thread %d (%ld seconds)\n", syscall(SYS_gettid), seconds); # endif if (reset_signals) { From 590e011b2f706f5b098a355a3ede6a85226f4911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 20 Dec 2022 20:31:41 +0100 Subject: [PATCH 04/36] indentation --- Zend/zend_execute_API.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index fa77c1c00144e..9f265fa78ea20 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1345,7 +1345,7 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */ /* }}} */ #ifndef ZEND_WIN32 -#if defined(ZTS) && defined(HAVE_TIMER_CREATE) +# if defined(ZTS) && defined(HAVE_TIMER_CREATE) static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ { if (si->si_value.sival_ptr != &EG(timer)) { @@ -1353,10 +1353,10 @@ static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ return; } -#else +# else static void zend_timeout_handler(int dummy) /* {{{ */ { -#endif +# endif #ifndef ZTS if (EG(timed_out)) { /* Die on hard timeout */ From d1eef55686899ebb870641a900a80d7e6941041d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 20 Dec 2022 20:52:08 +0100 Subject: [PATCH 05/36] fix cast --- Zend/zend_execute_API.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 9f265fa78ea20..67cb53d650262 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -46,6 +46,7 @@ #if defined(ZTS) && defined(HAVE_TIMER_CREATE) #include #include +#include // Musl Libc defines this macro, glibc does not // According to "man 2 timer_create" this field should always be available, but it's not # ifndef sigev_notify_thread_id @@ -185,10 +186,10 @@ void init_executor(void) /* {{{ */ sev.sigev_notify = SIGEV_THREAD_ID; sev.sigev_value.sival_ptr = &EG(timer); sev.sigev_signo = SIGIO; - sev.sigev_notify_thread_id = syscall(SYS_gettid); + sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) - fprintf(stderr, "error %d while creating timer on thread %d\n", errno, syscall(SYS_gettid)); + fprintf(stderr, "error %d while creating timer on thread %d\n", errno, (pid_t) syscall(SYS_gettid)); # ifdef TIMER_DEBUG else fprintf(stderr, "timer created on thread %d\n", syscall(SYS_gettid)); # endif @@ -421,9 +422,9 @@ void shutdown_executor(void) /* {{{ */ #if defined(ZTS) && defined(HAVE_TIMER_CREATE) if (timer_delete(EG(timer)) != 0) - fprintf(stderr, "error %d while deleting timer on thread %d\n", errno, syscall(SYS_gettid)); + fprintf(stderr, "error %d while deleting timer on thread %d\n", errno, (pid_t) syscall(SYS_gettid)); # ifdef TIMER_DEBUG - else fprintf(stderr, "timer deleted on thread %d\n", syscall(SYS_gettid)); + else fprintf(stderr, "timer deleted on thread %d\n", (pid_t) syscall(SYS_gettid)); # endif #endif @@ -1349,7 +1350,7 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */ static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ { if (si->si_value.sival_ptr != &EG(timer)) { - fprintf(stderr, "ignoring timeout signal SIGIO received on thread %d\n", syscall(SYS_gettid)); + fprintf(stderr, "ignoring timeout signal SIGIO received on thread %d\n", (pid_t) syscall(SYS_gettid)); return; } @@ -1466,12 +1467,12 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ its.it_interval.tv_nsec = 0; if (timer_settime(timer, 0, &its, NULL) != 0) { - fprintf(stderr, "unable to set timer on thread %d\n", syscall(SYS_gettid)); + fprintf(stderr, "unable to set timer on thread %d\n", (pid_t) syscall(SYS_gettid)); return; } # ifdef TIMER_DEBUG - else fprintf(stderr, "timer set on thread %d (%ld seconds)\n", syscall(SYS_gettid), seconds); + else fprintf(stderr, "timer set on thread %d (%ld seconds)\n", (pid_t) syscall(SYS_gettid), seconds); # endif if (reset_signals) { From b5277f0195e1f858f68a8accbba7c2ef46b0904e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 20 Dec 2022 23:11:38 +0100 Subject: [PATCH 06/36] hide debug info by default --- Zend/zend_execute_API.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 67cb53d650262..d0f79ebc117dc 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -188,10 +188,13 @@ void init_executor(void) /* {{{ */ sev.sigev_signo = SIGIO; sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); - if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) - fprintf(stderr, "error %d while creating timer on thread %d\n", errno, (pid_t) syscall(SYS_gettid)); + if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) { # ifdef TIMER_DEBUG - else fprintf(stderr, "timer created on thread %d\n", syscall(SYS_gettid)); + fprintf(stderr, "error %d while creating timer %#jx on thread %d\n", errno, (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); +# endif + } +# ifdef TIMER_DEBUG + else fprintf(stderr, "timer %#jx created on thread %d\n", (uintmax_t) EG(timer), syscall(SYS_gettid)); # endif #endif @@ -421,10 +424,13 @@ void shutdown_executor(void) /* {{{ */ #endif #if defined(ZTS) && defined(HAVE_TIMER_CREATE) - if (timer_delete(EG(timer)) != 0) - fprintf(stderr, "error %d while deleting timer on thread %d\n", errno, (pid_t) syscall(SYS_gettid)); + if (timer_delete(EG(timer)) != 0) { +# ifdef TIMER_DEBUG + fprintf(stderr, "error %d while deleting timer %#jx on thread %d\n", errno, (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); +# endif + } # ifdef TIMER_DEBUG - else fprintf(stderr, "timer deleted on thread %d\n", (pid_t) syscall(SYS_gettid)); + else fprintf(stderr, "timer %#jx deleted on thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); # endif #endif @@ -1350,7 +1356,9 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */ static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ { if (si->si_value.sival_ptr != &EG(timer)) { +#ifdef TIMER_DEBUG fprintf(stderr, "ignoring timeout signal SIGIO received on thread %d\n", (pid_t) syscall(SYS_gettid)); +#endif return; } @@ -1467,12 +1475,14 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ its.it_interval.tv_nsec = 0; if (timer_settime(timer, 0, &its, NULL) != 0) { - fprintf(stderr, "unable to set timer on thread %d\n", (pid_t) syscall(SYS_gettid)); +#ifdef TIMER_DEBUG + fprintf(stderr, "unable to set timer %#jx on thread %d\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); +#endif return; } # ifdef TIMER_DEBUG - else fprintf(stderr, "timer set on thread %d (%ld seconds)\n", (pid_t) syscall(SYS_gettid), seconds); + else fprintf(stderr, "timer %#jx set on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); # endif if (reset_signals) { From cfd0a6ece164c427b65f0d6fa13fff0bc61fc829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 26 Dec 2022 16:50:55 +0100 Subject: [PATCH 07/36] create only one timer per thread --- Zend/zend.c | 66 +++++++++++++++++++++++++++++- Zend/zend.h | 3 ++ Zend/zend_execute_API.c | 90 ++++++++++++----------------------------- Zend/zend_globals.h | 4 +- Zend/zend_timer.h | 18 +++++++++ 5 files changed, 114 insertions(+), 67 deletions(-) create mode 100644 Zend/zend_timer.h diff --git a/Zend/zend.c b/Zend/zend.c index be7fa210fff70..f26bc5875c3dd 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -35,6 +35,7 @@ #include "zend_attributes.h" #include "zend_observer.h" #include "zend_fibers.h" +#include "zend_timer.h" #include "Optimizer/zend_optimizer.h" static size_t global_map_ptr_last = 0; @@ -817,10 +818,60 @@ static void executor_globals_dtor(zend_executor_globals *executor_globals) /* {{ } /* }}} */ +# ifdef ZEND_TIMER +static void zend_timer_create() /* {{{ */ +{ + struct sigevent sev; + sev.sigev_notify = SIGEV_THREAD_ID; + sev.sigev_value.sival_ptr = &EG(timer); + // The chosen signal must: + // 1. not be used internally by libc + // 2. be allowed to happen spuriously without consequences + // 3. not be commonly used by applications, this excludes SIGALRM, SIGUSR1 and SIGUSR2 + // 4. not be used by profilers, this excludes SIGPROF + // 5. not be used internally by runtimes of programs that can embed PHP, this excludes SIGURG, which is used by Go + sev.sigev_signo = SIGIO; + sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); + + int errn = timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)); + if (errn != 0) { + EG(timer) = 0; + + zend_strerror_noreturn(E_ERROR, errn, "Could not create timer"); + } + +# ifdef TIMER_DEBUG + fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id); +# endif +} +/* }}} */ +# endif + static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ { zend_copy_ini_directives(); zend_ini_refresh_caches(ZEND_INI_STAGE_STARTUP); +#ifdef ZEND_TIMER + zend_timer_create(); +#endif +} +/* }}} */ + +static void zend_thread_shutdown_handler(void) { /* {{{ */ + zend_interned_strings_dtor(); + +# ifdef ZEND_TIMER + timer_t timer = EG(timer); + + if (timer == 0) return; + + int errn = timer_delete(EG(timer)); + if (errn != 0) zend_strerror_noreturn(E_ERROR, errn, "Could not delete timer"); + +# ifdef TIMER_DEBUG + fprintf(stderr, "Timer %#jx deleted on thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); +# endif +# endif } /* }}} */ #endif @@ -1026,7 +1077,7 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ #ifdef ZTS tsrm_set_new_thread_end_handler(zend_new_thread_end_handler); - tsrm_set_shutdown_handler(zend_interned_strings_dtor); + tsrm_set_shutdown_handler(zend_thread_shutdown_handler); #endif } /* }}} */ @@ -1092,6 +1143,10 @@ zend_result zend_post_startup(void) /* {{{ */ executor_globals_ctor(executor_globals); global_persistent_list = &EG(persistent_list); zend_copy_ini_directives(); + +# ifdef ZEND_TIMER + zend_timer_create(); +# endif #else global_map_ptr_last = CG(map_ptr_last); #endif @@ -1612,6 +1667,15 @@ ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char * abort(); } +ZEND_API ZEND_COLD void zend_strerror_noreturn(int type, int errn, const char *message) +{ + char buf[1024]; + if (!strerror_r(errn, buf, sizeof(buf))) + zend_error_noreturn(type, "%s: %d", message, errn); + + zend_error_noreturn(type, "%s: %s (%d)", message, buf, errn); +} + ZEND_API ZEND_COLD void zend_error_zstr(int type, zend_string *message) { zend_string *filename; uint32_t lineno; diff --git a/Zend/zend.h b/Zend/zend.h index 18e605c5bc27a..f06eea644057d 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -353,6 +353,9 @@ ZEND_API ZEND_COLD void zend_value_error(const char *format, ...) ZEND_ATTRIBUTE ZEND_COLD void zenderror(const char *error); +/* For internal C errors */ +ZEND_API ZEND_COLD void zend_strerror_noreturn(int type, int errn, const char *message); + /* The following #define is used for code duality in PHP for Engine 1 & 2 */ #define ZEND_STANDARD_CLASS_DEF_PTR zend_standard_class_def extern ZEND_API zend_class_entry *zend_standard_class_def; diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index d0f79ebc117dc..d33002ebe546d 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -37,22 +37,7 @@ #include "zend_weakrefs.h" #include "zend_inheritance.h" #include "zend_observer.h" -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#if defined(ZTS) && defined(HAVE_TIMER_CREATE) -#include -#include -#include -// Musl Libc defines this macro, glibc does not -// According to "man 2 timer_create" this field should always be available, but it's not -# ifndef sigev_notify_thread_id -# define sigev_notify_thread_id _sigev_un._tid -# endif -#endif +#include "zend_timer.h" ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data); ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value); @@ -181,23 +166,6 @@ void init_executor(void) /* {{{ */ EG(vm_interrupt) = 0; EG(timed_out) = 0; -#if defined(ZTS) && defined(HAVE_TIMER_CREATE) - struct sigevent sev; - sev.sigev_notify = SIGEV_THREAD_ID; - sev.sigev_value.sival_ptr = &EG(timer); - sev.sigev_signo = SIGIO; - sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); - - if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) { -# ifdef TIMER_DEBUG - fprintf(stderr, "error %d while creating timer %#jx on thread %d\n", errno, (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); -# endif - } -# ifdef TIMER_DEBUG - else fprintf(stderr, "timer %#jx created on thread %d\n", (uintmax_t) EG(timer), syscall(SYS_gettid)); -# endif -#endif - EG(exception) = NULL; EG(prev_exception) = NULL; @@ -413,6 +381,26 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown) zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); } +#ifdef ZEND_TIMER +static void zend_timer_settime(zend_long seconds) /* {{{ }*/ +{ + timer_t timer = EG(timer); + if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created"); + + struct itimerspec its; + its.it_value.tv_sec = seconds; + its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; + + int errn = timer_settime(timer, 0, &its, NULL); + if (errn != 0) zend_strerror_noreturn(E_ERROR, errn, "Could not set timer"); + +# ifdef TIMER_DEBUG + fprintf(stderr, "Timer %#jx set on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); +# endif +} +/* }}} */ +#endif + void shutdown_executor(void) /* {{{ */ { zend_string *key; @@ -423,17 +411,6 @@ void shutdown_executor(void) /* {{{ */ bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup); #endif -#if defined(ZTS) && defined(HAVE_TIMER_CREATE) - if (timer_delete(EG(timer)) != 0) { -# ifdef TIMER_DEBUG - fprintf(stderr, "error %d while deleting timer %#jx on thread %d\n", errno, (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); -# endif - } -# ifdef TIMER_DEBUG - else fprintf(stderr, "timer %#jx deleted on thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); -# endif -#endif - zend_try { zend_stream_shutdown(); } zend_end_try(); @@ -1352,7 +1329,7 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */ /* }}} */ #ifndef ZEND_WIN32 -# if defined(ZTS) && defined(HAVE_TIMER_CREATE) +# ifdef ZEND_TIMER static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ { if (si->si_value.sival_ptr != &EG(timer)) { @@ -1465,25 +1442,8 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ zend_error_noreturn(E_ERROR, "Could not queue new timer"); return; } -#elif defined(ZTS) && defined(HAVE_TIMER_CREATE) - timer_t timer = EG(timer); - struct itimerspec its; - - its.it_value.tv_sec = seconds; - its.it_value.tv_nsec = 0; - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 0; - - if (timer_settime(timer, 0, &its, NULL) != 0) { -#ifdef TIMER_DEBUG - fprintf(stderr, "unable to set timer %#jx on thread %d\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); -#endif - - return; - } -# ifdef TIMER_DEBUG - else fprintf(stderr, "timer %#jx set on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); -# endif +#elif defined(ZEND_TIMER) + zend_timer_settime(seconds); if (reset_signals) { sigset_t sigset; @@ -1562,6 +1522,8 @@ void zend_unset_timeout(void) /* {{{ */ } tq_timer = NULL; } +#elif ZEND_TIMER + zend_timer_settime(0); #elif defined(HAVE_SETITIMER) if (EG(timeout_seconds)) { struct itimerval no_timeout; diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index c1ab9390667c6..c8f08a144573f 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -22,7 +22,7 @@ #include -#if defined(ZTS) && defined(HAVE_TIMER_CREATE) +#ifdef ZEND_TIMER #include #endif @@ -269,7 +269,7 @@ struct _zend_executor_globals { uint32_t num_errors; zend_error_info **errors; -#if defined(ZTS) && defined(HAVE_TIMER_CREATE) +#ifndef ZEND_TIMER timer_t timer; #endif diff --git a/Zend/zend_timer.h b/Zend/zend_timer.h new file mode 100644 index 0000000000000..4097c44cda7a5 --- /dev/null +++ b/Zend/zend_timer.h @@ -0,0 +1,18 @@ +#if !defined(ZEND_TIMER_H) && defined(ZTS) && defined(__linux__) && defined(HAVE_TIMER_CREATE) +#define ZEND_TIMER_H + +#define ZEND_TIMER 1 + +#include +#include +#include +#include +#include + +// Musl Libc defines this macro, glibc does not +// According to "man 2 timer_create" this field should always be available, but it's not: https://sourceware.org/bugzilla/show_bug.cgi?id=27417 +# ifndef sigev_notify_thread_id +# define sigev_notify_thread_id _sigev_un._tid +# endif + +#endif From 215e097abad65da9c56ff1739ab4345c51fb9a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 26 Dec 2022 21:57:31 +0100 Subject: [PATCH 08/36] call previous signal handler --- Zend/zend.c | 2 ++ Zend/zend_execute_API.c | 9 ++++++++- Zend/zend_globals.h | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Zend/zend.c b/Zend/zend.c index f26bc5875c3dd..ab57eba2eb5ad 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -843,6 +843,8 @@ static void zend_timer_create() /* {{{ */ # ifdef TIMER_DEBUG fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id); # endif + + sigaction(sev.sigev_signo, NULL, &EG(oldact)); } /* }}} */ # endif diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index d33002ebe546d..079a2ab472270 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1334,9 +1334,16 @@ static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ { if (si->si_value.sival_ptr != &EG(timer)) { #ifdef TIMER_DEBUG - fprintf(stderr, "ignoring timeout signal SIGIO received on thread %d\n", (pid_t) syscall(SYS_gettid)); + fprintf(stderr, "Executing previous handler (if set) for unexpected signal SIGIO received on thread %d\n", (pid_t) syscall(SYS_gettid)); #endif + if (EG(oldact).sa_sigaction) { + EG(oldact).sa_sigaction(dummy, si, uc); + + return; + } + if (EG(oldact).sa_handler) EG(oldact).sa_handler(dummy); + return; } # else diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index c8f08a144573f..7b129063a6f66 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -24,6 +24,7 @@ #include #ifdef ZEND_TIMER #include +#include #endif #include "zend_globals_macros.h" @@ -271,6 +272,7 @@ struct _zend_executor_globals { #ifndef ZEND_TIMER timer_t timer; + struct sigaction oldact; #endif void *reserved[ZEND_MAX_RESERVED_RESOURCES]; From 16831770ea1d766c7ec61ad91074f46d4883f1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 26 Dec 2022 22:09:45 +0100 Subject: [PATCH 09/36] fix --- Zend/zend_execute_API.c | 6 ++++++ Zend/zend_globals.h | 7 ++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 079a2ab472270..8fbee612e6cb3 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -38,6 +38,12 @@ #include "zend_inheritance.h" #include "zend_observer.h" #include "zend_timer.h" +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data); ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 7b129063a6f66..a7ec8c1983ba5 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -22,10 +22,6 @@ #include -#ifdef ZEND_TIMER -#include -#include -#endif #include "zend_globals_macros.h" @@ -40,6 +36,7 @@ #include "zend_multibyte.h" #include "zend_multiply.h" #include "zend_arena.h" +#include "zend_timer.h" /* Define ZTS if you want a thread-safe Zend */ /*#undef ZTS*/ @@ -270,7 +267,7 @@ struct _zend_executor_globals { uint32_t num_errors; zend_error_info **errors; -#ifndef ZEND_TIMER +#ifdef ZEND_TIMER timer_t timer; struct sigaction oldact; #endif From ba39b4315875be672fd790af180054d8d5aa527e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 26 Dec 2022 23:00:57 +0100 Subject: [PATCH 10/36] better error handling --- Zend/zend.c | 13 ++++++------- Zend/zend_execute_API.c | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index ab57eba2eb5ad..152fccf3bc12a 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -833,11 +833,9 @@ static void zend_timer_create() /* {{{ */ sev.sigev_signo = SIGIO; sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); - int errn = timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)); - if (errn != 0) { + if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) { EG(timer) = 0; - - zend_strerror_noreturn(E_ERROR, errn, "Could not create timer"); + zend_strerror_noreturn(E_ERROR, errno, "Could not create timer"); } # ifdef TIMER_DEBUG @@ -865,10 +863,11 @@ static void zend_thread_shutdown_handler(void) { /* {{{ */ # ifdef ZEND_TIMER timer_t timer = EG(timer); - if (timer == 0) return; + if (timer == 0) + zend_error_noreturn(E_ERROR, "Could not c timer"); - int errn = timer_delete(EG(timer)); - if (errn != 0) zend_strerror_noreturn(E_ERROR, errn, "Could not delete timer"); + if (timer_delete(timer) != 0) + zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer"); # ifdef TIMER_DEBUG fprintf(stderr, "Timer %#jx deleted on thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 8fbee612e6cb3..c346447ac6132 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -397,8 +397,8 @@ static void zend_timer_settime(zend_long seconds) /* {{{ }*/ its.it_value.tv_sec = seconds; its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; - int errn = timer_settime(timer, 0, &its, NULL); - if (errn != 0) zend_strerror_noreturn(E_ERROR, errn, "Could not set timer"); + if (timer_settime(timer, 0, &its, NULL) != 0) + zend_strerror_noreturn(E_ERROR, errno, "Could not set timer"); # ifdef TIMER_DEBUG fprintf(stderr, "Timer %#jx set on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); From e44dd060ce3dd70911a7a583f2785ec964215379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 26 Dec 2022 23:30:38 +0100 Subject: [PATCH 11/36] fix error message generation --- Zend/zend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend.c b/Zend/zend.c index 152fccf3bc12a..e0eede6eae62d 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1671,7 +1671,7 @@ ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char * ZEND_API ZEND_COLD void zend_strerror_noreturn(int type, int errn, const char *message) { char buf[1024]; - if (!strerror_r(errn, buf, sizeof(buf))) + if (strerror_r(errn, buf, sizeof(buf)) != 0) zend_error_noreturn(type, "%s: %d", message, errn); zend_error_noreturn(type, "%s: %s (%d)", message, buf, errn); From 82b923fb58106cd4773ddb56a9d98cc068406542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 26 Dec 2022 23:38:33 +0100 Subject: [PATCH 12/36] more debug details --- Zend/zend.c | 20 ++++++++++++-------- Zend/zend_execute_API.c | 9 +++++---- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index e0eede6eae62d..6456b87324931 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -821,6 +821,10 @@ static void executor_globals_dtor(zend_executor_globals *executor_globals) /* {{ # ifdef ZEND_TIMER static void zend_timer_create() /* {{{ */ { +# ifdef TIMER_DEBUG + fprintf(stderr, "Trying to create timer on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id); +# endif + struct sigevent sev; sev.sigev_notify = SIGEV_THREAD_ID; sev.sigev_value.sival_ptr = &EG(timer); @@ -861,17 +865,17 @@ static void zend_thread_shutdown_handler(void) { /* {{{ */ zend_interned_strings_dtor(); # ifdef ZEND_TIMER - timer_t timer = EG(timer); +# ifdef TIMER_DEBUG + fprintf(stderr, "Trying to delete timer %#jx thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); +# endif - if (timer == 0) - zend_error_noreturn(E_ERROR, "Could not c timer"); + timer_t timer = EG(timer); + if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created"); - if (timer_delete(timer) != 0) + int err = timer_delete(timer); + EG(timer) = 0; + if (err != 0) zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer"); - -# ifdef TIMER_DEBUG - fprintf(stderr, "Timer %#jx deleted on thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); -# endif # endif } /* }}} */ diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index c346447ac6132..5d69b6e6d88c8 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -391,6 +391,11 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown) static void zend_timer_settime(zend_long seconds) /* {{{ }*/ { timer_t timer = EG(timer); + +# ifdef TIMER_DEBUG + fprintf(stderr, "Trying to set timer %#jx on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); +# endif + if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created"); struct itimerspec its; @@ -399,10 +404,6 @@ static void zend_timer_settime(zend_long seconds) /* {{{ }*/ if (timer_settime(timer, 0, &its, NULL) != 0) zend_strerror_noreturn(E_ERROR, errno, "Could not set timer"); - -# ifdef TIMER_DEBUG - fprintf(stderr, "Timer %#jx set on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); -# endif } /* }}} */ #endif From da6511e7317e0f7470b5ffccb19f049a7113a2eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 27 Dec 2022 09:23:20 +0100 Subject: [PATCH 13/36] refactor, fix pcntl_fork() --- Zend/zend.c | 50 ++----------------- Zend/zend.h | 1 + Zend/zend_execute_API.c | 25 ++-------- Zend/zend_timer.c | 104 ++++++++++++++++++++++++++++++++++++++++ Zend/zend_timer.h | 38 ++++++++++----- configure.ac | 2 +- ext/pcntl/pcntl.c | 6 +++ 7 files changed, 145 insertions(+), 81 deletions(-) create mode 100644 Zend/zend_timer.c diff --git a/Zend/zend.c b/Zend/zend.c index 6456b87324931..b45b624ba5e09 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -818,39 +818,6 @@ static void executor_globals_dtor(zend_executor_globals *executor_globals) /* {{ } /* }}} */ -# ifdef ZEND_TIMER -static void zend_timer_create() /* {{{ */ -{ -# ifdef TIMER_DEBUG - fprintf(stderr, "Trying to create timer on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id); -# endif - - struct sigevent sev; - sev.sigev_notify = SIGEV_THREAD_ID; - sev.sigev_value.sival_ptr = &EG(timer); - // The chosen signal must: - // 1. not be used internally by libc - // 2. be allowed to happen spuriously without consequences - // 3. not be commonly used by applications, this excludes SIGALRM, SIGUSR1 and SIGUSR2 - // 4. not be used by profilers, this excludes SIGPROF - // 5. not be used internally by runtimes of programs that can embed PHP, this excludes SIGURG, which is used by Go - sev.sigev_signo = SIGIO; - sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); - - if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) { - EG(timer) = 0; - zend_strerror_noreturn(E_ERROR, errno, "Could not create timer"); - } - -# ifdef TIMER_DEBUG - fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id); -# endif - - sigaction(sev.sigev_signo, NULL, &EG(oldact)); -} -/* }}} */ -# endif - static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ { zend_copy_ini_directives(); @@ -863,20 +830,9 @@ static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ static void zend_thread_shutdown_handler(void) { /* {{{ */ zend_interned_strings_dtor(); - -# ifdef ZEND_TIMER -# ifdef TIMER_DEBUG - fprintf(stderr, "Trying to delete timer %#jx thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); -# endif - - timer_t timer = EG(timer); - if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created"); - - int err = timer_delete(timer); - EG(timer) = 0; - if (err != 0) - zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer"); -# endif +#ifdef ZEND_TIMER + zend_timer_delete(); +#endif } /* }}} */ #endif diff --git a/Zend/zend.h b/Zend/zend.h index f06eea644057d..505bf4ef63da5 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -39,6 +39,7 @@ #include "zend_smart_str_public.h" #include "zend_smart_string_public.h" #include "zend_signal.h" +#include "zend_timer.h" #define zend_sprintf sprintf diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 5d69b6e6d88c8..b70ad7e808ca0 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -37,13 +37,15 @@ #include "zend_weakrefs.h" #include "zend_inheritance.h" #include "zend_observer.h" -#include "zend_timer.h" #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_UNISTD_H #include #endif +#ifdef ZEND_TIMER +#include +#endif ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data); ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value); @@ -387,27 +389,6 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown) zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); } -#ifdef ZEND_TIMER -static void zend_timer_settime(zend_long seconds) /* {{{ }*/ -{ - timer_t timer = EG(timer); - -# ifdef TIMER_DEBUG - fprintf(stderr, "Trying to set timer %#jx on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); -# endif - - if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created"); - - struct itimerspec its; - its.it_value.tv_sec = seconds; - its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; - - if (timer_settime(timer, 0, &its, NULL) != 0) - zend_strerror_noreturn(E_ERROR, errno, "Could not set timer"); -} -/* }}} */ -#endif - void shutdown_executor(void) /* {{{ */ { zend_string *key; diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c new file mode 100644 index 0000000000000..d7a716f5d20d7 --- /dev/null +++ b/Zend/zend_timer.c @@ -0,0 +1,104 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Kévin Dunglas | + +----------------------------------------------------------------------+ + */ + +#include "zend_timer.h" + +#ifdef ZEND_TIMER + +#include +#include +#include +#include +#include +#include +#include + +#include "zend.h" +#include "zend_globals.h" + +// Musl Libc defines this macro, glibc does not +// According to "man 2 timer_create" this field should always be available, but it's not: https://sourceware.org/bugzilla/show_bug.cgi?id=27417 +# ifndef sigev_notify_thread_id +# define sigev_notify_thread_id _sigev_un._tid +# endif + +ZEND_API void zend_timer_create(void) /* {{{ */ +{ +# ifdef TIMER_DEBUG + fprintf(stderr, "Trying to create timer on thread %d\n", (pid_t) syscall(SYS_gettid)); +# endif + + struct sigevent sev; + sev.sigev_notify = SIGEV_THREAD_ID; + sev.sigev_value.sival_ptr = &EG(timer); + // The chosen signal must: + // 1. not be used internally by libc + // 2. be allowed to happen spuriously without consequences + // 3. not be commonly used by applications, this excludes SIGALRM, SIGUSR1 and SIGUSR2 + // 4. not be used by profilers, this excludes SIGPROF + // 5. not be used internally by runtimes of programs that can embed PHP, this excludes SIGURG, which is used by Go + sev.sigev_signo = SIGIO; + sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); + + if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) { + EG(timer) = 0; + zend_strerror_noreturn(E_ERROR, errno, "Could not create timer"); + } + +# ifdef TIMER_DEBUG + fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id); +# endif + + sigaction(sev.sigev_signo, NULL, &EG(oldact)); +} +/* }}} */ + +ZEND_API void zend_timer_settime(zend_long seconds) /* {{{ }*/ +{ + timer_t timer = EG(timer); + +# ifdef TIMER_DEBUG + fprintf(stderr, "Trying to set timer %#jx on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); +# endif + + if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created"); + + struct itimerspec its; + its.it_value.tv_sec = seconds; + its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; + + if (timer_settime(timer, 0, &its, NULL) != 0) + zend_strerror_noreturn(E_ERROR, errno, "Could not set timer"); +} +/* }}} */ + +ZEND_API void zend_timer_delete(void) /* {{{ */ +{ +# ifdef TIMER_DEBUG + fprintf(stderr, "Trying to delete timer %#jx thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); +# endif + + timer_t timer = EG(timer); + if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created"); + + int err = timer_delete(timer); + EG(timer) = 0; + if (err != 0) + zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer"); +} +/* }}}} */ + +#endif diff --git a/Zend/zend_timer.h b/Zend/zend_timer.h index 4097c44cda7a5..25e3e8f98c4f6 100644 --- a/Zend/zend_timer.h +++ b/Zend/zend_timer.h @@ -1,18 +1,34 @@ -#if !defined(ZEND_TIMER_H) && defined(ZTS) && defined(__linux__) && defined(HAVE_TIMER_CREATE) +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Kévin Dunglas | + +----------------------------------------------------------------------+ + */ + +#ifndef ZEND_TIMER_H #define ZEND_TIMER_H +#ifdef __linux__ +#include "php_config.h" + +# if defined(ZTS) && defined(HAVE_TIMER_CREATE) #define ZEND_TIMER 1 -#include -#include -#include -#include -#include +#include "zend_long.h" -// Musl Libc defines this macro, glibc does not -// According to "man 2 timer_create" this field should always be available, but it's not: https://sourceware.org/bugzilla/show_bug.cgi?id=27417 -# ifndef sigev_notify_thread_id -# define sigev_notify_thread_id _sigev_un._tid -# endif +ZEND_API void zend_timer_create(void); +ZEND_API void zend_timer_settime(zend_long seconds); +ZEND_API void zend_timer_delete(void); +# endif +# endif #endif diff --git a/configure.ac b/configure.ac index ee38b260cf208..03ba1ceefc80d 100644 --- a/configure.ac +++ b/configure.ac @@ -1636,7 +1636,7 @@ PHP_ADD_SOURCES(Zend, \ zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \ zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \ - zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c \ + zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_timer.c \ Optimizer/zend_optimizer.c \ Optimizer/pass1.c \ Optimizer/pass3.c \ diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 2ed577af5e341..2666678a7f2bd 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -50,6 +50,8 @@ # define NSIG 32 #endif +#include "Zend/zend_timer.h" + ZEND_DECLARE_MODULE_GLOBALS(pcntl) static PHP_GINIT_FUNCTION(pcntl); @@ -531,6 +533,10 @@ PHP_FUNCTION(pcntl_fork) if (id == -1) { PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error %d", errno); + } else if (id == 0) { + #ifdef ZEND_TIMER + zend_timer_create(); + #endif } RETURN_LONG((zend_long) id); From 3832066b9b2b5a4b3d990b82c75f5d0cd67a5860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 27 Dec 2022 10:44:00 +0100 Subject: [PATCH 14/36] use strerror() on Windows --- Zend/zend.c | 7 +++++-- configure.ac | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index b45b624ba5e09..c9ce05d237e7e 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1630,9 +1630,12 @@ ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char * ZEND_API ZEND_COLD void zend_strerror_noreturn(int type, int errn, const char *message) { +#ifdef HAVE_STR_ERROR_R char buf[1024]; - if (strerror_r(errn, buf, sizeof(buf)) != 0) - zend_error_noreturn(type, "%s: %d", message, errn); + strerror_r(errn, buf, sizeof(buf)) != 0; +#else + char *buf = strerror(errn); +#endif zend_error_noreturn(type, "%s: %s (%d)", message, buf, errn); } diff --git a/configure.ac b/configure.ac index 03ba1ceefc80d..fc7a8bd8f2d5a 100644 --- a/configure.ac +++ b/configure.ac @@ -609,6 +609,7 @@ vasprintf \ asprintf \ nanosleep \ memmem \ +strerror_r \ ) AX_FUNC_WHICH_GETHOSTBYNAME_R From c00f3543b9d5865eeb0bbc4cfb1a777a0720510e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 27 Dec 2022 10:50:25 +0100 Subject: [PATCH 15/36] try to fix tracing JIT --- ext/opcache/ZendAccelerator.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index a912b5e604bb5..ed7509f72e72d 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -4693,6 +4693,9 @@ static int accel_finish_startup(void) zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid); exit(1); } +#ifdef ZEND_TIMER + zend_timer_create(); +#endif in_child = 1; } else { /* parent */ int status; From bfe9e42c67e63c7fdbcdef9fa08264161bd42406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 27 Dec 2022 13:00:19 +0100 Subject: [PATCH 16/36] better initialization --- Zend/zend.c | 2 +- Zend/zend_execute_API.c | 5 +++++ Zend/zend_timer.c | 4 +--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index c9ce05d237e7e..f7de24b097f5a 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1632,7 +1632,7 @@ ZEND_API ZEND_COLD void zend_strerror_noreturn(int type, int errn, const char *m { #ifdef HAVE_STR_ERROR_R char buf[1024]; - strerror_r(errn, buf, sizeof(buf)) != 0; + strerror_r(errn, buf, sizeof(buf)); #else char *buf = strerror(errn); #endif diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index b70ad7e808ca0..6212ac356a769 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -199,6 +199,11 @@ void init_executor(void) /* {{{ */ zend_weakrefs_init(); EG(active) = 1; + +#ifdef ZEND_TIMER + memset(EG(timer), 0, sizeof(*EG(timer))); + memset(&EG(oldact), 0, sizeof(EG(oldact))); +#endif } /* }}} */ diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c index d7a716f5d20d7..b588d567d9d4e 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timer.c @@ -53,10 +53,8 @@ ZEND_API void zend_timer_create(void) /* {{{ */ sev.sigev_signo = SIGIO; sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); - if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) { - EG(timer) = 0; + if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) zend_strerror_noreturn(E_ERROR, errno, "Could not create timer"); - } # ifdef TIMER_DEBUG fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id); From d696a3ac1ec59fbcf688176efa5aac499ee23e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 27 Dec 2022 21:54:21 +0100 Subject: [PATCH 17/36] fix some tests --- Zend/zend_timer.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c index b588d567d9d4e..136eb07b2aead 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timer.c @@ -37,10 +37,6 @@ ZEND_API void zend_timer_create(void) /* {{{ */ { -# ifdef TIMER_DEBUG - fprintf(stderr, "Trying to create timer on thread %d\n", (pid_t) syscall(SYS_gettid)); -# endif - struct sigevent sev; sev.sigev_notify = SIGEV_THREAD_ID; sev.sigev_value.sival_ptr = &EG(timer); @@ -53,8 +49,9 @@ ZEND_API void zend_timer_create(void) /* {{{ */ sev.sigev_signo = SIGIO; sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); - if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) + if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not create timer"); + } # ifdef TIMER_DEBUG fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id); @@ -68,34 +65,45 @@ ZEND_API void zend_timer_settime(zend_long seconds) /* {{{ }*/ { timer_t timer = EG(timer); -# ifdef TIMER_DEBUG - fprintf(stderr, "Trying to set timer %#jx on thread %d (%ld seconds)\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); -# endif - - if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created"); + if (timer == 0) { + zend_error_noreturn(E_ERROR, "Timer not created"); + } struct itimerspec its; its.it_value.tv_sec = seconds; its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; - if (timer_settime(timer, 0, &its, NULL) != 0) +# ifdef TIMER_DEBUG + fprintf(stderr, "Setting timer %#jx on thread %d (%ld seconds)...\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); +# endif + + if (timer_settime(timer, 0, &its, NULL) != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not set timer"); + } } /* }}} */ ZEND_API void zend_timer_delete(void) /* {{{ */ { -# ifdef TIMER_DEBUG - fprintf(stderr, "Trying to delete timer %#jx thread %d\n", (uintmax_t) EG(timer), (pid_t) syscall(SYS_gettid)); -# endif - timer_t timer = EG(timer); - if (timer == 0) zend_error_noreturn(E_ERROR, "Timer not created"); + if (timer == 0) { + /* Don't trigger an error here because the timer may not be initialized when PHP fail early, and on threads created by PHP but not managed by it. */ +# ifdef TIMER_DEBUG + fprintf(stderr, "Could not delete timer that has not been created on thread %d\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); +# endif + + return; + } + +# ifdef TIMER_DEBUG + fprintf(stderr, "Deleting timer %#jx on thread %d...\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); +# endif int err = timer_delete(timer); EG(timer) = 0; - if (err != 0) + if (err != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer"); + } } /* }}}} */ From 4f4bf357f24d0a8248862b0cc01909552e6b85e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 28 Dec 2022 11:23:28 +0100 Subject: [PATCH 18/36] fix SAPI tests --- sapi/cgi/cgi_main.c | 4 ++++ sapi/cli/php_cli_server.c | 5 +++++ sapi/fpm/fpm/fpm_php.c | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 499a7932bed17..ddc3fee6d6966 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -2053,6 +2053,10 @@ consult the installation file that came with this distribution, or visit \n\ sigaction(SIGQUIT, &old_quit, 0); sigaction(SIGINT, &old_int, 0); zend_signal_init(); + +#if ZEND_TIMER + zend_timer_create(); +#endif break; case -1: perror("php (pre-forking)"); diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 626c58fcc2457..1370a657024d5 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -64,6 +64,7 @@ #include "zend_execute.h" #include "zend_highlight.h" #include "zend_exceptions.h" +#include "zend_timer.h" #include "php_getopt.h" @@ -2400,6 +2401,10 @@ static void php_cli_server_startup_workers(void) { } else if (pid == SUCCESS) { return; } else { +#if ZEND_TIMER + zend_timer_create(); +#endif + php_cli_server_workers[php_cli_server_worker] = pid; } } diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c index 92b189668206e..f8f711a4085fd 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -11,6 +11,8 @@ #include "php_ini.h" #include "ext/standard/dl.h" +#include "zend_timer.h" + #include "fastcgi.h" #include "fpm.h" @@ -215,6 +217,10 @@ int fpm_php_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ return -1; } +#if ZEND_TIMER + zend_timer_create(); +#endif + if (wp->limit_extensions) { /* Take ownership of limit_extensions. */ limit_extensions = wp->limit_extensions; From d1391f61af7db54ed2fa76f22530cc87d9157ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 29 Dec 2022 14:44:45 +0100 Subject: [PATCH 19/36] better timer creation --- Zend/zend.c | 4 ---- Zend/zend_execute_API.c | 10 +++++----- Zend/zend_timer.c | 6 +++--- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index f7de24b097f5a..3dd8e37a1be30 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1104,10 +1104,6 @@ zend_result zend_post_startup(void) /* {{{ */ executor_globals_ctor(executor_globals); global_persistent_list = &EG(persistent_list); zend_copy_ini_directives(); - -# ifdef ZEND_TIMER - zend_timer_create(); -# endif #else global_map_ptr_last = CG(map_ptr_last); #endif diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 6212ac356a769..becf83b6d59a9 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -173,6 +173,11 @@ void init_executor(void) /* {{{ */ EG(full_tables_cleanup) = 0; EG(vm_interrupt) = 0; EG(timed_out) = 0; +#ifdef ZEND_TIMER + zend_timer_create(); + /*EG(timer) = (timer_t){0}; + EG(oldact) = (struct sigaction){0};*/ +#endif EG(exception) = NULL; EG(prev_exception) = NULL; @@ -199,11 +204,6 @@ void init_executor(void) /* {{{ */ zend_weakrefs_init(); EG(active) = 1; - -#ifdef ZEND_TIMER - memset(EG(timer), 0, sizeof(*EG(timer))); - memset(&EG(oldact), 0, sizeof(EG(oldact))); -#endif } /* }}} */ diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c index 136eb07b2aead..866e64481046c 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timer.c @@ -65,7 +65,7 @@ ZEND_API void zend_timer_settime(zend_long seconds) /* {{{ }*/ { timer_t timer = EG(timer); - if (timer == 0) { + if (timer == (timer_t){0}) { zend_error_noreturn(E_ERROR, "Timer not created"); } @@ -86,7 +86,7 @@ ZEND_API void zend_timer_settime(zend_long seconds) /* {{{ }*/ ZEND_API void zend_timer_delete(void) /* {{{ */ { timer_t timer = EG(timer); - if (timer == 0) { + if (timer == (timer_t){0}) { /* Don't trigger an error here because the timer may not be initialized when PHP fail early, and on threads created by PHP but not managed by it. */ # ifdef TIMER_DEBUG fprintf(stderr, "Could not delete timer that has not been created on thread %d\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); @@ -100,7 +100,7 @@ ZEND_API void zend_timer_delete(void) /* {{{ */ # endif int err = timer_delete(timer); - EG(timer) = 0; + EG(timer) = (timer_t){0}; if (err != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer"); } From ff02b8cd8696093d8cf6a78e8cc4873f42a676f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 29 Dec 2022 15:43:04 +0100 Subject: [PATCH 20/36] cleanup --- Zend/zend_execute_API.c | 2 -- Zend/zend_timer.c | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index becf83b6d59a9..54ca355e23bbb 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -175,8 +175,6 @@ void init_executor(void) /* {{{ */ EG(timed_out) = 0; #ifdef ZEND_TIMER zend_timer_create(); - /*EG(timer) = (timer_t){0}; - EG(oldact) = (struct sigaction){0};*/ #endif EG(exception) = NULL; diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c index 866e64481046c..a6c14e60b50cb 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timer.c @@ -65,10 +65,6 @@ ZEND_API void zend_timer_settime(zend_long seconds) /* {{{ }*/ { timer_t timer = EG(timer); - if (timer == (timer_t){0}) { - zend_error_noreturn(E_ERROR, "Timer not created"); - } - struct itimerspec its; its.it_value.tv_sec = seconds; its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; @@ -86,14 +82,6 @@ ZEND_API void zend_timer_settime(zend_long seconds) /* {{{ }*/ ZEND_API void zend_timer_delete(void) /* {{{ */ { timer_t timer = EG(timer); - if (timer == (timer_t){0}) { - /* Don't trigger an error here because the timer may not be initialized when PHP fail early, and on threads created by PHP but not managed by it. */ -# ifdef TIMER_DEBUG - fprintf(stderr, "Could not delete timer that has not been created on thread %d\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); -# endif - - return; - } # ifdef TIMER_DEBUG fprintf(stderr, "Deleting timer %#jx on thread %d...\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); From da21e3f834124918f060729345acb4ca4f19f074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 29 Dec 2022 16:21:54 +0100 Subject: [PATCH 21/36] skip delete when needed --- Zend/zend_timer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c index a6c14e60b50cb..3c51a6247e8db 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timer.c @@ -82,6 +82,14 @@ ZEND_API void zend_timer_settime(zend_long seconds) /* {{{ }*/ ZEND_API void zend_timer_delete(void) /* {{{ */ { timer_t timer = EG(timer); + if (timer == (timer_t){0}) { + /* Don't trigger an error here because the timer may not be initialized when PHP fail early, and on threads created by PHP but not managed by it. */ +# ifdef TIMER_DEBUG + fprintf(stderr, "Could not delete timer that has not been created on thread %d\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); +# endif + + return; + } # ifdef TIMER_DEBUG fprintf(stderr, "Deleting timer %#jx on thread %d...\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); From 9dad7b904273966140e58bb4dd7513202a482f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 30 Dec 2022 15:23:19 +0100 Subject: [PATCH 22/36] improve timer support detection --- Zend/Zend.m4 | 22 ++++++++++++++++++++++ Zend/zend_timer.c | 2 -- Zend/zend_timer.h | 7 +------ configure.ac | 3 --- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index 1a73cd6f8dca9..e301e22b5c450 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -269,6 +269,28 @@ fi AC_MSG_CHECKING(whether to enable zend signal handling) AC_MSG_RESULT($ZEND_SIGNALS) +dnl By default, enable Zend Timer only for ZTS builds +AC_ARG_ENABLE([zend-timer], + [AS_HELP_STRING([--enable-zend-timer], + [whether to enable zend timer system])], + [ZEND_TIMER=$enableval], + [ZEND_TIMER=$ZEND_ZTS]) + +AS_CASE(["$host_alias"], [*linux*], [], [ZEND_TIMER='no']) + +PHP_CHECK_FUNC(timer_create, rt) +if test "$ac_cv_func_timer_create" != "yes"; then + ZEND_TIMER='no' +fi + +if test "$ZEND_TIMER" = "yes"; then + AC_DEFINE(ZEND_TIMER, 1, [Use zend timer system]) + CFLAGS="$CFLAGS -DZEND_TIMER" +fi + +AC_MSG_CHECKING(whether to enable zend timer system) +AC_MSG_RESULT($ZEND_TIMER) + ]) AC_MSG_CHECKING(whether /dev/urandom exists) diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c index 3c51a6247e8db..d264576c19ebf 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timer.c @@ -14,8 +14,6 @@ +----------------------------------------------------------------------+ */ -#include "zend_timer.h" - #ifdef ZEND_TIMER #include diff --git a/Zend/zend_timer.h b/Zend/zend_timer.h index 25e3e8f98c4f6..3ff3a38fa2f0a 100644 --- a/Zend/zend_timer.h +++ b/Zend/zend_timer.h @@ -17,11 +17,7 @@ #ifndef ZEND_TIMER_H #define ZEND_TIMER_H -#ifdef __linux__ -#include "php_config.h" - -# if defined(ZTS) && defined(HAVE_TIMER_CREATE) -#define ZEND_TIMER 1 +# ifdef ZEND_TIMER #include "zend_long.h" @@ -29,6 +25,5 @@ ZEND_API void zend_timer_create(void); ZEND_API void zend_timer_settime(zend_long seconds); ZEND_API void zend_timer_delete(void); -# endif # endif #endif diff --git a/configure.ac b/configure.ac index fc7a8bd8f2d5a..749a86cfc00d9 100644 --- a/configure.ac +++ b/configure.ac @@ -744,9 +744,6 @@ fi dnl Check for openpty. It may require linking against libutil or libbsd. PHP_CHECK_FUNC(openpty, util, bsd) -dnl Check for timer_create -PHP_CHECK_FUNC(timer_create, rt) - dnl General settings. dnl ---------------------------------------------------------------------------- PHP_CONFIGURE_PART(General settings) From 1f72b22110dc7d6825ed9a037aea27fd0d6e04ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 30 Dec 2022 15:25:26 +0100 Subject: [PATCH 23/36] add entry in phpinfo --- Zend/Zend.m4 | 6 +++--- ext/standard/info.c | 6 ++++++ ext/standard/tests/general_functions/phpinfo.phpt | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index e301e22b5c450..652e3060540b1 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -272,7 +272,7 @@ AC_MSG_RESULT($ZEND_SIGNALS) dnl By default, enable Zend Timer only for ZTS builds AC_ARG_ENABLE([zend-timer], [AS_HELP_STRING([--enable-zend-timer], - [whether to enable zend timer system])], + [whether to enable zend timer])], [ZEND_TIMER=$enableval], [ZEND_TIMER=$ZEND_ZTS]) @@ -284,11 +284,11 @@ if test "$ac_cv_func_timer_create" != "yes"; then fi if test "$ZEND_TIMER" = "yes"; then - AC_DEFINE(ZEND_TIMER, 1, [Use zend timer system]) + AC_DEFINE(ZEND_TIMER, 1, [Use zend timer]) CFLAGS="$CFLAGS -DZEND_TIMER" fi -AC_MSG_CHECKING(whether to enable zend timer system) +AC_MSG_CHECKING(whether to enable zend timer) AC_MSG_RESULT($ZEND_TIMER) ]) diff --git a/ext/standard/info.c b/ext/standard/info.c index 651bf3ae3f6d7..ff0281f4b06dd 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -891,6 +891,12 @@ PHPAPI ZEND_COLD void php_print_info(int flag) efree(descr); } +#ifdef ZEND_TIMER + php_info_print_table_row(2, "Zend Timer", "enabled" ); +#else + php_info_print_table_row(2, "Zend Timer", "disabled" ); +#endif + #if HAVE_IPV6 php_info_print_table_row(2, "IPv6 Support", "enabled" ); #else diff --git a/ext/standard/tests/general_functions/phpinfo.phpt b/ext/standard/tests/general_functions/phpinfo.phpt index 5f4d99ffbaf2e..0127d6fe7eebe 100644 --- a/ext/standard/tests/general_functions/phpinfo.phpt +++ b/ext/standard/tests/general_functions/phpinfo.phpt @@ -34,6 +34,7 @@ Thread Safety => %s%A Zend Signal Handling => %s Zend Memory Manager => %s Zend Multibyte Support => %s +Zend Timer => %s IPv6 Support => %s DTrace Support => %s From b8770bb323acfde9e3b59785d634cf8c80d1638f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 9 Jan 2023 15:29:38 +0100 Subject: [PATCH 24/36] rename to zend_timers --- Zend/Zend.m4 | 18 +++++++++--------- Zend/zend.c | 10 +++++----- Zend/zend.h | 2 +- Zend/zend_execute_API.c | 16 ++++++++-------- Zend/zend_globals.h | 4 ++-- Zend/{zend_timer.c => zend_timers.c} | 8 ++++---- Zend/{zend_timer.h => zend_timers.h} | 12 ++++++------ configure.ac | 2 +- ext/opcache/ZendAccelerator.c | 4 ++-- ext/pcntl/pcntl.c | 6 +++--- ext/standard/info.c | 6 +++--- .../tests/general_functions/phpinfo.phpt | 2 +- sapi/cgi/cgi_main.c | 4 ++-- sapi/cli/php_cli_server.c | 6 +++--- sapi/fpm/fpm/fpm_php.c | 6 +++--- 15 files changed, 53 insertions(+), 53 deletions(-) rename Zend/{zend_timer.c => zend_timers.c} (95%) rename Zend/{zend_timer.h => zend_timers.h} (83%) diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index 652e3060540b1..26dbcb57626cf 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -269,27 +269,27 @@ fi AC_MSG_CHECKING(whether to enable zend signal handling) AC_MSG_RESULT($ZEND_SIGNALS) -dnl By default, enable Zend Timer only for ZTS builds +dnl By default, enable Zend Timers only for ZTS builds AC_ARG_ENABLE([zend-timer], [AS_HELP_STRING([--enable-zend-timer], [whether to enable zend timer])], - [ZEND_TIMER=$enableval], - [ZEND_TIMER=$ZEND_ZTS]) + [ZEND_TIMERS=$enableval], + [ZEND_TIMERS=$ZEND_ZTS]) -AS_CASE(["$host_alias"], [*linux*], [], [ZEND_TIMER='no']) +AS_CASE(["$host_alias"], [*linux*], [], [ZEND_TIMERS='no']) PHP_CHECK_FUNC(timer_create, rt) if test "$ac_cv_func_timer_create" != "yes"; then - ZEND_TIMER='no' + ZEND_TIMERS='no' fi -if test "$ZEND_TIMER" = "yes"; then - AC_DEFINE(ZEND_TIMER, 1, [Use zend timer]) - CFLAGS="$CFLAGS -DZEND_TIMER" +if test "$ZEND_TIMERS" = "yes"; then + AC_DEFINE(ZEND_TIMERS, 1, [Use zend timer]) + CFLAGS="$CFLAGS -DZEND_TIMERS" fi AC_MSG_CHECKING(whether to enable zend timer) -AC_MSG_RESULT($ZEND_TIMER) +AC_MSG_RESULT($ZEND_TIMERS) ]) diff --git a/Zend/zend.c b/Zend/zend.c index 3dd8e37a1be30..5687c6567b482 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -35,7 +35,7 @@ #include "zend_attributes.h" #include "zend_observer.h" #include "zend_fibers.h" -#include "zend_timer.h" +#include "zend_timers.h" #include "Optimizer/zend_optimizer.h" static size_t global_map_ptr_last = 0; @@ -822,16 +822,16 @@ static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ { zend_copy_ini_directives(); zend_ini_refresh_caches(ZEND_INI_STAGE_STARTUP); -#ifdef ZEND_TIMER - zend_timer_create(); +#ifdef ZEND_TIMERS + zend_timers_create(); #endif } /* }}} */ static void zend_thread_shutdown_handler(void) { /* {{{ */ zend_interned_strings_dtor(); -#ifdef ZEND_TIMER - zend_timer_delete(); +#ifdef ZEND_TIMERS + zend_timers_delete(); #endif } /* }}} */ diff --git a/Zend/zend.h b/Zend/zend.h index 505bf4ef63da5..5227890285a25 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -39,7 +39,7 @@ #include "zend_smart_str_public.h" #include "zend_smart_string_public.h" #include "zend_signal.h" -#include "zend_timer.h" +#include "zend_timers.h" #define zend_sprintf sprintf diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 54ca355e23bbb..34636fdc185dd 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -43,7 +43,7 @@ #ifdef HAVE_UNISTD_H #include #endif -#ifdef ZEND_TIMER +#ifdef ZEND_TIMERS #include #endif @@ -173,8 +173,8 @@ void init_executor(void) /* {{{ */ EG(full_tables_cleanup) = 0; EG(vm_interrupt) = 0; EG(timed_out) = 0; -#ifdef ZEND_TIMER - zend_timer_create(); +#ifdef ZEND_TIMERS + zend_timers_create(); #endif EG(exception) = NULL; @@ -1320,7 +1320,7 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */ /* }}} */ #ifndef ZEND_WIN32 -# ifdef ZEND_TIMER +# ifdef ZEND_TIMERS static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ { if (si->si_value.sival_ptr != &EG(timer)) { @@ -1440,8 +1440,8 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ zend_error_noreturn(E_ERROR, "Could not queue new timer"); return; } -#elif defined(ZEND_TIMER) - zend_timer_settime(seconds); +#elif defined(ZEND_TIMERS) + zend_timers_settime(seconds); if (reset_signals) { sigset_t sigset; @@ -1520,8 +1520,8 @@ void zend_unset_timeout(void) /* {{{ */ } tq_timer = NULL; } -#elif ZEND_TIMER - zend_timer_settime(0); +#elif ZEND_TIMERS + zend_timers_settime(0); #elif defined(HAVE_SETITIMER) if (EG(timeout_seconds)) { struct itimerval no_timeout; diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index a7ec8c1983ba5..e678266bbfd3d 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -36,7 +36,7 @@ #include "zend_multibyte.h" #include "zend_multiply.h" #include "zend_arena.h" -#include "zend_timer.h" +#include "zend_timers.h" /* Define ZTS if you want a thread-safe Zend */ /*#undef ZTS*/ @@ -267,7 +267,7 @@ struct _zend_executor_globals { uint32_t num_errors; zend_error_info **errors; -#ifdef ZEND_TIMER +#ifdef ZEND_TIMERS timer_t timer; struct sigaction oldact; #endif diff --git a/Zend/zend_timer.c b/Zend/zend_timers.c similarity index 95% rename from Zend/zend_timer.c rename to Zend/zend_timers.c index d264576c19ebf..bb7912134005c 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timers.c @@ -14,7 +14,7 @@ +----------------------------------------------------------------------+ */ -#ifdef ZEND_TIMER +#ifdef ZEND_TIMERS #include #include @@ -33,7 +33,7 @@ # define sigev_notify_thread_id _sigev_un._tid # endif -ZEND_API void zend_timer_create(void) /* {{{ */ +ZEND_API void zend_timers_create(void) /* {{{ */ { struct sigevent sev; sev.sigev_notify = SIGEV_THREAD_ID; @@ -59,7 +59,7 @@ ZEND_API void zend_timer_create(void) /* {{{ */ } /* }}} */ -ZEND_API void zend_timer_settime(zend_long seconds) /* {{{ }*/ +ZEND_API void zend_timers_settime(zend_long seconds) /* {{{ }*/ { timer_t timer = EG(timer); @@ -77,7 +77,7 @@ ZEND_API void zend_timer_settime(zend_long seconds) /* {{{ }*/ } /* }}} */ -ZEND_API void zend_timer_delete(void) /* {{{ */ +ZEND_API void zend_timers_delete(void) /* {{{ */ { timer_t timer = EG(timer); if (timer == (timer_t){0}) { diff --git a/Zend/zend_timer.h b/Zend/zend_timers.h similarity index 83% rename from Zend/zend_timer.h rename to Zend/zend_timers.h index 3ff3a38fa2f0a..580a68fbbb1fc 100644 --- a/Zend/zend_timer.h +++ b/Zend/zend_timers.h @@ -14,16 +14,16 @@ +----------------------------------------------------------------------+ */ -#ifndef ZEND_TIMER_H -#define ZEND_TIMER_H +#ifndef ZEND_TIMERS_H +#define ZEND_TIMERS_H -# ifdef ZEND_TIMER +# ifdef ZEND_TIMERS #include "zend_long.h" -ZEND_API void zend_timer_create(void); -ZEND_API void zend_timer_settime(zend_long seconds); -ZEND_API void zend_timer_delete(void); +ZEND_API void zend_timers_create(void); +ZEND_API void zend_timers_settime(zend_long seconds); +ZEND_API void zend_timers_delete(void); # endif #endif diff --git a/configure.ac b/configure.ac index 749a86cfc00d9..af8214b06cb85 100644 --- a/configure.ac +++ b/configure.ac @@ -1634,7 +1634,7 @@ PHP_ADD_SOURCES(Zend, \ zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \ zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \ - zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_timer.c \ + zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_timers.c \ Optimizer/zend_optimizer.c \ Optimizer/pass1.c \ Optimizer/pass3.c \ diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index ed7509f72e72d..0a8c733b35b5f 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -4693,8 +4693,8 @@ static int accel_finish_startup(void) zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid); exit(1); } -#ifdef ZEND_TIMER - zend_timer_create(); +#ifdef ZEND_TIMERS + zend_timers_create(); #endif in_child = 1; } else { /* parent */ diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 2666678a7f2bd..55983e32934d4 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -50,7 +50,7 @@ # define NSIG 32 #endif -#include "Zend/zend_timer.h" +#include "Zend/zend_timers.h" ZEND_DECLARE_MODULE_GLOBALS(pcntl) static PHP_GINIT_FUNCTION(pcntl); @@ -534,8 +534,8 @@ PHP_FUNCTION(pcntl_fork) PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error %d", errno); } else if (id == 0) { - #ifdef ZEND_TIMER - zend_timer_create(); + #ifdef ZEND_TIMERS + zend_timers_create(); #endif } diff --git a/ext/standard/info.c b/ext/standard/info.c index ff0281f4b06dd..192a7acf27565 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -891,10 +891,10 @@ PHPAPI ZEND_COLD void php_print_info(int flag) efree(descr); } -#ifdef ZEND_TIMER - php_info_print_table_row(2, "Zend Timer", "enabled" ); +#ifdef ZEND_TIMERS + php_info_print_table_row(2, "Zend Timers", "enabled" ); #else - php_info_print_table_row(2, "Zend Timer", "disabled" ); + php_info_print_table_row(2, "Zend Timers", "disabled" ); #endif #if HAVE_IPV6 diff --git a/ext/standard/tests/general_functions/phpinfo.phpt b/ext/standard/tests/general_functions/phpinfo.phpt index 0127d6fe7eebe..bd66a26606b9d 100644 --- a/ext/standard/tests/general_functions/phpinfo.phpt +++ b/ext/standard/tests/general_functions/phpinfo.phpt @@ -34,7 +34,7 @@ Thread Safety => %s%A Zend Signal Handling => %s Zend Memory Manager => %s Zend Multibyte Support => %s -Zend Timer => %s +Zend Timers => %s IPv6 Support => %s DTrace Support => %s diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index ddc3fee6d6966..1be1b88b21483 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -2054,8 +2054,8 @@ consult the installation file that came with this distribution, or visit \n\ sigaction(SIGINT, &old_int, 0); zend_signal_init(); -#if ZEND_TIMER - zend_timer_create(); +#if ZEND_TIMERS + zend_timers_create(); #endif break; case -1: diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 1370a657024d5..663a0882c78b0 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -64,7 +64,7 @@ #include "zend_execute.h" #include "zend_highlight.h" #include "zend_exceptions.h" -#include "zend_timer.h" +#include "zend_timers.h" #include "php_getopt.h" @@ -2401,8 +2401,8 @@ static void php_cli_server_startup_workers(void) { } else if (pid == SUCCESS) { return; } else { -#if ZEND_TIMER - zend_timer_create(); +#if ZEND_TIMERS + zend_timers_create(); #endif php_cli_server_workers[php_cli_server_worker] = pid; diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c index f8f711a4085fd..99b7e3d4b8af0 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -11,7 +11,7 @@ #include "php_ini.h" #include "ext/standard/dl.h" -#include "zend_timer.h" +#include "zend_timers.h" #include "fastcgi.h" @@ -217,8 +217,8 @@ int fpm_php_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ return -1; } -#if ZEND_TIMER - zend_timer_create(); +#if ZEND_TIMERS + zend_timers_create(); #endif if (wp->limit_extensions) { From cde29fd4e49f71c8dfef984d9f85d8a8a43ca464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 9 Jan 2023 15:38:26 +0100 Subject: [PATCH 25/36] Measure wall-time instead of CPU-time --- Zend/zend_timers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_timers.c b/Zend/zend_timers.c index bb7912134005c..5cedff32909ea 100644 --- a/Zend/zend_timers.c +++ b/Zend/zend_timers.c @@ -47,7 +47,7 @@ ZEND_API void zend_timers_create(void) /* {{{ */ sev.sigev_signo = SIGIO; sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); - if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &EG(timer)) != 0) { + if (timer_create(CLOCK_REALTIME, &sev, &EG(timer)) != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not create timer"); } From d261423e150115f0aa18ff7b53e5bab714ddda85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 9 Jan 2023 16:23:14 +0100 Subject: [PATCH 26/36] reduce API surface --- Zend/zend.c | 4 ++-- Zend/zend_execute_API.c | 2 +- Zend/zend_timers.c | 7 ++++--- Zend/zend_timers.h | 6 +++--- ext/opcache/ZendAccelerator.c | 2 +- ext/pcntl/pcntl.c | 2 +- sapi/cgi/cgi_main.c | 2 +- sapi/cli/php_cli_server.c | 2 +- sapi/fpm/fpm/fpm_php.c | 2 +- 9 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index 5687c6567b482..5e7c8263e3a34 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -823,7 +823,7 @@ static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ zend_copy_ini_directives(); zend_ini_refresh_caches(ZEND_INI_STAGE_STARTUP); #ifdef ZEND_TIMERS - zend_timers_create(); + zend_timers_startup(); #endif } /* }}} */ @@ -831,7 +831,7 @@ static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ static void zend_thread_shutdown_handler(void) { /* {{{ */ zend_interned_strings_dtor(); #ifdef ZEND_TIMERS - zend_timers_delete(); + zend_timers_shutdown(); #endif } /* }}} */ diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 34636fdc185dd..490166808fdab 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -174,7 +174,7 @@ void init_executor(void) /* {{{ */ EG(vm_interrupt) = 0; EG(timed_out) = 0; #ifdef ZEND_TIMERS - zend_timers_create(); + zend_timers_startup(); #endif EG(exception) = NULL; diff --git a/Zend/zend_timers.c b/Zend/zend_timers.c index 5cedff32909ea..564768ab46552 100644 --- a/Zend/zend_timers.c +++ b/Zend/zend_timers.c @@ -33,7 +33,7 @@ # define sigev_notify_thread_id _sigev_un._tid # endif -ZEND_API void zend_timers_create(void) /* {{{ */ +ZEND_API void zend_timers_startup(void) /* {{{ */ { struct sigevent sev; sev.sigev_notify = SIGEV_THREAD_ID; @@ -47,6 +47,7 @@ ZEND_API void zend_timers_create(void) /* {{{ */ sev.sigev_signo = SIGIO; sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); + // Measure wall time instead of CPU time as originally planned now that it is possible https://github.com/php/php-src/pull/6504#issuecomment-1370303727 if (timer_create(CLOCK_REALTIME, &sev, &EG(timer)) != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not create timer"); } @@ -59,7 +60,7 @@ ZEND_API void zend_timers_create(void) /* {{{ */ } /* }}} */ -ZEND_API void zend_timers_settime(zend_long seconds) /* {{{ }*/ +void zend_timers_settime(zend_long seconds) /* {{{ }*/ { timer_t timer = EG(timer); @@ -77,7 +78,7 @@ ZEND_API void zend_timers_settime(zend_long seconds) /* {{{ }*/ } /* }}} */ -ZEND_API void zend_timers_delete(void) /* {{{ */ +void zend_timers_shutdown(void) /* {{{ */ { timer_t timer = EG(timer); if (timer == (timer_t){0}) { diff --git a/Zend/zend_timers.h b/Zend/zend_timers.h index 580a68fbbb1fc..c57a1cebbd0ca 100644 --- a/Zend/zend_timers.h +++ b/Zend/zend_timers.h @@ -21,9 +21,9 @@ #include "zend_long.h" -ZEND_API void zend_timers_create(void); -ZEND_API void zend_timers_settime(zend_long seconds); -ZEND_API void zend_timers_delete(void); +ZEND_API void zend_timers_startup(void); +void zend_timers_settime(zend_long seconds); +void zend_timers_shutdown(void); # endif #endif diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 0a8c733b35b5f..6683152bce03b 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -4694,7 +4694,7 @@ static int accel_finish_startup(void) exit(1); } #ifdef ZEND_TIMERS - zend_timers_create(); + zend_timers_startup(); #endif in_child = 1; } else { /* parent */ diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 55983e32934d4..3e66bc6741f4f 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -535,7 +535,7 @@ PHP_FUNCTION(pcntl_fork) php_error_docref(NULL, E_WARNING, "Error %d", errno); } else if (id == 0) { #ifdef ZEND_TIMERS - zend_timers_create(); + zend_timers_startup(); #endif } diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 1be1b88b21483..8f3b4284f3c6b 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -2055,7 +2055,7 @@ consult the installation file that came with this distribution, or visit \n\ zend_signal_init(); #if ZEND_TIMERS - zend_timers_create(); + zend_timers_startup(); #endif break; case -1: diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 663a0882c78b0..064b5c59fb5fd 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -2402,7 +2402,7 @@ static void php_cli_server_startup_workers(void) { return; } else { #if ZEND_TIMERS - zend_timers_create(); + zend_timers_startup(); #endif php_cli_server_workers[php_cli_server_worker] = pid; diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c index 99b7e3d4b8af0..bf1589c33bf63 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -218,7 +218,7 @@ int fpm_php_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ } #if ZEND_TIMERS - zend_timers_create(); + zend_timers_startup(); #endif if (wp->limit_extensions) { From f0eabbde268496da9d5612a425ceae3899b7605c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 10 Jan 2023 09:37:27 +0100 Subject: [PATCH 27/36] cleanup API --- Zend/zend.c | 8 +++----- Zend/zend.h | 2 +- Zend/zend_execute_API.c | 8 +++----- Zend/zend_globals.h | 2 +- Zend/{zend_timers.c => zend_timer.c} | 6 +++--- Zend/{zend_timers.h => zend_timer.h} | 17 ++++++++++++----- configure.ac | 2 +- ext/opcache/ZendAccelerator.c | 5 ++--- ext/pcntl/pcntl.c | 6 ++---- sapi/apache2handler/sapi_apache2.c | 10 ++++++++++ sapi/cgi/cgi_main.c | 5 +---- sapi/cli/php_cli_server.c | 6 ++---- sapi/fpm/fpm/fpm_php.c | 7 ++----- 13 files changed, 43 insertions(+), 41 deletions(-) rename Zend/{zend_timers.c => zend_timer.c} (96%) rename Zend/{zend_timers.h => zend_timer.h} (77%) diff --git a/Zend/zend.c b/Zend/zend.c index 5e7c8263e3a34..c47a9c2e156c8 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -35,7 +35,7 @@ #include "zend_attributes.h" #include "zend_observer.h" #include "zend_fibers.h" -#include "zend_timers.h" +#include "zend_timer.h" #include "Optimizer/zend_optimizer.h" static size_t global_map_ptr_last = 0; @@ -822,16 +822,14 @@ static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ { zend_copy_ini_directives(); zend_ini_refresh_caches(ZEND_INI_STAGE_STARTUP); -#ifdef ZEND_TIMERS - zend_timers_startup(); -#endif + zend_timer_init(); } /* }}} */ static void zend_thread_shutdown_handler(void) { /* {{{ */ zend_interned_strings_dtor(); #ifdef ZEND_TIMERS - zend_timers_shutdown(); + zend_timer_shutdown(); #endif } /* }}} */ diff --git a/Zend/zend.h b/Zend/zend.h index 5227890285a25..505bf4ef63da5 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -39,7 +39,7 @@ #include "zend_smart_str_public.h" #include "zend_smart_string_public.h" #include "zend_signal.h" -#include "zend_timers.h" +#include "zend_timer.h" #define zend_sprintf sprintf diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 490166808fdab..96f6563b78670 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -173,9 +173,6 @@ void init_executor(void) /* {{{ */ EG(full_tables_cleanup) = 0; EG(vm_interrupt) = 0; EG(timed_out) = 0; -#ifdef ZEND_TIMERS - zend_timers_startup(); -#endif EG(exception) = NULL; EG(prev_exception) = NULL; @@ -198,6 +195,7 @@ void init_executor(void) /* {{{ */ EG(num_errors) = 0; EG(errors) = NULL; + zend_timer_init(); zend_fiber_init(); zend_weakrefs_init(); @@ -1441,7 +1439,7 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ return; } #elif defined(ZEND_TIMERS) - zend_timers_settime(seconds); + zend_timer_settime(seconds); if (reset_signals) { sigset_t sigset; @@ -1521,7 +1519,7 @@ void zend_unset_timeout(void) /* {{{ */ tq_timer = NULL; } #elif ZEND_TIMERS - zend_timers_settime(0); + zend_timer_settime(0); #elif defined(HAVE_SETITIMER) if (EG(timeout_seconds)) { struct itimerval no_timeout; diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index e678266bbfd3d..a1050c36e67f9 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -36,7 +36,7 @@ #include "zend_multibyte.h" #include "zend_multiply.h" #include "zend_arena.h" -#include "zend_timers.h" +#include "zend_timer.h" /* Define ZTS if you want a thread-safe Zend */ /*#undef ZTS*/ diff --git a/Zend/zend_timers.c b/Zend/zend_timer.c similarity index 96% rename from Zend/zend_timers.c rename to Zend/zend_timer.c index 564768ab46552..d0bdeb877d897 100644 --- a/Zend/zend_timers.c +++ b/Zend/zend_timer.c @@ -33,7 +33,7 @@ # define sigev_notify_thread_id _sigev_un._tid # endif -ZEND_API void zend_timers_startup(void) /* {{{ */ +ZEND_API void zend_timer_init(void) /* {{{ */ { struct sigevent sev; sev.sigev_notify = SIGEV_THREAD_ID; @@ -60,7 +60,7 @@ ZEND_API void zend_timers_startup(void) /* {{{ */ } /* }}} */ -void zend_timers_settime(zend_long seconds) /* {{{ }*/ +void zend_timer_settime(zend_long seconds) /* {{{ }*/ { timer_t timer = EG(timer); @@ -78,7 +78,7 @@ void zend_timers_settime(zend_long seconds) /* {{{ }*/ } /* }}} */ -void zend_timers_shutdown(void) /* {{{ */ +void zend_timer_shutdown(void) /* {{{ */ { timer_t timer = EG(timer); if (timer == (timer_t){0}) { diff --git a/Zend/zend_timers.h b/Zend/zend_timer.h similarity index 77% rename from Zend/zend_timers.h rename to Zend/zend_timer.h index c57a1cebbd0ca..9b07faf9f3910 100644 --- a/Zend/zend_timers.h +++ b/Zend/zend_timer.h @@ -14,16 +14,23 @@ +----------------------------------------------------------------------+ */ -#ifndef ZEND_TIMERS_H -#define ZEND_TIMERS_H +#ifndef ZEND_TIMER_H +#define ZEND_TIMER_H # ifdef ZEND_TIMERS #include "zend_long.h" -ZEND_API void zend_timers_startup(void); -void zend_timers_settime(zend_long seconds); -void zend_timers_shutdown(void); +/* Must be called after calls to fork() */ +ZEND_API void zend_timer_init(void); +void zend_timer_settime(zend_long seconds); +void zend_timer_shutdown(void); + +# else + +#define zend_timer_init() +#define zend_timer_settime(seconds) +#define zend_timer_shutdown() # endif #endif diff --git a/configure.ac b/configure.ac index af8214b06cb85..749a86cfc00d9 100644 --- a/configure.ac +++ b/configure.ac @@ -1634,7 +1634,7 @@ PHP_ADD_SOURCES(Zend, \ zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \ zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \ - zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_timers.c \ + zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_timer.c \ Optimizer/zend_optimizer.c \ Optimizer/pass1.c \ Optimizer/pass3.c \ diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 6683152bce03b..a7047fb0f8407 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -4693,9 +4693,8 @@ static int accel_finish_startup(void) zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid); exit(1); } -#ifdef ZEND_TIMERS - zend_timers_startup(); -#endif + zend_timer_init(); + in_child = 1; } else { /* parent */ int status; diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 3e66bc6741f4f..5c0d08528d86d 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -50,7 +50,7 @@ # define NSIG 32 #endif -#include "Zend/zend_timers.h" +#include "Zend/zend_timer.h" ZEND_DECLARE_MODULE_GLOBALS(pcntl) static PHP_GINIT_FUNCTION(pcntl); @@ -534,9 +534,7 @@ PHP_FUNCTION(pcntl_fork) PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error %d", errno); } else if (id == 0) { - #ifdef ZEND_TIMERS - zend_timers_startup(); - #endif + zend_timer_init(); } RETURN_LONG((zend_long) id); diff --git a/sapi/apache2handler/sapi_apache2.c b/sapi/apache2handler/sapi_apache2.c index 959348484c59f..06ae2ff8afdbc 100644 --- a/sapi/apache2handler/sapi_apache2.c +++ b/sapi/apache2handler/sapi_apache2.c @@ -753,6 +753,13 @@ static void php_apache_signal_init(apr_pool_t *pchild, server_rec *s) } #endif +#ifdef ZEND_TIMERS +static void php_apache_timers_init(apr_pool_t *pchild, server_rec *s) +{ + zend_timer_init(); +} +#endif + void php_ap2_register_hook(apr_pool_t *p) { ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE); @@ -760,6 +767,9 @@ void php_ap2_register_hook(apr_pool_t *p) ap_hook_handler(php_handler, NULL, NULL, APR_HOOK_MIDDLE); #ifdef ZEND_SIGNALS ap_hook_child_init(php_apache_signal_init, NULL, NULL, APR_HOOK_MIDDLE); +#endif +#ifdef ZEND_TIMERS + ap_hook_child_init(php_apache_timers_init, NULL, NULL, APR_HOOK_MIDDLE); #endif ap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE); } diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 8f3b4284f3c6b..77adbb9ae689a 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -2053,10 +2053,7 @@ consult the installation file that came with this distribution, or visit \n\ sigaction(SIGQUIT, &old_quit, 0); sigaction(SIGINT, &old_int, 0); zend_signal_init(); - -#if ZEND_TIMERS - zend_timers_startup(); -#endif + zend_timer_init(); break; case -1: perror("php (pre-forking)"); diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 064b5c59fb5fd..33660ab212646 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -64,7 +64,7 @@ #include "zend_execute.h" #include "zend_highlight.h" #include "zend_exceptions.h" -#include "zend_timers.h" +#include "zend_timer.h" #include "php_getopt.h" @@ -2401,9 +2401,7 @@ static void php_cli_server_startup_workers(void) { } else if (pid == SUCCESS) { return; } else { -#if ZEND_TIMERS - zend_timers_startup(); -#endif + zend_timer_init(); php_cli_server_workers[php_cli_server_worker] = pid; } diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c index bf1589c33bf63..5942432a622e4 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -11,7 +11,7 @@ #include "php_ini.h" #include "ext/standard/dl.h" -#include "zend_timers.h" +#include "zend_timer.h" #include "fastcgi.h" @@ -216,10 +216,7 @@ int fpm_php_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ 0 > fpm_php_set_allowed_clients(wp)) { return -1; } - -#if ZEND_TIMERS - zend_timers_startup(); -#endif + zend_timer_init(); if (wp->limit_extensions) { /* Take ownership of limit_extensions. */ From 9ba1025f667d39db1f2644e56747241f184596e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sun, 15 Jan 2023 22:10:11 +0100 Subject: [PATCH 28/36] add ZEND_NORETURN to zend_strerror_noreturn() --- Zend/zend.c | 2 +- Zend/zend.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index c47a9c2e156c8..8a094e1268651 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1622,7 +1622,7 @@ ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char * abort(); } -ZEND_API ZEND_COLD void zend_strerror_noreturn(int type, int errn, const char *message) +ZEND_API ZEND_COLD ZEND_NORETURN void zend_strerror_noreturn(int type, int errn, const char *message) { #ifdef HAVE_STR_ERROR_R char buf[1024]; diff --git a/Zend/zend.h b/Zend/zend.h index 505bf4ef63da5..db40fcd9fc13d 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -355,7 +355,7 @@ ZEND_API ZEND_COLD void zend_value_error(const char *format, ...) ZEND_ATTRIBUTE ZEND_COLD void zenderror(const char *error); /* For internal C errors */ -ZEND_API ZEND_COLD void zend_strerror_noreturn(int type, int errn, const char *message); +ZEND_API ZEND_COLD ZEND_NORETURN void zend_strerror_noreturn(int type, int errn, const char *message); /* The following #define is used for code duality in PHP for Engine 1 & 2 */ #define ZEND_STANDARD_CLASS_DEF_PTR zend_standard_class_def From aec1f1ba374926cf5a5145045e9fd9f8b2a51c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sun, 15 Jan 2023 23:42:49 +0100 Subject: [PATCH 29/36] store pid --- Zend/zend_globals.h | 2 ++ Zend/zend_timer.c | 6 ++++++ ext/opcache/ZendAccelerator.c | 2 -- sapi/apache2handler/sapi_apache2.c | 10 ---------- sapi/cgi/cgi_main.c | 1 - sapi/cli/php_cli_server.c | 3 --- sapi/fpm/fpm/fpm_php.c | 3 --- 7 files changed, 8 insertions(+), 19 deletions(-) diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index a1050c36e67f9..98fdc3b36cfac 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -22,6 +22,7 @@ #include +#include #include "zend_globals_macros.h" @@ -269,6 +270,7 @@ struct _zend_executor_globals { #ifdef ZEND_TIMERS timer_t timer; + pid_t pid; struct sigaction oldact; #endif diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c index d0bdeb877d897..2ce9c811f255a 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timer.c @@ -47,6 +47,7 @@ ZEND_API void zend_timer_init(void) /* {{{ */ sev.sigev_signo = SIGIO; sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); + EG(pid) = getpid(); // Measure wall time instead of CPU time as originally planned now that it is possible https://github.com/php/php-src/pull/6504#issuecomment-1370303727 if (timer_create(CLOCK_REALTIME, &sev, &EG(timer)) != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not create timer"); @@ -80,6 +81,11 @@ void zend_timer_settime(zend_long seconds) /* {{{ }*/ void zend_timer_shutdown(void) /* {{{ */ { + /* Don't try to delete a timer created before a call to fork() */ + if (EG(pid) != getpid()) { + return; + } + timer_t timer = EG(timer); if (timer == (timer_t){0}) { /* Don't trigger an error here because the timer may not be initialized when PHP fail early, and on threads created by PHP but not managed by it. */ diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index a7047fb0f8407..a912b5e604bb5 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -4693,8 +4693,6 @@ static int accel_finish_startup(void) zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid); exit(1); } - zend_timer_init(); - in_child = 1; } else { /* parent */ int status; diff --git a/sapi/apache2handler/sapi_apache2.c b/sapi/apache2handler/sapi_apache2.c index 06ae2ff8afdbc..959348484c59f 100644 --- a/sapi/apache2handler/sapi_apache2.c +++ b/sapi/apache2handler/sapi_apache2.c @@ -753,13 +753,6 @@ static void php_apache_signal_init(apr_pool_t *pchild, server_rec *s) } #endif -#ifdef ZEND_TIMERS -static void php_apache_timers_init(apr_pool_t *pchild, server_rec *s) -{ - zend_timer_init(); -} -#endif - void php_ap2_register_hook(apr_pool_t *p) { ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE); @@ -767,9 +760,6 @@ void php_ap2_register_hook(apr_pool_t *p) ap_hook_handler(php_handler, NULL, NULL, APR_HOOK_MIDDLE); #ifdef ZEND_SIGNALS ap_hook_child_init(php_apache_signal_init, NULL, NULL, APR_HOOK_MIDDLE); -#endif -#ifdef ZEND_TIMERS - ap_hook_child_init(php_apache_timers_init, NULL, NULL, APR_HOOK_MIDDLE); #endif ap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE); } diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 77adbb9ae689a..499a7932bed17 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -2053,7 +2053,6 @@ consult the installation file that came with this distribution, or visit \n\ sigaction(SIGQUIT, &old_quit, 0); sigaction(SIGINT, &old_int, 0); zend_signal_init(); - zend_timer_init(); break; case -1: perror("php (pre-forking)"); diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 33660ab212646..626c58fcc2457 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -64,7 +64,6 @@ #include "zend_execute.h" #include "zend_highlight.h" #include "zend_exceptions.h" -#include "zend_timer.h" #include "php_getopt.h" @@ -2401,8 +2400,6 @@ static void php_cli_server_startup_workers(void) { } else if (pid == SUCCESS) { return; } else { - zend_timer_init(); - php_cli_server_workers[php_cli_server_worker] = pid; } } diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c index 5942432a622e4..92b189668206e 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -11,8 +11,6 @@ #include "php_ini.h" #include "ext/standard/dl.h" -#include "zend_timer.h" - #include "fastcgi.h" #include "fpm.h" @@ -216,7 +214,6 @@ int fpm_php_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ 0 > fpm_php_set_allowed_clients(wp)) { return -1; } - zend_timer_init(); if (wp->limit_extensions) { /* Take ownership of limit_extensions. */ From f1182d064abf21f1c0058325b0c65e002ae0ce4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 30 Jan 2023 21:51:55 +0100 Subject: [PATCH 30/36] fix review --- Zend/zend.c | 10 +--------- Zend/zend_execute_API.c | 1 + 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index 8a094e1268651..cf23adee83913 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -825,14 +825,6 @@ static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ zend_timer_init(); } /* }}} */ - -static void zend_thread_shutdown_handler(void) { /* {{{ */ - zend_interned_strings_dtor(); -#ifdef ZEND_TIMERS - zend_timer_shutdown(); -#endif -} -/* }}} */ #endif #if defined(__FreeBSD__) || defined(__DragonFly__) @@ -1036,7 +1028,7 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */ #ifdef ZTS tsrm_set_new_thread_end_handler(zend_new_thread_end_handler); - tsrm_set_shutdown_handler(zend_thread_shutdown_handler); + tsrm_set_shutdown_handler(zend_interned_strings_dtor); #endif } /* }}} */ diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 96f6563b78670..3f9eff6f18013 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -407,6 +407,7 @@ void shutdown_executor(void) /* {{{ */ zend_shutdown_executor_values(fast_shutdown); zend_weakrefs_shutdown(); + zend_timer_shutdown(); zend_fiber_shutdown(); zend_try { From 11e5ab64ca4ac3e80acd77a397f2c7d8e5ea2567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 31 Jan 2023 11:58:08 +0100 Subject: [PATCH 31/36] fix tests --- Zend/zend_timer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c index 2ce9c811f255a..818bcea75bfc8 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timer.c @@ -65,6 +65,11 @@ void zend_timer_settime(zend_long seconds) /* {{{ }*/ { timer_t timer = EG(timer); + /* Timer doesn't anymore on request shutdown. */ + if (timer == (timer_t){0}) { + return; + } + struct itimerspec its; its.it_value.tv_sec = seconds; its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; From 9e6b557aa100f1f44a6b892222fc19502eb3fb30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 8 Feb 2023 17:33:11 +0100 Subject: [PATCH 32/36] feat: use CLOCK_BOOTTIME --- Zend/zend_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c index 818bcea75bfc8..5dc089965eba3 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timer.c @@ -49,7 +49,7 @@ ZEND_API void zend_timer_init(void) /* {{{ */ EG(pid) = getpid(); // Measure wall time instead of CPU time as originally planned now that it is possible https://github.com/php/php-src/pull/6504#issuecomment-1370303727 - if (timer_create(CLOCK_REALTIME, &sev, &EG(timer)) != 0) { + if (timer_create(CLOCK_BOOTTIME, &sev, &EG(timer)) != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not create timer"); } From c6675d871817bad2b202c1f4cf4483ecd8400519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 8 Feb 2023 18:00:23 +0100 Subject: [PATCH 33/36] feat: use real-time signal --- Zend/zend_execute_API.c | 6 +++--- Zend/zend_timer.c | 8 +------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 3f9eff6f18013..020626029c8c4 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1324,7 +1324,7 @@ static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ { if (si->si_value.sival_ptr != &EG(timer)) { #ifdef TIMER_DEBUG - fprintf(stderr, "Executing previous handler (if set) for unexpected signal SIGIO received on thread %d\n", (pid_t) syscall(SYS_gettid)); + fprintf(stderr, "Executing previous handler (if set) for unexpected signal SIGRTMIN received on thread %d\n", (pid_t) syscall(SYS_gettid)); #endif if (EG(oldact).sa_sigaction) { @@ -1449,9 +1449,9 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ act.sa_sigaction = zend_timeout_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_ONSTACK | SA_SIGINFO; - sigaction(SIGIO, &act, NULL); + sigaction(SIGRTMIN, &act, NULL); sigemptyset(&sigset); - sigaddset(&sigset, SIGIO); + sigaddset(&sigset, SIGRTMIN); sigprocmask(SIG_UNBLOCK, &sigset, NULL); } #elif defined(HAVE_SETITIMER) diff --git a/Zend/zend_timer.c b/Zend/zend_timer.c index 5dc089965eba3..9a7ac5ca2fcb7 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_timer.c @@ -38,13 +38,7 @@ ZEND_API void zend_timer_init(void) /* {{{ */ struct sigevent sev; sev.sigev_notify = SIGEV_THREAD_ID; sev.sigev_value.sival_ptr = &EG(timer); - // The chosen signal must: - // 1. not be used internally by libc - // 2. be allowed to happen spuriously without consequences - // 3. not be commonly used by applications, this excludes SIGALRM, SIGUSR1 and SIGUSR2 - // 4. not be used by profilers, this excludes SIGPROF - // 5. not be used internally by runtimes of programs that can embed PHP, this excludes SIGURG, which is used by Go - sev.sigev_signo = SIGIO; + sev.sigev_signo = SIGRTMIN; sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); EG(pid) = getpid(); From b96ef6a8c300800a48211e552fa653bb8ea2f676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 21 Feb 2023 00:53:47 +0100 Subject: [PATCH 34/36] rename --- Zend/Zend.m4 | 26 ++++++++--------- Zend/zend.c | 4 +-- Zend/zend.h | 2 +- Zend/zend_execute_API.c | 20 ++++++------- Zend/zend_globals.h | 6 ++-- ...end_timer.c => zend_max_execution_timer.c} | 28 +++++++++---------- ...end_timer.h => zend_max_execution_timer.h} | 18 ++++++------ configure.ac | 2 +- ext/pcntl/pcntl.c | 4 +-- ext/standard/info.c | 6 ++-- .../tests/general_functions/phpinfo.phpt | 2 +- 11 files changed, 59 insertions(+), 59 deletions(-) rename Zend/{zend_timer.c => zend_max_execution_timer.c} (81%) rename Zend/{zend_timer.h => zend_max_execution_timer.h} (73%) diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index 26dbcb57626cf..3d75f76018fe8 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -269,27 +269,27 @@ fi AC_MSG_CHECKING(whether to enable zend signal handling) AC_MSG_RESULT($ZEND_SIGNALS) -dnl By default, enable Zend Timers only for ZTS builds -AC_ARG_ENABLE([zend-timer], - [AS_HELP_STRING([--enable-zend-timer], - [whether to enable zend timer])], - [ZEND_TIMERS=$enableval], - [ZEND_TIMERS=$ZEND_ZTS]) +dnl By default, enable Zend Max Execution Timers only for ZTS builds +AC_ARG_ENABLE([zend-max-execution-timers], + [AS_HELP_STRING([--enable-zend-max-execution-timers], + [whether to enable zend max execution timers])], + [ZEND_MAX_EXECUTION_TIMERS=$enableval], + [ZEND_MAX_EXECUTION_TIMERS=$ZEND_ZTS]) -AS_CASE(["$host_alias"], [*linux*], [], [ZEND_TIMERS='no']) +AS_CASE(["$host_alias"], [*linux*], [], [ZEND_MAX_EXECUTION_TIMERS='no']) PHP_CHECK_FUNC(timer_create, rt) if test "$ac_cv_func_timer_create" != "yes"; then - ZEND_TIMERS='no' + ZEND_MAX_EXECUTION_TIMERS='no' fi -if test "$ZEND_TIMERS" = "yes"; then - AC_DEFINE(ZEND_TIMERS, 1, [Use zend timer]) - CFLAGS="$CFLAGS -DZEND_TIMERS" +if test "$ZEND_MAX_EXECUTION_TIMERS" = "yes"; then + AC_DEFINE(ZEND_MAX_EXECUTION_TIMERS, 1, [Use zend max execution timers]) + CFLAGS="$CFLAGS -DZEND_MAX_EXECUTION_TIMERS" fi -AC_MSG_CHECKING(whether to enable zend timer) -AC_MSG_RESULT($ZEND_TIMERS) +AC_MSG_CHECKING(whether to enable zend max execution timers) +AC_MSG_RESULT($ZEND_MAX_EXECUTION_TIMERS) ]) diff --git a/Zend/zend.c b/Zend/zend.c index cf23adee83913..aa93a68604e89 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -35,7 +35,7 @@ #include "zend_attributes.h" #include "zend_observer.h" #include "zend_fibers.h" -#include "zend_timer.h" +#include "zend_max_execution_timer.h" #include "Optimizer/zend_optimizer.h" static size_t global_map_ptr_last = 0; @@ -822,7 +822,7 @@ static void zend_new_thread_end_handler(THREAD_T thread_id) /* {{{ */ { zend_copy_ini_directives(); zend_ini_refresh_caches(ZEND_INI_STAGE_STARTUP); - zend_timer_init(); + zend_max_execution_timer_init(); } /* }}} */ #endif diff --git a/Zend/zend.h b/Zend/zend.h index db40fcd9fc13d..0b054b6477a53 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -39,7 +39,7 @@ #include "zend_smart_str_public.h" #include "zend_smart_string_public.h" #include "zend_signal.h" -#include "zend_timer.h" +#include "zend_max_execution_timer.h" #define zend_sprintf sprintf diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 020626029c8c4..a85a11e77308c 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -43,7 +43,7 @@ #ifdef HAVE_UNISTD_H #include #endif -#ifdef ZEND_TIMERS +#ifdef ZEND_MAX_EXECUTION_TIMERS #include #endif @@ -195,7 +195,7 @@ void init_executor(void) /* {{{ */ EG(num_errors) = 0; EG(errors) = NULL; - zend_timer_init(); + zend_max_execution_timer_init(); zend_fiber_init(); zend_weakrefs_init(); @@ -407,7 +407,7 @@ void shutdown_executor(void) /* {{{ */ zend_shutdown_executor_values(fast_shutdown); zend_weakrefs_shutdown(); - zend_timer_shutdown(); + zend_max_execution_timer_shutdown(); zend_fiber_shutdown(); zend_try { @@ -1319,11 +1319,11 @@ ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */ /* }}} */ #ifndef ZEND_WIN32 -# ifdef ZEND_TIMERS +# ifdef ZEND_MAX_EXECUTION_TIMERS static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */ { - if (si->si_value.sival_ptr != &EG(timer)) { -#ifdef TIMER_DEBUG + if (si->si_value.sival_ptr != &EG(max_execution_timer_timer)) { +#ifdef MAX_EXECUTION_TIMERS_DEBUG fprintf(stderr, "Executing previous handler (if set) for unexpected signal SIGRTMIN received on thread %d\n", (pid_t) syscall(SYS_gettid)); #endif @@ -1439,8 +1439,8 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ zend_error_noreturn(E_ERROR, "Could not queue new timer"); return; } -#elif defined(ZEND_TIMERS) - zend_timer_settime(seconds); +#elif defined(ZEND_MAX_EXECUTION_TIMERS) + zend_max_execution_timer_settime(seconds); if (reset_signals) { sigset_t sigset; @@ -1519,8 +1519,8 @@ void zend_unset_timeout(void) /* {{{ */ } tq_timer = NULL; } -#elif ZEND_TIMERS - zend_timer_settime(0); +#elif ZEND_MAX_EXECUTION_TIMERS + zend_max_execution_timer_settime(0); #elif defined(HAVE_SETITIMER) if (EG(timeout_seconds)) { struct itimerval no_timeout; diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 98fdc3b36cfac..4612198b44ca5 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -37,7 +37,7 @@ #include "zend_multibyte.h" #include "zend_multiply.h" #include "zend_arena.h" -#include "zend_timer.h" +#include "zend_max_execution_timer.h" /* Define ZTS if you want a thread-safe Zend */ /*#undef ZTS*/ @@ -268,8 +268,8 @@ struct _zend_executor_globals { uint32_t num_errors; zend_error_info **errors; -#ifdef ZEND_TIMERS - timer_t timer; +#ifdef ZEND_MAX_EXECUTION_TIMERS + timer_t max_execution_timer_timer; pid_t pid; struct sigaction oldact; #endif diff --git a/Zend/zend_timer.c b/Zend/zend_max_execution_timer.c similarity index 81% rename from Zend/zend_timer.c rename to Zend/zend_max_execution_timer.c index 9a7ac5ca2fcb7..642974851a4a3 100644 --- a/Zend/zend_timer.c +++ b/Zend/zend_max_execution_timer.c @@ -14,7 +14,7 @@ +----------------------------------------------------------------------+ */ -#ifdef ZEND_TIMERS +#ifdef ZEND_MAX_EXECUTION_TIMERS #include #include @@ -33,31 +33,31 @@ # define sigev_notify_thread_id _sigev_un._tid # endif -ZEND_API void zend_timer_init(void) /* {{{ */ +ZEND_API void zend_max_execution_timer_init(void) /* {{{ */ { struct sigevent sev; sev.sigev_notify = SIGEV_THREAD_ID; - sev.sigev_value.sival_ptr = &EG(timer); + sev.sigev_value.sival_ptr = &EG(max_execution_timer_timer); sev.sigev_signo = SIGRTMIN; sev.sigev_notify_thread_id = (pid_t) syscall(SYS_gettid); EG(pid) = getpid(); // Measure wall time instead of CPU time as originally planned now that it is possible https://github.com/php/php-src/pull/6504#issuecomment-1370303727 - if (timer_create(CLOCK_BOOTTIME, &sev, &EG(timer)) != 0) { + if (timer_create(CLOCK_BOOTTIME, &sev, &EG(max_execution_timer_timer)) != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not create timer"); } -# ifdef TIMER_DEBUG - fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(timer), sev.sigev_notify_thread_id); +# ifdef MAX_EXECUTION_TIMERS_DEBUG + fprintf(stderr, "Timer %#jx created on thread %d\n", (uintmax_t) EG(max_execution_timer_timer), sev.sigev_notify_thread_id); # endif sigaction(sev.sigev_signo, NULL, &EG(oldact)); } /* }}} */ -void zend_timer_settime(zend_long seconds) /* {{{ }*/ +void zend_max_execution_timer_settime(zend_long seconds) /* {{{ }*/ { - timer_t timer = EG(timer); + timer_t timer = EG(max_execution_timer_timer); /* Timer doesn't anymore on request shutdown. */ if (timer == (timer_t){0}) { @@ -68,7 +68,7 @@ void zend_timer_settime(zend_long seconds) /* {{{ }*/ its.it_value.tv_sec = seconds; its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; -# ifdef TIMER_DEBUG +# ifdef MAX_EXECUTION_TIMERS_DEBUG fprintf(stderr, "Setting timer %#jx on thread %d (%ld seconds)...\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid), seconds); # endif @@ -78,29 +78,29 @@ void zend_timer_settime(zend_long seconds) /* {{{ }*/ } /* }}} */ -void zend_timer_shutdown(void) /* {{{ */ +void zend_max_execution_timer_shutdown(void) /* {{{ */ { /* Don't try to delete a timer created before a call to fork() */ if (EG(pid) != getpid()) { return; } - timer_t timer = EG(timer); + timer_t timer = EG(max_execution_timer_timer); if (timer == (timer_t){0}) { /* Don't trigger an error here because the timer may not be initialized when PHP fail early, and on threads created by PHP but not managed by it. */ -# ifdef TIMER_DEBUG +# ifdef MAX_EXECUTION_TIMERS_DEBUG fprintf(stderr, "Could not delete timer that has not been created on thread %d\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); # endif return; } -# ifdef TIMER_DEBUG +# ifdef MAX_EXECUTION_TIMERS_DEBUG fprintf(stderr, "Deleting timer %#jx on thread %d...\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); # endif int err = timer_delete(timer); - EG(timer) = (timer_t){0}; + EG(max_execution_timer_timer) = (timer_t){0}; if (err != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer"); } diff --git a/Zend/zend_timer.h b/Zend/zend_max_execution_timer.h similarity index 73% rename from Zend/zend_timer.h rename to Zend/zend_max_execution_timer.h index 9b07faf9f3910..789f50e6b7dcd 100644 --- a/Zend/zend_timer.h +++ b/Zend/zend_max_execution_timer.h @@ -14,23 +14,23 @@ +----------------------------------------------------------------------+ */ -#ifndef ZEND_TIMER_H -#define ZEND_TIMER_H +#ifndef ZEND_MAX_EXECUTION_TIMER_H +#define ZEND_MAX_EXECUTION_TIMER_H -# ifdef ZEND_TIMERS +# ifdef ZEND_MAX_EXECUTION_TIMERS #include "zend_long.h" /* Must be called after calls to fork() */ -ZEND_API void zend_timer_init(void); -void zend_timer_settime(zend_long seconds); -void zend_timer_shutdown(void); +ZEND_API void zend_max_execution_timer_init(void); +void zend_max_execution_timer_settime(zend_long seconds); +void zend_max_execution_timer_shutdown(void); # else -#define zend_timer_init() -#define zend_timer_settime(seconds) -#define zend_timer_shutdown() +#define zend_max_execution_timer_init() +#define zend_max_execution_timer_settime(seconds) +#define zend_max_execution_timer_shutdown() # endif #endif diff --git a/configure.ac b/configure.ac index 749a86cfc00d9..197c49a5fcfb0 100644 --- a/configure.ac +++ b/configure.ac @@ -1634,7 +1634,7 @@ PHP_ADD_SOURCES(Zend, \ zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \ zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \ - zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_timer.c \ + zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_max_execution_timer.c \ Optimizer/zend_optimizer.c \ Optimizer/pass1.c \ Optimizer/pass3.c \ diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 5c0d08528d86d..c691d32239e36 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -50,7 +50,7 @@ # define NSIG 32 #endif -#include "Zend/zend_timer.h" +#include "Zend/zend_max_execution_timer.h" ZEND_DECLARE_MODULE_GLOBALS(pcntl) static PHP_GINIT_FUNCTION(pcntl); @@ -534,7 +534,7 @@ PHP_FUNCTION(pcntl_fork) PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error %d", errno); } else if (id == 0) { - zend_timer_init(); + zend_max_execution_timer_init(); } RETURN_LONG((zend_long) id); diff --git a/ext/standard/info.c b/ext/standard/info.c index 192a7acf27565..58e2eee6d49cb 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -891,10 +891,10 @@ PHPAPI ZEND_COLD void php_print_info(int flag) efree(descr); } -#ifdef ZEND_TIMERS - php_info_print_table_row(2, "Zend Timers", "enabled" ); +#ifdef ZEND_MAX_EXECUTION_TIMERS + php_info_print_table_row(2, "Zend Max Execution Timers", "enabled" ); #else - php_info_print_table_row(2, "Zend Timers", "disabled" ); + php_info_print_table_row(2, "Zend Max Execution Timers", "disabled" ); #endif #if HAVE_IPV6 diff --git a/ext/standard/tests/general_functions/phpinfo.phpt b/ext/standard/tests/general_functions/phpinfo.phpt index bd66a26606b9d..57ba13bb7bf7c 100644 --- a/ext/standard/tests/general_functions/phpinfo.phpt +++ b/ext/standard/tests/general_functions/phpinfo.phpt @@ -34,7 +34,7 @@ Thread Safety => %s%A Zend Signal Handling => %s Zend Memory Manager => %s Zend Multibyte Support => %s -Zend Timers => %s +Zend Max Execution Timers => %s IPv6 Support => %s DTrace Support => %s From c172e8d2399628d17d303a1016259e8261cf1dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 24 Feb 2023 17:06:28 +0100 Subject: [PATCH 35/36] arnaud's patch --- Zend/zend.c | 4 ++++ Zend/zend_max_execution_timer.c | 19 ++++++------------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index aa93a68604e89..bd2a04e2ba9d8 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -801,6 +801,10 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{ executor_globals->record_errors = false; executor_globals->num_errors = 0; executor_globals->errors = NULL; +#ifdef ZEND_MAX_EXECUTION_TIMERS + executor_globals->pid = 0; + executor_globals->oldact = (struct sigaction){0}; +#endif } /* }}} */ diff --git a/Zend/zend_max_execution_timer.c b/Zend/zend_max_execution_timer.c index 642974851a4a3..b1c83e9cbb3a6 100644 --- a/Zend/zend_max_execution_timer.c +++ b/Zend/zend_max_execution_timer.c @@ -57,13 +57,13 @@ ZEND_API void zend_max_execution_timer_init(void) /* {{{ */ void zend_max_execution_timer_settime(zend_long seconds) /* {{{ }*/ { - timer_t timer = EG(max_execution_timer_timer); - - /* Timer doesn't anymore on request shutdown. */ - if (timer == (timer_t){0}) { + /* Timer not initialized or shutdown. */ + if (!EG(pid)) { return; } + timer_t timer = EG(max_execution_timer_timer); + struct itimerspec its; its.it_value.tv_sec = seconds; its.it_value.tv_nsec = its.it_interval.tv_sec = its.it_interval.tv_nsec = 0; @@ -85,22 +85,15 @@ void zend_max_execution_timer_shutdown(void) /* {{{ */ return; } - timer_t timer = EG(max_execution_timer_timer); - if (timer == (timer_t){0}) { - /* Don't trigger an error here because the timer may not be initialized when PHP fail early, and on threads created by PHP but not managed by it. */ -# ifdef MAX_EXECUTION_TIMERS_DEBUG - fprintf(stderr, "Could not delete timer that has not been created on thread %d\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); -# endif + EG(pid) = 0; - return; - } + timer_t timer = EG(max_execution_timer_timer); # ifdef MAX_EXECUTION_TIMERS_DEBUG fprintf(stderr, "Deleting timer %#jx on thread %d...\n", (uintmax_t) timer, (pid_t) syscall(SYS_gettid)); # endif int err = timer_delete(timer); - EG(max_execution_timer_timer) = (timer_t){0}; if (err != 0) { zend_strerror_noreturn(E_ERROR, errno, "Could not delete timer"); } From fdcd57e79386b462ed994eb578d7eea1a8691f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sat, 25 Feb 2023 16:26:58 +0100 Subject: [PATCH 36/36] disable max execution timers by default --- Zend/Zend.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index 3d75f76018fe8..475355a78db13 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -269,12 +269,12 @@ fi AC_MSG_CHECKING(whether to enable zend signal handling) AC_MSG_RESULT($ZEND_SIGNALS) -dnl By default, enable Zend Max Execution Timers only for ZTS builds +dnl Don't enable Zend Max Execution Timers by default until PHP 8.3 to not break the ABI AC_ARG_ENABLE([zend-max-execution-timers], [AS_HELP_STRING([--enable-zend-max-execution-timers], [whether to enable zend max execution timers])], [ZEND_MAX_EXECUTION_TIMERS=$enableval], - [ZEND_MAX_EXECUTION_TIMERS=$ZEND_ZTS]) + [ZEND_MAX_EXECUTION_TIMERS='no']) AS_CASE(["$host_alias"], [*linux*], [], [ZEND_MAX_EXECUTION_TIMERS='no'])