diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 56131e72ea4d..be4471c75f0a 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -1449,6 +1449,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_http_response_code, 0, 0, 0) ZEND_ARG_INFO(0, response_code) ZEND_END_ARG_INFO() /* }}} */ +/* {{{ hrtime.c */ +#if HRTIME_AVAILABLE +ZEND_BEGIN_ARG_INFO(arginfo_hrtime, 0) +ZEND_END_ARG_INFO() +#endif +/* }}} */ /* {{{ html.c */ ZEND_BEGIN_ARG_INFO_EX(arginfo_htmlspecialchars, 0, 0, 1) ZEND_ARG_INFO(0, string) @@ -2982,6 +2988,10 @@ const zend_function_entry basic_functions[] = { /* {{{ */ PHP_FE(getrusage, arginfo_getrusage) #endif +#if HRTIME_AVAILABLE + PHP_FE(hrtime, arginfo_hrtime) +#endif + #ifdef HAVE_GETTIMEOFDAY PHP_FE(uniqid, arginfo_uniqid) #endif @@ -3708,6 +3718,10 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */ BASIC_MINIT_SUBMODULE(random) +#if HRTIME_AVAILABLE + BASIC_MINIT_SUBMODULE(hrtime) +#endif + return SUCCESS; } /* }}} */ @@ -4040,7 +4054,7 @@ PHP_FUNCTION(long2ip) ********************/ /* {{{ proto string getenv(string varname[, bool local_only] - Get the value of an environment variable or every available environment variable + Get the value of an environment variable or every available environment variable if no varname is present */ PHP_FUNCTION(getenv) { diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 284e74e967ea..c86be26ad199 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -13,14 +13,14 @@ int main(int argc, char **argv) char *filename = tmpnam(NULL); char buffer[64]; int result = 0; - + FILE *fp = fopen(filename, "wb"); if (NULL == fp) return 0; fputs("line 1\n", fp); fputs("line 2\n", fp); fclose(fp); - + fp = fopen(filename, "rb+"); if (NULL == fp) return 0; @@ -58,7 +58,7 @@ if test "$ac_cv_func_crypt" = "no"; then AC_DEFINE(HAVE_CRYPT, 1, [ ]) ]) fi - + AC_CACHE_CHECK(for standard DES crypt, ac_cv_crypt_des,[ AC_TRY_RUN([ #if HAVE_UNISTD_H @@ -124,7 +124,7 @@ int main() { char salt[15], answer[40]; char *encrypted; - salt[0]='$'; salt[1]='1'; salt[2]='$'; + salt[0]='$'; salt[1]='1'; salt[2]='$'; salt[3]='r'; salt[4]='a'; salt[5]='s'; salt[6]='m'; salt[7]='u'; salt[8]='s'; salt[9]='l'; salt[10]='e'; salt[11]='$'; @@ -267,7 +267,7 @@ else AC_DEFINE_UNQUOTED(PHP_USE_PHP_CRYPT_R, 0, [Whether PHP has to use its own crypt_r for blowfish, des and ext des]) fi -dnl +dnl dnl Check for __attribute__ ((__aligned__)) support in the compiler dnl AC_CACHE_CHECK(whether the compiler supports aligned attribute, ac_cv_attribute_aligned,[ @@ -289,7 +289,7 @@ dnl dnl log2 could be used to improve the log function, however it requires C99. The check for log2 should be turned on, dnl as soon as we support C99. AC_CHECK_FUNCS(getcwd getwd asinh acosh atanh log1p hypot glob strfmon nice fpclass mempcpy strpncpy) -AC_FUNC_FNMATCH +AC_FUNC_FNMATCH dnl dnl Check if there is a support means of creating a new process @@ -455,7 +455,7 @@ PHP_NEW_EXTENSION(standard, array.c base64.c basic_functions.c browscap.c crc32. http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ filters.c proc_open.c streamsfuncs.c http.c password.c \ - random.c,,, + random.c hrtime.c,,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_ADD_MAKEFILE_FRAGMENT diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index 00b2166abe87..c81b3393742c 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -31,12 +31,11 @@ EXTENSION("standard", "array.c base64.c basic_functions.c browscap.c \ url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \ php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \ user_filters.c uuencode.c filters.c proc_open.c password.c \ - streamsfuncs.c http.c flock_compat.c random.c", false /* never shared */, + streamsfuncs.c http.c flock_compat.c random.c hrtime.c", false /* never shared */, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); PHP_INSTALL_HEADERS("", "ext/standard"); if (PHP_MBREGEX != "no") { - CHECK_HEADER_ADD_INCLUDE("oniguruma.h", "CFLAGS_STANDARD", PHP_MBREGEX + ";ext\\mbstring\\oniguruma") + CHECK_HEADER_ADD_INCLUDE("oniguruma.h", "CFLAGS_STANDARD", PHP_MBREGEX + ";ext\\mbstring\\oniguruma") } ADD_MAKEFILE_FRAGMENT(); PHP_INSTALL_HEADERS("", "ext/standard"); - diff --git a/ext/standard/hrtime.c b/ext/standard/hrtime.c new file mode 100644 index 000000000000..fb7bbed61cdc --- /dev/null +++ b/ext/standard/hrtime.c @@ -0,0 +1,174 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2017 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: | + | http://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: Niklas Keller | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#include "php.h" +#include "zend_exceptions.h" +#include "hrtime.h" + +#if HRTIME_AVAILABLE + +/* - timer.h ------------------------------------------------------------------------------------ */ +/* The following code is based on: + timer.h - Cross-platform timer library - Public Domain - 2011 Mattias Jansson / Rampant Pixels */ + +#define TIMER_PLATFORM_POSIX 0 +#define TIMER_PLATFORM_WINDOWS 0 +#define TIMER_PLATFORM_APPLE 0 +#define TIMER_PLATFORM_HPUX 0 + +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) && defined(CLOCK_MONOTONIC) + +# undef TIMER_PLATFORM_POSIX +# define TIMER_PLATFORM_POSIX 1 +# include +# include +# include + +#elif defined(_WIN32) || defined(_WIN64) + +# undef TIMER_PLATFORM_WINDOWS +# define TIMER_PLATFORM_WINDOWS 1 +# define WIN32_LEAN_AND_MEAN +# include + +#elif defined(__APPLE__) + +# undef TIMER_PLATFORM_APPLE +# define TIMER_PLATFORM_APPLE 1 +# include +# include +static mach_timebase_info_data_t _timerlib_info; +static void absolutetime_to_nanoseconds (uint64_t mach_time, uint64_t* clock ) { *clock = mach_time * _timerlib_info.numer / _timerlib_info.denom; } + +#elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) + +# undef TIMER_PLATFORM_HPUX +# define TIMER_PLATFORM_HPUX 1 +# include + +#endif + +static uint64_t _timer_freq = 0; + +static int _timer_init() +{ +#if TIMER_PLATFORM_WINDOWS + + uint64_t unused; + if (!QueryPerformanceFrequency((LARGE_INTEGER*) &_timer_freq) || + !QueryPerformanceCounter((LARGE_INTEGER*) &unused)) { + return -1; + } + +#elif TIMER_PLATFORM_APPLE + + if (mach_timebase_info(&_timerlib_info)) { + return -1; + } + _timer_freq = 1000000000ULL; + +#elif TIMER_PLATFORM_POSIX + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) { + return -1; + } + _timer_freq = 1000000000ULL; + +#elif TIMER_PLATFORM_HPUX + + _timer_freq = 1000000000ULL; + +#endif + + return 0; +} + +static uint64_t _timer_current() +{ +#if TIMER_PLATFORM_WINDOWS + + uint64_t curclock; + QueryPerformanceCounter((LARGE_INTEGER*) &curclock); + return curclock; + +#elif TIMER_PLATFORM_APPLE + + uint64_t curclock = 0; + absolutetime_to_nanoseconds(mach_absolute_time(), &curclock); + return curclock; + +#elif TIMER_PLATFORM_POSIX + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) { + return -1; + } + return ((uint64_t) ts.tv_sec * 1000000000ULL) + ts.tv_nsec; + +#elif TIMER_PLATFORM_HPUX + + return (uint64_t) gethrtime(); + +#endif +} + +/* - end of timer.h ----------------------------------------------------------------------------- */ + +/* {{{ */ +PHP_MINIT_FUNCTION(hrtime) +{ + if (_timer_init()) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize internal timer"); + return FAILURE; + } + + return SUCCESS; +} +/* }}} */ + +/* {{{ */ +PHP_MSHUTDOWN_FUNCTION(hrtime) +{ + return SUCCESS; +} +/* }}} */ + +/* {{{ proto float hrtime() + Returns a float containing the current high-resolution time in seconds + counted from an arbitrary point in time */ +PHP_FUNCTION(hrtime) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + uint64_t current_time = _timer_current(); + + if (UNEXPECTED(current_time == -1)) { + zend_throw_exception(zend_ce_error, "Failed to get current system time", 0); + return; + } + + RETURN_DOUBLE((double) current_time / _timer_freq); +} +/* }}} */ + +#endif /* HRTIME_AVAILABLE */ diff --git a/ext/standard/hrtime.h b/ext/standard/hrtime.h new file mode 100644 index 000000000000..7756b46c55c1 --- /dev/null +++ b/ext/standard/hrtime.h @@ -0,0 +1,43 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2017 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: | + | http://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: Niklas Keller | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef HRTIME_H +#define HRTIME_H + +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) && defined(CLOCK_MONOTONIC) +#define HRTIME_AVAILABLE 1 +#elif defined(_WIN32) || defined(_WIN64) +#define HRTIME_AVAILABLE 1 +#elif defined(__APPLE__) +#define HRTIME_AVAILABLE 1 +#elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) +#define HRTIME_AVAILABLE 1 +#else +#define HRTIME_AVAILABLE 0 +#endif + +#if HRTIME_AVAILABLE + PHP_MINIT_FUNCTION(hrtime); + PHP_MSHUTDOWN_FUNCTION(hrtime); + + PHP_FUNCTION(hrtime); +#endif /* HRTIME_AVAILABLE */ + +#endif /* HRTIME_H */ diff --git a/ext/standard/php_standard.h b/ext/standard/php_standard.h index 5b0111f143c3..00e85d075ed9 100644 --- a/ext/standard/php_standard.h +++ b/ext/standard/php_standard.h @@ -27,6 +27,7 @@ #include "php_mail.h" #include "md5.h" #include "sha1.h" +#include "hrtime.h" #include "html.h" #include "exec.h" #include "file.h" diff --git a/ext/standard/tests/hrtime/hrtime.phpt b/ext/standard/tests/hrtime/hrtime.phpt new file mode 100644 index 000000000000..9972be90889c --- /dev/null +++ b/ext/standard/tests/hrtime/hrtime.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test hrtime() aligns with microtime() +--FILE-- + 0.0001) { + print "fail"; +} else { + print "OK"; +} + +?> +--EXPECT-- +OK diff --git a/ext/standard/tests/hrtime/hrtime_error.phpt b/ext/standard/tests/hrtime/hrtime_error.phpt new file mode 100644 index 000000000000..344aa840ea7f --- /dev/null +++ b/ext/standard/tests/hrtime/hrtime_error.phpt @@ -0,0 +1,10 @@ +--TEST-- +Test hrtime() errors +--FILE-- + +--EXPECTF-- +Warning: hrtime() expects exactly 0 parameters, 1 given in %s