|  | 
| 22 | 22 | #include "zend_exceptions.h" | 
| 23 | 23 | #include "hrtime.h" | 
| 24 | 24 | 
 | 
| 25 |  | -#if HRTIME_AVAILABLE | 
| 26 |  | - | 
| 27 |  | -/* - timer.h ------------------------------------------------------------------------------------ */ | 
| 28 |  | -/* The following code is based on: | 
| 29 |  | -   timer.h - Cross-platform timer library - Public Domain - 2011 Mattias Jansson / Rampant Pixels */ | 
|  | 25 | +/* {{{ */ | 
|  | 26 | +/* This file reuses code parts from the cross-platform timer library | 
|  | 27 | +	Public Domain - 2011 Mattias Jansson / Rampant Pixels */ | 
| 30 | 28 | 
 | 
| 31 |  | -#define TIMER_PLATFORM_POSIX   0 | 
| 32 |  | -#define TIMER_PLATFORM_WINDOWS 0 | 
| 33 |  | -#define TIMER_PLATFORM_APPLE   0 | 
| 34 |  | -#define TIMER_PLATFORM_HPUX    0 | 
|  | 29 | +#if PHP_HRTIME_PLATFORM_POSIX | 
| 35 | 30 | 
 | 
| 36 |  | -#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) && defined(CLOCK_MONOTONIC) | 
|  | 31 | +# include <unistd.h> | 
|  | 32 | +# include <time.h> | 
|  | 33 | +# include <string.h> | 
| 37 | 34 | 
 | 
| 38 |  | -#  undef  TIMER_PLATFORM_POSIX | 
| 39 |  | -#  define TIMER_PLATFORM_POSIX 1 | 
| 40 |  | -#  include <unistd.h> | 
| 41 |  | -#  include <time.h> | 
| 42 |  | -#  include <string.h> | 
|  | 35 | +#elif PHP_HRTIME_PLATFORM_WINDOWS | 
| 43 | 36 | 
 | 
| 44 |  | -#elif defined(_WIN32) || defined(_WIN64) | 
|  | 37 | +# define WIN32_LEAN_AND_MEAN | 
|  | 38 | +# include <windows.h> | 
| 45 | 39 | 
 | 
| 46 |  | -#  undef  TIMER_PLATFORM_WINDOWS | 
| 47 |  | -#  define TIMER_PLATFORM_WINDOWS 1 | 
| 48 |  | -#  define WIN32_LEAN_AND_MEAN | 
| 49 |  | -#  include <windows.h> | 
|  | 40 | +static uint64_t _timer_freq = 0; | 
|  | 41 | +static double _timer_int = .0; | 
| 50 | 42 | 
 | 
| 51 |  | -#elif defined(__APPLE__) | 
|  | 43 | +#elif PHP_HRTIME_PLATFORM_APPLE | 
| 52 | 44 | 
 | 
| 53 |  | -#  undef  TIMER_PLATFORM_APPLE | 
| 54 |  | -#  define TIMER_PLATFORM_APPLE 1 | 
| 55 |  | -#  include <mach/mach_time.h> | 
| 56 |  | -#  include <string.h> | 
|  | 45 | +# include <mach/mach_time.h> | 
|  | 46 | +# include <string.h> | 
| 57 | 47 | static mach_timebase_info_data_t _timerlib_info; | 
| 58 |  | -static void absolutetime_to_nanoseconds (uint64_t mach_time, uint64_t* clock ) { *clock = mach_time * _timerlib_info.numer / _timerlib_info.denom; } | 
| 59 | 48 | 
 | 
| 60 |  | -#elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) | 
|  | 49 | +#elif PHP_HRTIME_PLATFORM_HPUX | 
| 61 | 50 | 
 | 
| 62 |  | -#  undef  TIMER_PLATFORM_HPUX | 
| 63 |  | -#  define TIMER_PLATFORM_HPUX 1 | 
| 64 |  | -#  include <sys/time.h> | 
|  | 51 | +# include <sys/time.h> | 
|  | 52 | + | 
|  | 53 | +#elif PHP_HRTIME_PLATFORM_AIX | 
|  | 54 | + | 
|  | 55 | +# include <sys/time.h> | 
|  | 56 | +# include <sys/systemcfg.h> | 
| 65 | 57 | 
 | 
| 66 | 58 | #endif | 
| 67 | 59 | 
 | 
| 68 |  | -static uint64_t _timer_freq = 0; | 
|  | 60 | +#define NANO_IN_SEC 1000000000 | 
|  | 61 | +/* }}} */ | 
| 69 | 62 | 
 | 
| 70 | 63 | static int _timer_init() | 
| 71 |  | -{ | 
| 72 |  | -#if TIMER_PLATFORM_WINDOWS | 
|  | 64 | +{/*{{{*/ | 
|  | 65 | +#if PHP_HRTIME_PLATFORM_WINDOWS | 
| 73 | 66 | 
 | 
| 74 | 67 | 	uint64_t unused; | 
| 75 | 68 | 	if (!QueryPerformanceFrequency((LARGE_INTEGER*) &_timer_freq) || | 
| 76 | 69 | 		!QueryPerformanceCounter((LARGE_INTEGER*) &unused)) { | 
| 77 | 70 | 		return -1; | 
| 78 | 71 | 	} | 
|  | 72 | +	_timer_int = 1.0 / _timer_freq; | 
| 79 | 73 | 
 | 
| 80 |  | -#elif TIMER_PLATFORM_APPLE | 
|  | 74 | +#elif PHP_HRTIME_PLATFORM_APPLE | 
| 81 | 75 | 
 | 
| 82 | 76 | 	if (mach_timebase_info(&_timerlib_info)) { | 
| 83 | 77 | 		return -1; | 
| 84 | 78 | 	} | 
| 85 |  | -	_timer_freq = 1000000000ULL; | 
| 86 | 79 | 
 | 
| 87 |  | -#elif TIMER_PLATFORM_POSIX | 
|  | 80 | +#elif PHP_HRTIME_PLATFORM_POSIX | 
| 88 | 81 | 
 | 
| 89 | 82 | 	struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; | 
|  | 83 | + | 
| 90 | 84 | 	if (clock_gettime(CLOCK_MONOTONIC, &ts)) { | 
| 91 | 85 | 		return -1; | 
| 92 | 86 | 	} | 
| 93 |  | -	_timer_freq = 1000000000ULL; | 
| 94 | 87 | 
 | 
| 95 |  | -#elif TIMER_PLATFORM_HPUX | 
| 96 |  | - | 
| 97 |  | -	_timer_freq = 1000000000ULL; | 
| 98 |  | - | 
| 99 |  | -#endif | 
|  | 88 | +#elif PHP_HRTIME_PLATFORM_HPUX | 
| 100 | 89 | 
 | 
| 101 |  | -	return 0; | 
| 102 |  | -} | 
| 103 |  | - | 
| 104 |  | -static uint64_t _timer_current() | 
| 105 |  | -{ | 
| 106 |  | -#if TIMER_PLATFORM_WINDOWS | 
| 107 |  | - | 
| 108 |  | -	uint64_t curclock; | 
| 109 |  | -	QueryPerformanceCounter((LARGE_INTEGER*) &curclock); | 
| 110 |  | -	return curclock; | 
| 111 |  | - | 
| 112 |  | -#elif TIMER_PLATFORM_APPLE | 
| 113 |  | - | 
| 114 |  | -	uint64_t curclock = 0; | 
| 115 |  | -	absolutetime_to_nanoseconds(mach_absolute_time(), &curclock); | 
| 116 |  | -	return curclock; | 
| 117 |  | - | 
| 118 |  | -#elif TIMER_PLATFORM_POSIX | 
| 119 |  | - | 
| 120 |  | -	struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; | 
| 121 |  | -	if (clock_gettime(CLOCK_MONOTONIC, &ts)) { | 
| 122 |  | -		return -1; | 
| 123 |  | -	} | 
| 124 |  | -	return ((uint64_t) ts.tv_sec * 1000000000ULL) + ts.tv_nsec; | 
|  | 90 | +	/* pass */ | 
| 125 | 91 | 
 | 
| 126 |  | -#elif TIMER_PLATFORM_HPUX | 
|  | 92 | +#elif PHP_HRTIME_PLATFORM_AIX | 
| 127 | 93 | 
 | 
| 128 |  | -	return (uint64_t) gethrtime(); | 
|  | 94 | +	/* pass */ | 
| 129 | 95 | 
 | 
|  | 96 | +#else | 
|  | 97 | +	/* Timer unavailable. */ | 
|  | 98 | +	return -1; | 
| 130 | 99 | #endif | 
| 131 |  | -} | 
| 132 | 100 | 
 | 
| 133 |  | -/* - end of timer.h ----------------------------------------------------------------------------- */ | 
|  | 101 | +	return 0; | 
|  | 102 | +}/*}}}*/ | 
| 134 | 103 | 
 | 
| 135 | 104 | /* {{{ */ | 
| 136 | 105 | PHP_MINIT_FUNCTION(hrtime) | 
| 137 | 106 | { | 
| 138 |  | -	if (_timer_init()) { | 
| 139 |  | -		php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize internal timer"); | 
|  | 107 | +	if (0 > _timer_init()) { | 
|  | 108 | +		php_error_docref(NULL, E_WARNING, "Failed to initialize high-resolution timer"); | 
| 140 | 109 | 		return FAILURE; | 
| 141 | 110 | 	} | 
| 142 | 111 | 
 | 
| 143 | 112 | 	return SUCCESS; | 
| 144 | 113 | } | 
| 145 | 114 | /* }}} */ | 
| 146 | 115 | 
 | 
| 147 |  | -/* {{{ */ | 
| 148 |  | -PHP_MSHUTDOWN_FUNCTION(hrtime) | 
| 149 |  | -{ | 
| 150 |  | -	return SUCCESS; | 
| 151 |  | -} | 
| 152 |  | -/* }}} */ | 
|  | 116 | +static zend_always_inline php_hrtime_t _timer_current(void) | 
|  | 117 | +{/*{{{*/ | 
|  | 118 | +#if PHP_HRTIME_PLATFORM_WINDOWS | 
|  | 119 | +	uint64_t cur; | 
|  | 120 | +	QueryPerformanceCounter((LARGE_INTEGER*) &cur); | 
|  | 121 | +	return (php_hrtime_t)((double)cur * _timer_int * (double)NANO_IN_SEC); | 
|  | 122 | +#elif PHP_HRTIME_PLATFORM_APPLE | 
|  | 123 | +	return (php_hrtime_t)mach_absolute_time() * _timerlib_info.numer / _timerlib_info.denom; | 
|  | 124 | +#elif PHP_HRTIME_PLATFORM_POSIX | 
|  | 125 | +	struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; | 
|  | 126 | +	if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) { | 
|  | 127 | +		return ((php_hrtime_t) ts.tv_sec * (php_hrtime_t)NANO_IN_SEC) + ts.tv_nsec; | 
|  | 128 | +	} | 
|  | 129 | +	return 0; | 
|  | 130 | +#elif PHP_HRTIME_PLATFORM_HPUX | 
|  | 131 | +	return (php_hrtime_t) gethrtime(); | 
|  | 132 | +#elif  PHP_HRTIME_PLATFORM_AIX | 
|  | 133 | +	timebasestruct_t t; | 
|  | 134 | +	read_wall_time(&t, TIMEBASE_SZ); | 
|  | 135 | +	time_base_to_time(&t, TIMEBASE_SZ); | 
|  | 136 | +	return (php_hrtime_t) t.tb_high * (php_hrtime_t)NANO_IN_SEC + t.tb_low; | 
|  | 137 | +#else | 
|  | 138 | +	return 0; | 
|  | 139 | +#endif | 
|  | 140 | +}/*}}}*/ | 
|  | 141 | + | 
|  | 142 | +#if ZEND_ENABLE_ZVAL_LONG64 | 
|  | 143 | +#define PHP_RETURN_HRTIME(t) RETURN_LONG((zend_long)t) | 
|  | 144 | +#else | 
|  | 145 | +#ifdef _WIN32 | 
|  | 146 | +# define HRTIME_U64A(i, s, len) _ui64toa_s(i, s, len, 10) | 
|  | 147 | +#else | 
|  | 148 | +# define HRTIME_U64A(i, s, len) \ | 
|  | 149 | +	do { \ | 
|  | 150 | +		int st = snprintf(s, len, "%llu", i); \ | 
|  | 151 | +		s[st] = '\0'; \ | 
|  | 152 | +	} while (0) | 
|  | 153 | +#endif | 
|  | 154 | +#define PHP_RETURN_HRTIME(t) do { \ | 
|  | 155 | +	char _a[ZEND_LTOA_BUF_LEN]; \ | 
|  | 156 | +	double _d; \ | 
|  | 157 | +	HRTIME_U64A(t, _a, ZEND_LTOA_BUF_LEN); \ | 
|  | 158 | +	_d = zend_strtod(_a, NULL); \ | 
|  | 159 | +	RETURN_DOUBLE(_d); \ | 
|  | 160 | +	} while (0) | 
|  | 161 | +#endif | 
| 153 | 162 | 
 | 
| 154 |  | -/* {{{ proto float hrtime() | 
| 155 |  | -   Returns a float containing the current high-resolution time in seconds | 
| 156 |  | -   counted from an arbitrary point in time */ | 
|  | 163 | +/* {{{ proto mixed hrtime([bool get_as_numu = false]) | 
|  | 164 | +	Returns an array of integers in form [seconds, nanoseconds] counted | 
|  | 165 | +	from an arbitrary point in time. If an optional boolean argument is | 
|  | 166 | +	passed, returns an integer on 64-bit platforms or float on 32-bit | 
|  | 167 | +	containing the current high-resolution time in nanoseconds */ | 
| 157 | 168 | PHP_FUNCTION(hrtime) | 
| 158 | 169 | { | 
| 159 |  | -	if (zend_parse_parameters_none() == FAILURE) { | 
| 160 |  | -		return; | 
| 161 |  | -	} | 
| 162 |  | - | 
| 163 |  | -	uint64_t current_time = _timer_current(); | 
| 164 |  | - | 
| 165 |  | -	if (UNEXPECTED(current_time == -1)) { | 
| 166 |  | -		zend_throw_exception(zend_ce_error, "Failed to get current system time", 0); | 
| 167 |  | -		return; | 
|  | 170 | +#if HRTIME_AVAILABLE | 
|  | 171 | +	zend_bool get_as_num = 0; | 
|  | 172 | +	php_hrtime_t t = _timer_current(); | 
|  | 173 | + | 
|  | 174 | +	ZEND_PARSE_PARAMETERS_START(0, 1) | 
|  | 175 | +		Z_PARAM_OPTIONAL | 
|  | 176 | +		Z_PARAM_BOOL(get_as_num) | 
|  | 177 | +	ZEND_PARSE_PARAMETERS_END(); | 
|  | 178 | + | 
|  | 179 | +	if (!get_as_num) { | 
|  | 180 | +		/* TODO On 32-bit care about millenium bug. */ | 
|  | 181 | +		array_init(return_value); | 
|  | 182 | +		add_next_index_long(return_value, (zend_long)(t / (php_hrtime_t)NANO_IN_SEC)); | 
|  | 183 | +		add_next_index_long(return_value, (zend_long)(t % (php_hrtime_t)NANO_IN_SEC)); | 
|  | 184 | +	} else { | 
|  | 185 | +		PHP_RETURN_HRTIME(t); | 
| 168 | 186 | 	} | 
| 169 |  | - | 
| 170 |  | -	RETURN_DOUBLE((double) current_time / _timer_freq); | 
|  | 187 | +#else | 
|  | 188 | +	RETURN_LONG(0); | 
|  | 189 | +#endif | 
| 171 | 190 | } | 
| 172 | 191 | /* }}} */ | 
| 173 | 192 | 
 | 
| 174 |  | -#endif /* HRTIME_AVAILABLE */ | 
|  | 193 | +PHPAPI php_hrtime_t php_hrtime_current(void) | 
|  | 194 | +{/*{{{*/ | 
|  | 195 | +	return _timer_current(); | 
|  | 196 | +}/*}}}*/ | 
|  | 197 | + | 
|  | 198 | +/* | 
|  | 199 | + * Local variables: | 
|  | 200 | + * tab-width: 4 | 
|  | 201 | + * c-basic-offset: 4 | 
|  | 202 | + * End: | 
|  | 203 | + * vim600: sw=4 ts=4 fdm=marker | 
|  | 204 | + * vim<600: sw=4 ts=4 | 
|  | 205 | + */ | 
|  | 206 | + | 
0 commit comments