|
55 | 55 | # define GCC_DIAG_IGNORE_CPP_COMPAT_RESTORE_STMT GCC_DIAG_RESTORE_STMT
|
56 | 56 | #endif
|
57 | 57 |
|
| 58 | +#ifndef PERL_STATIC_FORCE_INLINE |
| 59 | +# define PERL_STATIC_FORCE_INLINE STATIC |
| 60 | +#endif |
| 61 | + |
58 | 62 | #if PERL_VERSION_GE(5,7,3) && !PERL_VERSION_GE(5,10,1)
|
59 | 63 | # undef SAVEOP
|
60 | 64 | # define SAVEOP() SAVEVPTR(PL_op)
|
@@ -136,10 +140,10 @@ typedef union {
|
136 | 140 | # define MY_CXT_KEY "Time::HiRes_" XS_VERSION
|
137 | 141 |
|
138 | 142 | typedef struct {
|
139 |
| - unsigned long run_count; |
140 | 143 | unsigned __int64 base_ticks;
|
141 | 144 | FT_t base_systime_as_filetime;
|
142 | 145 | unsigned __int64 reset_time;
|
| 146 | + unsigned long run_count; |
143 | 147 | } my_cxt_t;
|
144 | 148 |
|
145 | 149 | static unsigned __int64 tick_frequency = 0;
|
@@ -190,7 +194,7 @@ START_MY_CXT
|
190 | 194 | for performance reasons */
|
191 | 195 |
|
192 | 196 | # undef gettimeofday
|
193 |
| -# define gettimeofday(tp, not_used) _gettimeofday(aTHX_ tp, not_used) |
| 197 | +# define gettimeofday(tp, not_used) ((*(tp) = _gettimeofday_x(aTHX)), 0) |
194 | 198 |
|
195 | 199 | # undef GetSystemTimePreciseAsFileTime
|
196 | 200 | # define GetSystemTimePreciseAsFileTime(out) (void)(*(out) = _GetSystemTimePreciseAsFileTime(aTHX))
|
@@ -239,78 +243,99 @@ START_MY_CXT
|
239 | 243 | * the pointer for long term Interlocked or Atomic message passing from an
|
240 | 244 | * unknown 2nd OS thread running on another CPU Core.
|
241 | 245 | */
|
| 246 | + |
242 | 247 | static FILETIME
|
243 | 248 | _GetSystemTimePreciseAsFileTime(pTHX)
|
244 | 249 | {
|
245 |
| - dMY_CXT; |
246 |
| - FT_t ft; |
247 |
| - |
248 |
| - if (MY_CXT.run_count++ == 0 || |
249 |
| - MY_CXT.base_systime_as_filetime.ft_i64 > MY_CXT.reset_time) { |
250 |
| - |
251 |
| - QueryPerformanceCounter((LARGE_INTEGER*)&MY_CXT.base_ticks); |
252 |
| - GetSystemTimeAsFileTime(&MY_CXT.base_systime_as_filetime.ft_val); |
253 |
| - ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64; |
254 |
| - MY_CXT.reset_time = ft.ft_i64 + MAX_PERF_COUNTER_TICKS; |
| 250 | +#define MY_CXTX (*MY_CXT_x) |
| 251 | + unsigned __int64 ticks; |
| 252 | + unsigned __int64 ticks_mem; |
| 253 | + unsigned __int64 timesys; |
| 254 | + __int64 diff; |
| 255 | +/* If no threads, CC will probably optimize away all MY_CXT_x references |
| 256 | + so they directly access the C static global struct. */ |
| 257 | + my_cxt_t * MY_CXT_x; |
| 258 | + |
| 259 | + QueryPerformanceCounter((LARGE_INTEGER*)&ticks_mem); |
| 260 | + /* Inform the CC nothing external or in this fn (ptr aliasing) can ever |
| 261 | + rewrite the value in ticks. Increases chance of CC using registers. */ |
| 262 | + ticks = ticks_mem; |
| 263 | + { |
| 264 | + dMY_CXT; |
| 265 | + MY_CXT_x = &(MY_CXT); |
| 266 | + } |
| 267 | + if (MY_CXTX.run_count++ == 0 || |
| 268 | + MY_CXTX.base_systime_as_filetime.ft_i64 > MY_CXTX.reset_time) { |
| 269 | + MY_CXTX.base_ticks = ticks; |
| 270 | + GetSystemTimeAsFileTime(&MY_CXTX.base_systime_as_filetime.ft_val); |
| 271 | + timesys = MY_CXTX.base_systime_as_filetime.ft_i64; |
| 272 | + MY_CXTX.reset_time = timesys + MAX_PERF_COUNTER_TICKS; |
255 | 273 | }
|
256 | 274 | else {
|
257 |
| - __int64 diff; |
258 |
| - unsigned __int64 ticks; |
259 |
| - QueryPerformanceCounter((LARGE_INTEGER*)&ticks); |
260 |
| - ticks -= MY_CXT.base_ticks; |
261 |
| - ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64 |
| 275 | + ticks -= MY_CXTX.base_ticks; |
| 276 | + timesys = MY_CXTX.base_systime_as_filetime.ft_i64 |
262 | 277 | + Const64(IV_1E7) * (ticks / tick_frequency)
|
263 | 278 | +(Const64(IV_1E7) * (ticks % tick_frequency)) / tick_frequency;
|
264 |
| - diff = ft.ft_i64 - MY_CXT.base_systime_as_filetime.ft_i64; |
| 279 | + diff = timesys - MY_CXTX.base_systime_as_filetime.ft_i64; |
265 | 280 | if (diff < -MAX_PERF_COUNTER_SKEW || diff > MAX_PERF_COUNTER_SKEW) {
|
266 |
| - MY_CXT.base_ticks += ticks; |
267 |
| - GetSystemTimeAsFileTime(&MY_CXT.base_systime_as_filetime.ft_val); |
268 |
| - ft.ft_i64 = MY_CXT.base_systime_as_filetime.ft_i64; |
| 281 | + MY_CXTX.base_ticks += ticks; |
| 282 | + GetSystemTimeAsFileTime(&MY_CXTX.base_systime_as_filetime.ft_val); |
| 283 | + timesys = MY_CXTX.base_systime_as_filetime.ft_i64; |
269 | 284 | }
|
270 | 285 | }
|
271 |
| - |
272 |
| - return ft.ft_val; |
| 286 | +#undef MY_CXTX |
| 287 | + { |
| 288 | + FT_t ft; |
| 289 | + ft.ft_i64 = timesys; |
| 290 | + return ft.ft_val; |
| 291 | + } |
273 | 292 | }
|
274 | 293 |
|
275 |
| -static int |
276 |
| -_gettimeofday(pTHX_ struct timeval *tp, void *not_used) |
| 294 | +/* former prototype: static int _gettimeofday(pTHX_ struct timeval *tp, void *not_used); |
| 295 | +
|
| 296 | + B/c _gettimeofday_x() is not capable of failing, and retval was always |
| 297 | + constant 0, and its a static fn that never leaves this TU, repurpose the |
| 298 | + retval for something better. */ |
| 299 | + |
| 300 | +PERL_STATIC_FORCE_INLINE struct timeval |
| 301 | +_gettimeofday_x(pTHX) |
277 | 302 | {
|
278 | 303 | FT_t ft;
|
279 |
| - |
280 |
| - PERL_UNUSED_ARG(not_used); |
| 304 | + struct timeval tp; |
281 | 305 |
|
282 | 306 | GetSystemTimePreciseAsFileTime(&ft.ft_val);
|
283 | 307 |
|
284 | 308 | /* seconds since epoch */
|
285 |
| - tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(IV_1E7)); |
| 309 | + tp.tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(IV_1E7)); |
286 | 310 |
|
287 | 311 | /* microseconds remaining */
|
288 |
| - tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(IV_1E6)); |
| 312 | + tp.tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(IV_1E6)); |
289 | 313 |
|
290 |
| - return 0; |
| 314 | + return tp; |
291 | 315 | }
|
292 | 316 |
|
293 |
| -static int |
| 317 | +/* force inline it, because XS_Time__HiRes_clock_gettime() is the only caller */ |
| 318 | + |
| 319 | +PERL_STATIC_FORCE_INLINE int |
294 | 320 | _clock_gettime(pTHX_ clockid_t clock_id, struct timespec *tp)
|
295 | 321 | {
|
296 |
| - switch (clock_id) { |
297 |
| - case CLOCK_REALTIME: { |
298 |
| - FT_t ft; |
| 322 | + FT_t ft; |
| 323 | + unsigned __int64 ticks; |
| 324 | + unsigned __int64 time_sys; |
299 | 325 |
|
| 326 | + switch (clock_id) { |
| 327 | + case CLOCK_REALTIME: |
300 | 328 | GetSystemTimePreciseAsFileTime(&ft.ft_val);
|
301 |
| - tp->tv_sec = (time_t)((ft.ft_i64 - EPOCH_BIAS) / IV_1E7); |
302 |
| - tp->tv_nsec = (long)((ft.ft_i64 % IV_1E7) * 100); |
| 329 | + time_sys = ft.ft_i64; |
| 330 | + tp->tv_sec = (time_t)((time_sys - EPOCH_BIAS) / IV_1E7); |
| 331 | + tp->tv_nsec = (long)((time_sys % IV_1E7) * 100); |
303 | 332 | break;
|
304 |
| - } |
305 |
| - case CLOCK_MONOTONIC: { |
306 |
| - unsigned __int64 ticks; |
307 |
| - |
308 |
| - QueryPerformanceCounter((LARGE_INTEGER*)&ticks); |
309 |
| - |
| 333 | + case CLOCK_MONOTONIC: |
| 334 | + QueryPerformanceCounter((LARGE_INTEGER*)&ft.ft_i64); |
| 335 | + ticks = ft.ft_i64; |
310 | 336 | tp->tv_sec = (time_t)(ticks / tick_frequency);
|
311 | 337 | tp->tv_nsec = (long)((IV_1E9 * (ticks % tick_frequency)) / tick_frequency);
|
312 | 338 | break;
|
313 |
| - } |
314 | 339 | default:
|
315 | 340 | errno = EINVAL;
|
316 | 341 | return 1;
|
|
0 commit comments