Coverage Report

Created: 2022-10-06 01:35

/src/php-src/ext/standard/hrtime.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   +----------------------------------------------------------------------+
3
   | Copyright (c) The PHP Group                                          |
4
   +----------------------------------------------------------------------+
5
   | This source file is subject to version 3.01 of the PHP license,      |
6
   | that is bundled with this package in the file LICENSE, and is        |
7
   | available through the world-wide-web at the following url:           |
8
   | http://www.php.net/license/3_01.txt                                  |
9
   | If you did not receive a copy of the PHP license and are unable to   |
10
   | obtain it through the world-wide-web, please send a note to          |
11
   | license@php.net so we can mail you a copy immediately.               |
12
   +----------------------------------------------------------------------+
13
   | Author: Niklas Keller <kelunik@php.net>                              |
14
   | Author: Anatol Belski <ab@php.net>                                   |
15
   +----------------------------------------------------------------------+
16
 */
17
18
#include "php.h"
19
#include "hrtime.h"
20
21
/* {{{ */
22
/* This file reuses code parts from the cross-platform timer library
23
  Public Domain - 2011 Mattias Jansson / Rampant Pixels */
24
25
#if PHP_HRTIME_PLATFORM_POSIX
26
27
# include <unistd.h>
28
# include <time.h>
29
# include <string.h>
30
31
#elif PHP_HRTIME_PLATFORM_WINDOWS
32
33
# define WIN32_LEAN_AND_MEAN
34
35
static double _timer_scale = .0;
36
37
#elif PHP_HRTIME_PLATFORM_APPLE
38
39
# include <mach/mach_time.h>
40
# include <string.h>
41
static mach_timebase_info_data_t _timerlib_info;
42
43
#elif PHP_HRTIME_PLATFORM_HPUX
44
45
# include <sys/time.h>
46
47
#elif PHP_HRTIME_PLATFORM_AIX
48
49
# include <sys/time.h>
50
# include <sys/systemcfg.h>
51
52
#endif
53
54
0
#define NANO_IN_SEC 1000000000
55
/* }}} */
56
57
static int _timer_init()
58
3.68k
{/*{{{*/
59
#if PHP_HRTIME_PLATFORM_WINDOWS
60
61
  LARGE_INTEGER tf = {0};
62
  if (!QueryPerformanceFrequency(&tf) || 0 == tf.QuadPart) {
63
    return -1;
64
  }
65
  _timer_scale = (double)NANO_IN_SEC / (php_hrtime_t)tf.QuadPart;
66
67
#elif PHP_HRTIME_PLATFORM_APPLE
68
69
  if (mach_timebase_info(&_timerlib_info)) {
70
    return -1;
71
  }
72
73
#elif PHP_HRTIME_PLATFORM_POSIX
74
75
3.68k
#if !_POSIX_MONOTONIC_CLOCK
76
3.68k
#ifdef _SC_MONOTONIC_CLOCK
77
3.68k
  if (0 >= sysconf(_SC_MONOTONIC_CLOCK)) {
78
0
    return -1;
79
0
  }
80
3.68k
#endif
81
3.68k
#endif
82
83
#elif PHP_HRTIME_PLATFORM_HPUX
84
85
  /* pass */
86
87
#elif PHP_HRTIME_PLATFORM_AIX
88
89
  /* pass */
90
91
#else
92
  /* Timer unavailable. */
93
  return -1;
94
#endif
95
96
3.68k
  return 0;
97
3.68k
}/*}}}*/
98
99
/* {{{ */
100
PHP_MINIT_FUNCTION(hrtime)
101
3.68k
{
102
3.68k
  if (0 > _timer_init()) {
103
0
    php_error_docref(NULL, E_WARNING, "Failed to initialize high-resolution timer");
104
0
    return FAILURE;
105
0
  }
106
107
3.68k
  return SUCCESS;
108
3.68k
}
109
/* }}} */
110
111
static zend_always_inline php_hrtime_t _timer_current(void)
112
0
{/*{{{*/
113
#if PHP_HRTIME_PLATFORM_WINDOWS
114
  LARGE_INTEGER lt = {0};
115
  QueryPerformanceCounter(&lt);
116
  return (php_hrtime_t)((php_hrtime_t)lt.QuadPart * _timer_scale);
117
#elif PHP_HRTIME_PLATFORM_APPLE
118
  return (php_hrtime_t)mach_absolute_time() * _timerlib_info.numer / _timerlib_info.denom;
119
#elif PHP_HRTIME_PLATFORM_POSIX
120
0
  struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
121
0
  if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) {
122
0
    return ((php_hrtime_t) ts.tv_sec * (php_hrtime_t)NANO_IN_SEC) + ts.tv_nsec;
123
0
  }
124
0
  return 0;
125
#elif PHP_HRTIME_PLATFORM_HPUX
126
  return (php_hrtime_t) gethrtime();
127
#elif  PHP_HRTIME_PLATFORM_AIX
128
  timebasestruct_t t;
129
  read_wall_time(&t, TIMEBASE_SZ);
130
  time_base_to_time(&t, TIMEBASE_SZ);
131
  return (php_hrtime_t) t.tb_high * (php_hrtime_t)NANO_IN_SEC + t.tb_low;
132
#else
133
  return 0;
134
#endif
135
0
}/*}}}*/
136
137
#if ZEND_ENABLE_ZVAL_LONG64
138
0
#define PHP_RETURN_HRTIME(t) RETURN_LONG((zend_long)t)
139
#else
140
#ifdef _WIN32
141
# define HRTIME_U64A(i, s, len) _ui64toa_s(i, s, len, 10)
142
#else
143
# define HRTIME_U64A(i, s, len) \
144
  do { \
145
    int st = snprintf(s, len, "%llu", i); \
146
    s[st] = '\0'; \
147
  } while (0)
148
#endif
149
#define PHP_RETURN_HRTIME(t) do { \
150
  char _a[ZEND_LTOA_BUF_LEN]; \
151
  double _d; \
152
  HRTIME_U64A(t, _a, ZEND_LTOA_BUF_LEN); \
153
  _d = zend_strtod(_a, NULL); \
154
  RETURN_DOUBLE(_d); \
155
  } while (0)
156
#endif
157
158
/* {{{ proto mixed hrtime([bool get_as_number = false])
159
  Returns an array of integers in form [seconds, nanoseconds] counted
160
  from an arbitrary point in time. If an optional boolean argument is
161
  passed, returns an integer on 64-bit platforms or float on 32-bit
162
  containing the current high-resolution time in nanoseconds. The
163
  delivered timestamp is monotonic and can not be adjusted. */
164
PHP_FUNCTION(hrtime)
165
0
{
166
0
#if HRTIME_AVAILABLE
167
0
  zend_bool get_as_num = 0;
168
0
  php_hrtime_t t = _timer_current();
169
170
0
  ZEND_PARSE_PARAMETERS_START(0, 1)
171
0
    Z_PARAM_OPTIONAL
172
0
    Z_PARAM_BOOL(get_as_num)
173
0
  ZEND_PARSE_PARAMETERS_END();
174
175
0
  if (UNEXPECTED(get_as_num)) {
176
0
    PHP_RETURN_HRTIME(t);
177
0
  } else {
178
0
    array_init_size(return_value, 2);
179
0
    zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
180
0
    add_next_index_long(return_value, (zend_long)(t / (php_hrtime_t)NANO_IN_SEC));
181
0
    add_next_index_long(return_value, (zend_long)(t % (php_hrtime_t)NANO_IN_SEC));
182
0
  }
183
#else
184
  RETURN_FALSE;
185
#endif
186
0
}
187
/* }}} */
188
189
PHPAPI php_hrtime_t php_hrtime_current(void)
190
0
{/*{{{*/
191
0
  return _timer_current();
192
0
}/*}}}*/