Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 55 additions & 0 deletions Zend/zend_time.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
+----------------------------------------------------------------------+
| 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 <marc@mabe.berlin> |
+----------------------------------------------------------------------+
*/

#include "zend_time.h"

/* Current real/wall-time in seconds */
ZEND_API time_t zend_time_real_sec(void) {
return time(NULL);
}

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
}
95 changes: 95 additions & 0 deletions Zend/zend_time.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
+----------------------------------------------------------------------+
| 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 <marc@mabe.berlin> |
+----------------------------------------------------------------------+
*/

#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 <sys/time.h>
#endif
#include <time.h>

#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_MILLI_IN_SEC 1000U
#define ZEND_MICRO_IN_SEC 1000000U
Comment on lines +40 to +41
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define ZEND_MILLI_IN_SEC 1000U
#define ZEND_MICRO_IN_SEC 1000000U
#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_MICRO_IN_SEC);
tv->tv_usec = (tv_usec_t) (usec % ZEND_MICRO_IN_SEC);

if (UNEXPECTED(tv->tv_usec < 0)) {
tv->tv_usec += ZEND_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_MICRO_IN_SEC);

if (UNEXPECTED(tv->tv_usec < 0)) {
tv->tv_usec += ZEND_MICRO_IN_SEC;
tv->tv_sec -= 1;
} else if (UNEXPECTED(tv->tv_usec >= ZEND_MICRO_IN_SEC)) {
// rare, but protects against rounding up to exactly 1 second
tv->tv_usec -= ZEND_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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking the tv by value and ts by pointer looks odd. Personally I find taking and returning by value more convenient, so I wonder if we should just do this for all the APIs:

Suggested change
static zend_always_inline void zend_time_val2spec(struct timeval tv, struct timespec *ts) {
static zend_always_inline struct timespec zend_time_val2spec(struct timeval tv) {

On Linux both struct timespec and struct timeval are 16 bytes, thus they can be passed and returned in a register pair.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is also specifically intended for the other reviewers to discuss.

ts->tv_sec = (time_t) tv.tv_sec;
ts->tv_nsec = (long) (tv.tv_usec * 1000);
}

/* Current real/wall-time in seconds */
ZEND_API time_t zend_time_real_sec(void);

/* 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
3 changes: 3 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ AC_CHECK_FUNCS(m4_normalize([
asctime_r
asprintf
chroot
clock_gettime
ctime_r
explicit_memset
fdatasync
Expand Down Expand Up @@ -591,6 +592,7 @@ AC_CHECK_FUNCS(m4_normalize([
strptime
strtok_r
symlink
timespec_get
tzset
unsetenv
usleep
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion win32/build/config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
1 change: 1 addition & 0 deletions win32/build/config.w32.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading