diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index ccdba855ec52..1896c76a0b2d 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -74,6 +74,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES longer is a pointer, but a directly embedded HashTable struct. . Added a C23_ENUM() helper macro to define forward-compatible fixed-size enums. + . Introduced a new time-retrieval API zend_time_*. ======================== 2. Build system changes diff --git a/Zend/zend_time.c b/Zend/zend_time.c new file mode 100644 index 000000000000..5ef1c5a3ac8f --- /dev/null +++ b/Zend/zend_time.c @@ -0,0 +1,50 @@ +/* + +----------------------------------------------------------------------+ + | 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: Marc Bennewitz | + +----------------------------------------------------------------------+ +*/ + +#include "zend_time.h" + +ZEND_API void zend_time_real_spec(struct timespec *ts) { +#if defined(HAVE_CLOCK_GETTIME) + + (void) clock_gettime(CLOCK_REALTIME, ts); + +#elif defined(HAVE_TIMESPEC_GET) + + (void) timespec_get(ts, TIME_UTC); + +#elif defined(HAVE_GETTIMEOFDAY) + + struct timeval tv; + (void) gettimeofday(&tv, NULL); + zend_time_val2spec(tv, ts); + +#else + + ts->tv_sec = zend_time_real_get(); + ts->tv_nsec = 0; + +#endif +} + +ZEND_API uint64_t zend_time_mono_fallback_nsec(void) { +#if ZEND_HRTIME_AVAILABLE + return (uint64_t)zend_hrtime(); +#else + struct timespec ts; + zend_time_real_spec(&ts); + return ((uint64_t) ts.tv_sec * ZEND_NANO_IN_SEC) + ts.tv_nsec; +#endif +} diff --git a/Zend/zend_time.h b/Zend/zend_time.h new file mode 100644 index 000000000000..58dbac44088d --- /dev/null +++ b/Zend/zend_time.h @@ -0,0 +1,97 @@ +/* + +----------------------------------------------------------------------+ + | 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: Marc Bennewitz | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_TIME_H +#define ZEND_TIME_H + +#include "zend_portability.h" + +#ifdef PHP_WIN32 +# include "win32/time.h" +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include + +#include "zend_hrtime.h" + +#ifndef PHP_WIN32 +# define tv_sec_t time_t +# define tv_usec_t suseconds_t +#else +# define tv_sec_t long +# define tv_usec_t long +#endif + +#define ZEND_TIME_MILLI_IN_SEC 1000U +#define ZEND_TIME_MICRO_IN_SEC 1000000U + +BEGIN_EXTERN_C() + +/* Assign seconds to timeval */ +static zend_always_inline void zend_time_sec2val(time_t s, struct timeval *tv) { + tv->tv_sec = (tv_sec_t) s; + tv->tv_usec = 0; +} + +/* Assign microseconds to timeval */ +static zend_always_inline void zend_time_usec2val(int64_t usec, struct timeval *tv) { + tv->tv_sec = (tv_sec_t) (usec / ZEND_TIME_MICRO_IN_SEC); + tv->tv_usec = (tv_usec_t) (usec % ZEND_TIME_MICRO_IN_SEC); + + if (UNEXPECTED(tv->tv_usec < 0)) { + tv->tv_usec += ZEND_TIME_MICRO_IN_SEC; + tv->tv_sec -= 1; + } +} + +/* Assign double (seconds) to timeval */ +static zend_always_inline void zend_time_dbl2val(double s, struct timeval *tv) { + tv->tv_sec = (tv_sec_t) s; + tv->tv_usec = (tv_usec_t) ((s - tv->tv_sec) * ZEND_TIME_MICRO_IN_SEC); + + if (UNEXPECTED(tv->tv_usec < 0)) { + tv->tv_usec += ZEND_TIME_MICRO_IN_SEC; + tv->tv_sec -= 1; + } else if (UNEXPECTED(tv->tv_usec >= ZEND_TIME_MICRO_IN_SEC)) { + // rare, but protects against rounding up to exactly 1 second + tv->tv_usec -= ZEND_TIME_MICRO_IN_SEC; + tv->tv_sec += 1; + } +} + +/* Assign timeval to timespec */ +static zend_always_inline void zend_time_val2spec(struct timeval tv, struct timespec *ts) { + ts->tv_sec = (time_t) tv.tv_sec; + ts->tv_nsec = (long) (tv.tv_usec * 1000); +} + +/* Current real/wall-time in seconds */ +static zend_always_inline time_t zend_time_real_sec(void) { + return time(NULL); +} + +/* Current real/wall-time in up-to nano seconds */ +ZEND_API void zend_time_real_spec(struct timespec *ts); + +/* Monotonic time in nanoseconds with a fallback to real/wall-time + if no monotonic timer is available */ +ZEND_API uint64_t zend_time_mono_fallback_nsec(void); + +END_EXTERN_C() + +#endif // ZEND_TIME_H diff --git a/configure.ac b/configure.ac index 07d64902ebf0..7f9e2da959a6 100644 --- a/configure.ac +++ b/configure.ac @@ -540,6 +540,7 @@ AC_CHECK_FUNCS(m4_normalize([ asctime_r asprintf chroot + clock_gettime ctime_r explicit_memset fdatasync @@ -591,6 +592,7 @@ AC_CHECK_FUNCS(m4_normalize([ strptime strtok_r symlink + timespec_get tzset unsetenv usleep @@ -1760,6 +1762,7 @@ PHP_ADD_SOURCES([Zend], m4_normalize([ zend_generators.c zend_hash.c zend_highlight.c + zend_time.c zend_hrtime.c zend_inheritance.c zend_ini_parser.c diff --git a/win32/build/config.w32 b/win32/build/config.w32 index aefcfb5f8247..33acc3eea7bf 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -240,7 +240,7 @@ ADD_SOURCES("Zend", "zend_language_parser.c zend_language_scanner.c \ zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c zend_weakrefs.c \ zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c zend_ast.c \ zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_observer.c zend_system_id.c \ - zend_enum.c zend_fibers.c zend_atomic.c zend_hrtime.c zend_frameless_function.c zend_property_hooks.c \ + zend_enum.c zend_fibers.c zend_atomic.c zend_time.c zend_hrtime.c zend_frameless_function.c zend_property_hooks.c \ zend_lazy_objects.c zend_autoload.c"); ADD_SOURCES("Zend\\Optimizer", "zend_optimizer.c pass1.c pass3.c optimize_func_calls.c block_pass.c optimize_temp_vars_5.c nop_removal.c compact_literals.c zend_cfg.c zend_dfg.c dfa_pass.c zend_ssa.c zend_inference.c zend_func_info.c zend_call_graph.c zend_dump.c escape_analysis.c compact_vars.c dce.c sccp.c scdf.c"); diff --git a/win32/build/config.w32.h.in b/win32/build/config.w32.h.in index 7b1bb4d932d3..fff0206db1c0 100644 --- a/win32/build/config.w32.h.in +++ b/win32/build/config.w32.h.in @@ -48,6 +48,7 @@ #undef HAVE_SETITIMER #undef HAVE_IODBC #define HAVE_LIBDL 1 +#define HAVE_TIMESPEC_GET 1 #define HAVE_GETTIMEOFDAY 1 #define HAVE_PUTENV 1 #define HAVE_TZSET 1