1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 1999-2018. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 /*
22 * Support routines for the time
23 */
24
25 /* #define ERTS_TIME_CORRECTION_PRINT */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include "sys.h"
32 #include "erl_vm.h"
33 #include "global.h"
34 #define ERTS_WANT_TIMER_WHEEL_API
35 #include "erl_time.h"
36 #include "erl_driver.h"
37 #include "erl_nif.h"
38 #include "erl_proc_sig_queue.h"
39
40 static erts_mtx_t erts_get_time_mtx;
41
42 /* used by erts_runtime_elapsed_both */
43 typedef struct {
44 erts_mtx_t mtx;
45 ErtsMonotonicTime user;
46 ErtsMonotonicTime sys;
47 } ErtsRunTimePrevData;
48
49 static union {
50 ErtsRunTimePrevData data;
51 char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsRunTimePrevData))];
52 } runtime_prev erts_align_attribute(ERTS_CACHE_LINE_SIZE);
53
54 static union {
55 erts_atomic64_t time;
56 char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_atomic64_t))];
57 } wall_clock_prev erts_align_attribute(ERTS_CACHE_LINE_SIZE);
58
59 static union {
60 erts_atomic64_t time;
61 char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_atomic64_t))];
62 } now_prev erts_align_attribute(ERTS_CACHE_LINE_SIZE);
63
64 static ErtsMonitor *time_offset_monitors = NULL;
65 static Uint no_time_offset_monitors = 0;
66
67 #ifdef DEBUG
68 static int time_sup_initialized = 0;
69 #endif
70
71 #define ERTS_MONOTONIC_TIME_KILO \
72 ((ErtsMonotonicTime) 1000)
73 #define ERTS_MONOTONIC_TIME_MEGA \
74 (ERTS_MONOTONIC_TIME_KILO*ERTS_MONOTONIC_TIME_KILO)
75 #define ERTS_MONOTONIC_TIME_GIGA \
76 (ERTS_MONOTONIC_TIME_MEGA*ERTS_MONOTONIC_TIME_KILO)
77 #define ERTS_MONOTONIC_TIME_TERA \
78 (ERTS_MONOTONIC_TIME_GIGA*ERTS_MONOTONIC_TIME_KILO)
79
80 static void init_time_napi(void);
81 static void
82 schedule_send_time_offset_changed_notifications(ErtsMonotonicTime new_offset);
83
84 struct time_sup_read_only__ {
85 ErtsMonotonicTime (*get_time)(void);
86 int correction;
87 ErtsTimeWarpMode warp_mode;
88 #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
89 ErtsMonotonicTime moffset;
90 int os_corrected_monotonic_time;
91 int os_monotonic_time_disable;
92 char *os_monotonic_time_func;
93 char *os_monotonic_time_clock_id;
94 int os_monotonic_time_locked;
95 Uint64 os_monotonic_time_resolution;
96 Uint64 os_monotonic_time_extended;
97 #endif
98 char *os_system_time_func;
99 char *os_system_time_clock_id;
100 int os_system_time_locked;
101 Uint64 os_system_time_resolution;
102 Uint64 os_system_time_extended;
103 struct {
104 ErtsMonotonicTime large_diff;
105 ErtsMonotonicTime small_diff;
106 } adj;
107 struct {
108 ErtsMonotonicTime error;
109 ErtsMonotonicTime resolution;
110 int intervals;
111 int use_avg;
112 } drift_adj;
113 };
114
115 typedef struct {
116 ErtsMonotonicTime drift; /* Correction for os monotonic drift */
117 ErtsMonotonicTime error; /* Correction for error between system times */
118 } ErtsMonotonicCorrection;
119
120 typedef struct {
121 ErtsMonotonicTime erl_mtime;
122 ErtsMonotonicTime os_mtime;
123 ErtsMonotonicCorrection correction;
124 } ErtsMonotonicCorrectionInstance;
125
126 #define ERTS_MAX_DRIFT_INTERVALS 50
127 typedef struct {
128 struct {
129 struct {
130 ErtsMonotonicTime sys;
131 ErtsMonotonicTime mon;
132 } diff;
133 struct {
134 ErtsMonotonicTime sys;
135 ErtsMonotonicTime mon;
136 } time;
137 } intervals[ERTS_MAX_DRIFT_INTERVALS];
138 struct {
139 ErtsMonotonicTime sys;
140 ErtsMonotonicTime mon;
141 } acc;
142 int ix;
143 int dirty_counter;
144 } ErtsMonotonicDriftData;
145
146 typedef struct {
147 ErtsMonotonicCorrectionInstance prev;
148 ErtsMonotonicCorrectionInstance curr;
149 } ErtsMonotonicCorrectionInstances;
150
151 typedef struct {
152 ErtsMonotonicCorrectionInstances insts;
153 ErtsMonotonicDriftData drift;
154 ErtsMonotonicTime last_check;
155 int short_check_interval;
156 } ErtsMonotonicCorrectionData;
157
158 struct time_sup_infrequently_changed__ {
159 #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
160 struct {
161 erts_rwmtx_t rwmtx;
162 ErtsTWheelTimer timer;
163 ErtsMonotonicCorrectionData cdata;
164 } parmon;
165 ErtsMonotonicTime minit;
166 #endif
167 ErtsSystemTime sinit;
168 ErtsMonotonicTime not_corrected_moffset;
169 erts_atomic64_t offset;
170 ErtsMonotonicTime shadow_offset;
171 erts_atomic32_t preliminary_offset;
172 };
173
174 struct time_sup_frequently_changed__ {
175 ErtsMonotonicTime last_not_corrected_time;
176 };
177
178 static struct {
179 union {
180 struct time_sup_read_only__ o;
181 char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(struct time_sup_read_only__))];
182 } r;
183 union {
184 struct time_sup_infrequently_changed__ c;
185 char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(struct time_sup_infrequently_changed__))];
186 } inf;
187 union {
188 struct time_sup_frequently_changed__ c;
189 char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(struct time_sup_frequently_changed__))];
190 } f;
191 } time_sup erts_align_attribute(ERTS_CACHE_LINE_SIZE);
192
193 ErtsTimeSupData erts_time_sup__ erts_align_attribute(ERTS_CACHE_LINE_SIZE);
194
195 static ERTS_INLINE void
init_time_offset(ErtsMonotonicTime offset)196 init_time_offset(ErtsMonotonicTime offset)
197 {
198 erts_atomic64_init_nob(&time_sup.inf.c.offset, (erts_aint64_t) offset);
199 }
200
201 static ERTS_INLINE void
set_time_offset(ErtsMonotonicTime offset)202 set_time_offset(ErtsMonotonicTime offset)
203 {
204 erts_atomic64_set_relb(&time_sup.inf.c.offset, (erts_aint64_t) offset);
205 }
206
207 static ERTS_INLINE ErtsMonotonicTime
get_time_offset(void)208 get_time_offset(void)
209 {
210 return (ErtsMonotonicTime) erts_atomic64_read_acqb(&time_sup.inf.c.offset);
211 }
212
213 static ERTS_INLINE void
update_last_mtime(ErtsSchedulerData * esdp,ErtsMonotonicTime mtime)214 update_last_mtime(ErtsSchedulerData *esdp, ErtsMonotonicTime mtime)
215 {
216 if (!esdp)
217 esdp = erts_get_scheduler_data();
218 if (esdp) {
219 ASSERT(mtime >= esdp->last_monotonic_time);
220 esdp->last_monotonic_time = mtime;
221 esdp->check_time_reds = 0;
222 }
223 }
224
225 #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
226
227 /*
228 * Time correction adjustments made due to
229 * error between Erlang system time and OS
230 * system time:
231 * - Large adjustment ~1%
232 * - Small adjustment ~0.05%
233 */
234 #define ERTS_TCORR_ERR_UNIT 2048
235 #define ERTS_TCORR_ERR_LARGE_ADJ 20
236 #define ERTS_TCORR_ERR_SMALL_ADJ 1
237
238 #define ERTS_INIT_SHORT_INTERVAL_COUNTER 10
239 #define ERTS_LONG_TIME_CORRECTION_CHECK ERTS_SEC_TO_MONOTONIC(60)
240 #define ERTS_SHORT_TIME_CORRECTION_CHECK ERTS_SEC_TO_MONOTONIC(15)
241
242 #define ERTS_TIME_DRIFT_MAX_ADJ_DIFF ERTS_USEC_TO_MONOTONIC(50)
243 #define ERTS_TIME_DRIFT_MIN_ADJ_DIFF ERTS_USEC_TO_MONOTONIC(5)
244
245 /*
246 * Maximum drift of the OS monotonic clock expected.
247 *
248 * We use 1 milli second per second. If the monotonic
249 * clock drifts more than this we will fail to adjust for
250 * drift, and error correction will kick in instead.
251 * If it is larger than this, one could argue that the
252 * primitive is to poor to be used...
253 */
254 #define ERTS_MAX_MONOTONIC_DRIFT ERTS_MSEC_TO_MONOTONIC(1)
255
256 /*
257 * We assume that precision is 32 times worse than the
258 * resolution. This is a wild guess, but there are no
259 * practical way to determine actual precision.
260 */
261 #define ERTS_ASSUMED_PRECISION_DROP 32
262
263 #define ERTS_MIN_MONOTONIC_DRIFT_MEASUREMENT \
264 (ERTS_SHORT_TIME_CORRECTION_CHECK - 2*ERTS_MAX_MONOTONIC_DRIFT)
265
266
267 static ERTS_INLINE ErtsMonotonicTime
calc_corrected_erl_mtime(ErtsMonotonicTime os_mtime,ErtsMonotonicCorrectionInstance * cip,ErtsMonotonicTime * os_mdiff_p,int os_drift_corrected)268 calc_corrected_erl_mtime(ErtsMonotonicTime os_mtime,
269 ErtsMonotonicCorrectionInstance *cip,
270 ErtsMonotonicTime *os_mdiff_p,
271 int os_drift_corrected)
272 {
273 ErtsMonotonicTime erl_mtime, diff = os_mtime - cip->os_mtime;
274 ERTS_TIME_ASSERT(diff >= 0);
275 if (!os_drift_corrected)
276 diff += (cip->correction.drift*diff)/ERTS_MONOTONIC_TIME_UNIT;
277 erl_mtime = cip->erl_mtime;
278 erl_mtime += diff;
279 erl_mtime += cip->correction.error*(diff/ERTS_TCORR_ERR_UNIT);
280 if (os_mdiff_p)
281 *os_mdiff_p = diff;
282 return erl_mtime;
283 }
284
285 static ERTS_INLINE ErtsMonotonicTime
read_corrected_time(int os_drift_corrected)286 read_corrected_time(int os_drift_corrected)
287 {
288 ErtsMonotonicTime os_mtime;
289 ErtsMonotonicCorrectionInstance ci;
290
291 erts_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx);
292
293 os_mtime = erts_os_monotonic_time();
294
295 if (os_mtime >= time_sup.inf.c.parmon.cdata.insts.curr.os_mtime)
296 ci = time_sup.inf.c.parmon.cdata.insts.curr;
297 else {
298 if (os_mtime < time_sup.inf.c.parmon.cdata.insts.prev.os_mtime)
299 erts_exit(ERTS_ABORT_EXIT,
300 "OS monotonic time stepped backwards\n");
301 ci = time_sup.inf.c.parmon.cdata.insts.prev;
302 }
303
304 erts_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx);
305
306 return calc_corrected_erl_mtime(os_mtime, &ci, NULL,
307 os_drift_corrected);
308 }
309
get_os_drift_corrected_time(void)310 static ErtsMonotonicTime get_os_drift_corrected_time(void)
311 {
312 return read_corrected_time(!0);
313 }
314
get_corrected_time(void)315 static ErtsMonotonicTime get_corrected_time(void)
316 {
317 return read_corrected_time(0);
318 }
319
320 #ifdef ERTS_TIME_CORRECTION_PRINT
321
322 static ERTS_INLINE void
print_correction(int change,ErtsMonotonicTime sdiff,ErtsMonotonicTime old_ecorr,ErtsMonotonicTime old_dcorr,ErtsMonotonicTime new_ecorr,ErtsMonotonicTime new_dcorr,Uint tmo)323 print_correction(int change,
324 ErtsMonotonicTime sdiff,
325 ErtsMonotonicTime old_ecorr,
326 ErtsMonotonicTime old_dcorr,
327 ErtsMonotonicTime new_ecorr,
328 ErtsMonotonicTime new_dcorr,
329 Uint tmo)
330 {
331 ErtsMonotonicTime usec_sdiff;
332 if (sdiff < 0)
333 usec_sdiff = -1*ERTS_MONOTONIC_TO_USEC(-1*sdiff);
334 else
335 usec_sdiff = ERTS_MONOTONIC_TO_USEC(sdiff);
336
337 if (!change)
338 erts_fprintf(stderr,
339 "sdiff = %b64d usec : [ec=%b64d ppm, dc=%b64d ppb] : "
340 "tmo = %bpu msec\r\n",
341 usec_sdiff,
342 (1000000*old_ecorr) / ERTS_TCORR_ERR_UNIT,
343 (1000000000*old_dcorr) / ERTS_MONOTONIC_TIME_UNIT,
344 tmo);
345 else
346 erts_fprintf(stderr,
347 "sdiff = %b64d usec : [ec=%b64d ppm, dc=%b64d ppb] "
348 "-> [ec=%b64d ppm, dc=%b64d ppb] : tmo = %bpu msec\r\n",
349 usec_sdiff,
350 (1000000*old_ecorr) / ERTS_TCORR_ERR_UNIT,
351 (1000000000*old_dcorr) / ERTS_MONOTONIC_TIME_UNIT,
352 (1000000*new_ecorr) / ERTS_TCORR_ERR_UNIT,
353 (1000000000*new_dcorr) / ERTS_MONOTONIC_TIME_UNIT,
354 tmo);
355 }
356
357 #endif
358
359 static ERTS_INLINE ErtsMonotonicTime
get_timeout_pos(ErtsMonotonicTime now,ErtsMonotonicTime tmo)360 get_timeout_pos(ErtsMonotonicTime now, ErtsMonotonicTime tmo)
361 {
362 ErtsMonotonicTime tpos;
363 tpos = ERTS_MONOTONIC_TO_CLKTCKS(now - 1);
364 tpos += ERTS_MSEC_TO_CLKTCKS(tmo);
365 tpos += 1;
366 return tpos;
367 }
368
369 static void
check_time_correction(void * vesdp)370 check_time_correction(void *vesdp)
371 {
372 int init_drift_adj = !vesdp;
373 ErtsSchedulerData *esdp = (ErtsSchedulerData *) vesdp;
374 ErtsMonotonicCorrection new_correction;
375 ErtsMonotonicCorrectionInstance ci;
376 ErtsMonotonicTime mdiff, sdiff, os_mtime, erl_mtime, os_stime,
377 erl_stime, time_offset, timeout_pos;
378 Uint timeout;
379 int os_drift_corrected = time_sup.r.o.os_corrected_monotonic_time;
380 int set_new_correction = 0, begin_short_intervals = 0;
381
382 erts_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx);
383
384 erts_os_times(&os_mtime, &os_stime);
385
386 ci = time_sup.inf.c.parmon.cdata.insts.curr;
387
388 erts_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx);
389
390 if (os_mtime < ci.os_mtime)
391 erts_exit(ERTS_ABORT_EXIT,
392 "OS monotonic time stepped backwards\n");
393
394 erl_mtime = calc_corrected_erl_mtime(os_mtime, &ci, &mdiff,
395 os_drift_corrected);
396 time_offset = get_time_offset();
397 erl_stime = erl_mtime + time_offset;
398
399 sdiff = erl_stime - os_stime;
400
401 if (time_sup.inf.c.shadow_offset) {
402 ERTS_TIME_ASSERT(time_sup.r.o.warp_mode == ERTS_SINGLE_TIME_WARP_MODE);
403 if (erts_atomic32_read_nob(&time_sup.inf.c.preliminary_offset))
404 sdiff += time_sup.inf.c.shadow_offset;
405 else
406 time_sup.inf.c.shadow_offset = 0;
407 }
408
409 new_correction = ci.correction;
410
411 if (time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE
412 && (sdiff < -2*time_sup.r.o.adj.small_diff
413 || 2*time_sup.r.o.adj.small_diff < sdiff)) {
414 /* System time diff exeeded limits; change time offset... */
415 time_offset -= sdiff;
416 sdiff = 0;
417 set_time_offset(time_offset);
418 schedule_send_time_offset_changed_notifications(time_offset);
419 begin_short_intervals = 1;
420 if (ci.correction.error != 0) {
421 set_new_correction = 1;
422 new_correction.error = 0;
423 }
424 }
425 else if ((time_sup.r.o.warp_mode == ERTS_SINGLE_TIME_WARP_MODE
426 && erts_atomic32_read_nob(&time_sup.inf.c.preliminary_offset))
427 && (sdiff < -2*time_sup.r.o.adj.small_diff
428 || 2*time_sup.r.o.adj.small_diff < sdiff)) {
429 /*
430 * System time diff exeeded limits; change shadow offset
431 * and let OS system time leap away from Erlang system
432 * time.
433 */
434 time_sup.inf.c.shadow_offset -= sdiff;
435 sdiff = 0;
436 begin_short_intervals = 1;
437 if (ci.correction.error != 0) {
438 set_new_correction = 1;
439 new_correction.error = 0;
440 }
441 }
442 else if (ci.correction.error == 0) {
443 if (sdiff < -time_sup.r.o.adj.small_diff) {
444 set_new_correction = 1;
445 if (sdiff < -time_sup.r.o.adj.large_diff)
446 new_correction.error = ERTS_TCORR_ERR_LARGE_ADJ;
447 else
448 new_correction.error = ERTS_TCORR_ERR_SMALL_ADJ;
449 }
450 else if (sdiff > time_sup.r.o.adj.small_diff) {
451 set_new_correction = 1;
452 if (sdiff > time_sup.r.o.adj.large_diff)
453 new_correction.error = -ERTS_TCORR_ERR_LARGE_ADJ;
454 else
455 new_correction.error = -ERTS_TCORR_ERR_SMALL_ADJ;
456 }
457 }
458 else if (ci.correction.error > 0) {
459 if (sdiff < 0) {
460 if (ci.correction.error != ERTS_TCORR_ERR_LARGE_ADJ
461 && sdiff < -time_sup.r.o.adj.large_diff) {
462 new_correction.error = ERTS_TCORR_ERR_LARGE_ADJ;
463 set_new_correction = 1;
464 }
465 }
466 else if (sdiff > time_sup.r.o.adj.small_diff) {
467 set_new_correction = 1;
468 if (sdiff > time_sup.r.o.adj.large_diff)
469 new_correction.error = -ERTS_TCORR_ERR_LARGE_ADJ;
470 else
471 new_correction.error = -ERTS_TCORR_ERR_SMALL_ADJ;
472 }
473 else {
474 set_new_correction = 1;
475 new_correction.error = 0;
476 }
477 }
478 else /* if (ci.correction.error < 0) */ {
479 if (0 < sdiff) {
480 if (ci.correction.error != -ERTS_TCORR_ERR_LARGE_ADJ
481 && time_sup.r.o.adj.large_diff < sdiff) {
482 new_correction.error = -ERTS_TCORR_ERR_LARGE_ADJ;
483 set_new_correction = 1;
484 }
485 }
486 else if (sdiff < -time_sup.r.o.adj.small_diff) {
487 set_new_correction = 1;
488 if (sdiff < -time_sup.r.o.adj.large_diff)
489 new_correction.error = ERTS_TCORR_ERR_LARGE_ADJ;
490 else
491 new_correction.error = ERTS_TCORR_ERR_SMALL_ADJ;
492 }
493 else {
494 set_new_correction = 1;
495 new_correction.error = 0;
496 }
497 }
498
499 if (!os_drift_corrected) {
500 ErtsMonotonicDriftData *ddp = &time_sup.inf.c.parmon.cdata.drift;
501 int ix = ddp->ix;
502 ErtsMonotonicTime mtime_diff, old_os_mtime;
503
504 old_os_mtime = ddp->intervals[ix].time.mon;
505 mtime_diff = os_mtime - old_os_mtime;
506
507 if ((mtime_diff >= ERTS_MIN_MONOTONIC_DRIFT_MEASUREMENT)
508 | init_drift_adj) {
509 ErtsMonotonicTime drift_adj, drift_adj_diff, old_os_stime,
510 smtime_diff, stime_diff, mtime_acc, stime_acc,
511 avg_drift_adj, max_drift;
512
513 old_os_stime = ddp->intervals[ix].time.sys;
514
515 mtime_acc = ddp->acc.mon;
516 stime_acc = ddp->acc.sys;
517
518 avg_drift_adj = (((stime_acc - mtime_acc)
519 * ERTS_MONOTONIC_TIME_UNIT)
520 / mtime_acc);
521
522 mtime_diff = os_mtime - old_os_mtime;
523 stime_diff = os_stime - old_os_stime;
524 smtime_diff = stime_diff - mtime_diff;
525 ix++;
526 if (ix >= time_sup.r.o.drift_adj.intervals)
527 ix = 0;
528 mtime_acc -= ddp->intervals[ix].diff.mon;
529 mtime_acc += mtime_diff;
530 stime_acc -= ddp->intervals[ix].diff.sys;
531 stime_acc += stime_diff;
532
533 ddp->intervals[ix].diff.mon = mtime_diff;
534 ddp->intervals[ix].diff.sys = stime_diff;
535 ddp->intervals[ix].time.mon = os_mtime;
536 ddp->intervals[ix].time.sys = os_stime;
537
538 ddp->ix = ix;
539 ddp->acc.mon = mtime_acc;
540 ddp->acc.sys = stime_acc;
541
542 max_drift = ERTS_MAX_MONOTONIC_DRIFT;
543 max_drift *= ERTS_MONOTONIC_TO_SEC(mtime_diff);
544
545 if (smtime_diff > time_sup.r.o.drift_adj.error + max_drift
546 || smtime_diff < -1*time_sup.r.o.drift_adj.error - max_drift) {
547 dirty_intervals:
548 /*
549 * We had a leap in system time. Mark array as
550 * dirty to ensure that dirty values are rotated
551 * out before we use it again...
552 */
553 ddp->dirty_counter = time_sup.r.o.drift_adj.intervals;
554 begin_short_intervals = 1;
555 }
556 else if (ddp->dirty_counter > 0) {
557 if (init_drift_adj) {
558 new_correction.drift = ((smtime_diff
559 * ERTS_MONOTONIC_TIME_UNIT)
560 / mtime_diff);
561 set_new_correction = 1;
562 }
563 ddp->dirty_counter--;
564 }
565 else {
566 if (ddp->dirty_counter == 0) {
567 /* Force set new drift correction... */
568 set_new_correction = 1;
569 ddp->dirty_counter--;
570 }
571
572 if (time_sup.r.o.drift_adj.use_avg)
573 drift_adj = (((stime_acc - mtime_acc)
574 * ERTS_MONOTONIC_TIME_UNIT)
575 / mtime_acc);
576 else
577 drift_adj = ((smtime_diff
578 * ERTS_MONOTONIC_TIME_UNIT)
579 / mtime_diff);
580
581 drift_adj_diff = avg_drift_adj - drift_adj;
582 if (drift_adj_diff < -ERTS_TIME_DRIFT_MAX_ADJ_DIFF
583 || ERTS_TIME_DRIFT_MAX_ADJ_DIFF < drift_adj_diff)
584 goto dirty_intervals;
585
586 drift_adj_diff = drift_adj - new_correction.drift;
587 if (drift_adj_diff) {
588 if (drift_adj_diff > ERTS_TIME_DRIFT_MAX_ADJ_DIFF)
589 drift_adj_diff = ERTS_TIME_DRIFT_MAX_ADJ_DIFF;
590 else if (drift_adj_diff < -ERTS_TIME_DRIFT_MAX_ADJ_DIFF)
591 drift_adj_diff = -ERTS_TIME_DRIFT_MAX_ADJ_DIFF;
592 new_correction.drift += drift_adj_diff;
593 if (drift_adj_diff < -ERTS_TIME_DRIFT_MIN_ADJ_DIFF
594 || ERTS_TIME_DRIFT_MIN_ADJ_DIFF < drift_adj_diff) {
595 set_new_correction = 1;
596 }
597 }
598 }
599 }
600 }
601
602 begin_short_intervals |= set_new_correction;
603
604 if (begin_short_intervals) {
605 time_sup.inf.c.parmon.cdata.short_check_interval
606 = ERTS_INIT_SHORT_INTERVAL_COUNTER;
607 }
608 else if ((os_mtime - time_sup.inf.c.parmon.cdata.last_check
609 >= ERTS_SHORT_TIME_CORRECTION_CHECK - ERTS_MONOTONIC_TIME_UNIT)
610 && time_sup.inf.c.parmon.cdata.short_check_interval > 0) {
611 time_sup.inf.c.parmon.cdata.short_check_interval--;
612 }
613 time_sup.inf.c.parmon.cdata.last_check = os_mtime;
614
615 if (new_correction.error == 0)
616 timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_LONG_TIME_CORRECTION_CHECK);
617 else {
618 ErtsMonotonicTime ecorr = new_correction.error;
619 ErtsMonotonicTime abs_sdiff;
620 abs_sdiff = (sdiff < 0) ? -1*sdiff : sdiff;
621 if (ecorr < 0)
622 ecorr = -1*ecorr;
623 if (abs_sdiff > ecorr*(ERTS_LONG_TIME_CORRECTION_CHECK/ERTS_TCORR_ERR_UNIT))
624 timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_LONG_TIME_CORRECTION_CHECK);
625 else {
626 timeout = ERTS_MONOTONIC_TO_MSEC((ERTS_TCORR_ERR_UNIT*abs_sdiff)/ecorr);
627 if (timeout < 10)
628 timeout = 10;
629 }
630 }
631
632 if (timeout > ERTS_MONOTONIC_TO_MSEC(ERTS_SHORT_TIME_CORRECTION_CHECK)
633 && (time_sup.inf.c.parmon.cdata.short_check_interval
634 || time_sup.inf.c.parmon.cdata.drift.dirty_counter >= 0)) {
635 timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_SHORT_TIME_CORRECTION_CHECK);
636 }
637
638 timeout_pos = get_timeout_pos(erl_mtime, timeout);
639
640 #ifdef ERTS_TIME_CORRECTION_PRINT
641 print_correction(set_new_correction,
642 sdiff,
643 ci.correction.error,
644 ci.correction.drift,
645 new_correction.error,
646 new_correction.drift,
647 timeout);
648 #endif
649
650 if (set_new_correction) {
651 erts_rwmtx_rwlock(&time_sup.inf.c.parmon.rwmtx);
652
653 os_mtime = erts_os_monotonic_time();
654
655 /* Save previous correction instance */
656 time_sup.inf.c.parmon.cdata.insts.prev = ci;
657
658 /*
659 * Current correction instance begin when
660 * OS monotonic time has increased two units.
661 */
662 os_mtime += 2;
663
664 /*
665 * Erlang monotonic time corresponding to
666 * next OS monotonic time using previous
667 * correction.
668 */
669 erl_mtime = calc_corrected_erl_mtime(os_mtime, &ci, NULL,
670 os_drift_corrected);
671
672 /*
673 * Save new current correction instance.
674 */
675 time_sup.inf.c.parmon.cdata.insts.curr.erl_mtime = erl_mtime;
676 time_sup.inf.c.parmon.cdata.insts.curr.os_mtime = os_mtime;
677 time_sup.inf.c.parmon.cdata.insts.curr.correction = new_correction;
678
679 erts_rwmtx_rwunlock(&time_sup.inf.c.parmon.rwmtx);
680 }
681
682 if (!esdp)
683 esdp = erts_get_scheduler_data();
684
685 erts_twheel_set_timer(esdp->timer_wheel,
686 &time_sup.inf.c.parmon.timer,
687 check_time_correction,
688 (void *) esdp,
689 timeout_pos);
690 }
691
get_os_corrected_time(void)692 static ErtsMonotonicTime get_os_corrected_time(void)
693 {
694 ASSERT(time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE);
695 return erts_os_monotonic_time() + time_sup.r.o.moffset;
696 }
697
698 static void
check_time_offset(void * vesdp)699 check_time_offset(void *vesdp)
700 {
701 ErtsSchedulerData *esdp = (ErtsSchedulerData *) vesdp;
702 ErtsMonotonicTime sdiff, os_mtime, erl_mtime, os_stime,
703 erl_stime, time_offset, timeout, timeout_pos;
704
705 ASSERT(time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE);
706
707 erts_os_times(&os_mtime, &os_stime);
708
709 erl_mtime = os_mtime + time_sup.r.o.moffset;
710 time_offset = get_time_offset();
711 erl_stime = erl_mtime + time_offset;
712
713 sdiff = erl_stime - os_stime;
714
715 if ((sdiff < -2*time_sup.r.o.adj.small_diff
716 || 2*time_sup.r.o.adj.small_diff < sdiff)) {
717 /* System time diff exeeded limits; change time offset... */
718 #ifdef ERTS_TIME_CORRECTION_PRINT
719 erts_fprintf(stderr, "sdiff = %b64d nsec -> 0 nsec\n",
720 ERTS_MONOTONIC_TO_NSEC(sdiff));
721 #endif
722 time_offset -= sdiff;
723 sdiff = 0;
724 set_time_offset(time_offset);
725 schedule_send_time_offset_changed_notifications(time_offset);
726 }
727 #ifdef ERTS_TIME_CORRECTION_PRINT
728 else erts_fprintf(stderr, "sdiff = %b64d nsec\n",
729 ERTS_MONOTONIC_TO_NSEC(sdiff));
730 #endif
731
732 timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_LONG_TIME_CORRECTION_CHECK);
733 timeout_pos = get_timeout_pos(erl_mtime, timeout);
734
735 erts_twheel_set_timer(esdp->timer_wheel,
736 &time_sup.inf.c.parmon.timer,
737 check_time_offset,
738 vesdp,
739 timeout_pos);
740 }
741
742 static void
init_check_time_correction(void * vesdp)743 init_check_time_correction(void *vesdp)
744 {
745 ErtsMonotonicDriftData *ddp;
746 ErtsMonotonicTime old_mtime, old_stime, mtime, stime, mtime_diff,
747 stime_diff, smtime_diff, max_drift;
748 int ix;
749
750 ddp = &time_sup.inf.c.parmon.cdata.drift;
751 ix = ddp->ix;
752 old_mtime = ddp->intervals[0].time.mon;
753 old_stime = ddp->intervals[0].time.sys;
754
755 erts_os_times(&mtime, &stime);
756
757 mtime_diff = mtime - old_mtime;
758 stime_diff = stime - old_stime;
759 smtime_diff = stime_diff - mtime_diff;
760
761 max_drift = ERTS_MAX_MONOTONIC_DRIFT;
762 max_drift *= ERTS_MONOTONIC_TO_SEC(mtime_diff);
763
764 if (smtime_diff > time_sup.r.o.drift_adj.error + max_drift
765 || smtime_diff < -1*time_sup.r.o.drift_adj.error - max_drift) {
766 /* Had a system time leap... pretend no drift... */
767 stime_diff = mtime_diff;
768 }
769
770 /*
771 * We use old time values in order to trigger
772 * a drift adjustment, and repeat this interval
773 * in all slots...
774 */
775 for (ix = 0; ix < time_sup.r.o.drift_adj.intervals; ix++) {
776 ddp->intervals[ix].diff.mon = mtime_diff;
777 ddp->intervals[ix].diff.sys = stime_diff;
778 ddp->intervals[ix].time.mon = old_mtime;
779 ddp->intervals[ix].time.sys = old_stime;
780 }
781
782 ddp->acc.sys = stime_diff*time_sup.r.o.drift_adj.intervals;
783 ddp->acc.mon = mtime_diff*time_sup.r.o.drift_adj.intervals;
784 ddp->ix = 0;
785 ddp->dirty_counter = time_sup.r.o.drift_adj.intervals;
786
787 check_time_correction(vesdp);
788 }
789
790 static ErtsMonotonicTime
finalize_corrected_time_offset(ErtsSystemTime * stimep)791 finalize_corrected_time_offset(ErtsSystemTime *stimep)
792 {
793 ErtsMonotonicTime os_mtime;
794 ErtsMonotonicCorrectionInstance ci;
795 int os_drift_corrected = time_sup.r.o.os_corrected_monotonic_time;
796
797 erts_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx);
798
799 erts_os_times(&os_mtime, stimep);
800
801 ci = time_sup.inf.c.parmon.cdata.insts.curr;
802
803 erts_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx);
804
805 if (os_mtime < ci.os_mtime)
806 erts_exit(ERTS_ABORT_EXIT,
807 "OS monotonic time stepped backwards\n");
808
809 return calc_corrected_erl_mtime(os_mtime, &ci, NULL,
810 os_drift_corrected);
811 }
812
813 static void
late_init_time_correction(ErtsSchedulerData * esdp)814 late_init_time_correction(ErtsSchedulerData *esdp)
815 {
816 int quick_init_drift_adj;
817 void (*check_func)(void *);
818 ErtsMonotonicTime timeout, timeout_pos;
819
820 quick_init_drift_adj =
821 ERTS_MONOTONIC_TO_USEC(time_sup.r.o.drift_adj.error) == 0;
822
823 if (quick_init_drift_adj)
824 timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_SHORT_TIME_CORRECTION_CHECK/10);
825 else
826 timeout = ERTS_MONOTONIC_TO_MSEC(ERTS_SHORT_TIME_CORRECTION_CHECK);
827
828 if (!time_sup.r.o.os_corrected_monotonic_time)
829 check_func = init_check_time_correction;
830 else if (time_sup.r.o.get_time == get_os_corrected_time) {
831 quick_init_drift_adj = 0;
832 check_func = check_time_offset;
833 }
834 else
835 check_func = check_time_correction;
836
837 timeout_pos = get_timeout_pos(erts_get_monotonic_time(esdp),
838 timeout);
839
840 erts_twheel_init_timer(&time_sup.inf.c.parmon.timer);
841 erts_twheel_set_timer(esdp->timer_wheel,
842 &time_sup.inf.c.parmon.timer,
843 check_func,
844 (quick_init_drift_adj
845 ? NULL
846 : esdp),
847 timeout_pos);
848 }
849
850 #endif /* ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT */
851
get_not_corrected_time(void)852 static ErtsMonotonicTime get_not_corrected_time(void)
853 {
854 ErtsMonotonicTime stime, mtime;
855
856 erts_mtx_lock(&erts_get_time_mtx);
857
858 stime = erts_os_system_time();
859
860 mtime = stime - time_sup.inf.c.not_corrected_moffset;
861
862 if (mtime >= time_sup.f.c.last_not_corrected_time)
863 time_sup.f.c.last_not_corrected_time = mtime;
864 else {
865 mtime = time_sup.f.c.last_not_corrected_time;
866
867 if (time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE) {
868 ErtsMonotonicTime new_offset = stime - mtime;
869 new_offset = ERTS_MONOTONIC_TO_USEC(new_offset);
870 new_offset = ERTS_USEC_TO_MONOTONIC(new_offset);
871 if (time_sup.inf.c.not_corrected_moffset != new_offset) {
872 time_sup.inf.c.not_corrected_moffset = new_offset;
873 set_time_offset(new_offset);
874 schedule_send_time_offset_changed_notifications(new_offset);
875 }
876 }
877
878 }
879
880 ASSERT(stime == mtime + time_sup.inf.c.not_corrected_moffset);
881
882 erts_mtx_unlock(&erts_get_time_mtx);
883
884 return mtime;
885 }
886
erts_check_time_adj_support(int time_correction,ErtsTimeWarpMode time_warp_mode)887 int erts_check_time_adj_support(int time_correction,
888 ErtsTimeWarpMode time_warp_mode)
889 {
890 if (!time_correction)
891 return 1;
892
893 /* User wants time correction */
894
895 #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
896 return !time_sup.r.o.os_monotonic_time_disable;
897 #else
898 return 0;
899 #endif
900 }
901
902 int
erts_has_time_correction(void)903 erts_has_time_correction(void)
904 {
905 return time_sup.r.o.correction;
906 }
907
erts_init_sys_time_sup(void)908 void erts_init_sys_time_sup(void)
909 {
910 ErtsSysInitTimeResult sys_init_time_res
911 = ERTS_SYS_INIT_TIME_RESULT_INITER;
912
913 sys_init_time(&sys_init_time_res);
914
915 erts_time_sup__.r.o.monotonic_time_unit
916 = sys_init_time_res.os_monotonic_time_unit;
917
918 #ifndef SYS_CLOCK_RESOLUTION
919 erts_time_sup__.r.o.clktck_resolution
920 = sys_init_time_res.sys_clock_resolution;
921 erts_time_sup__.r.o.clktck_resolution *= 1000;
922 #endif
923
924 #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
925 time_sup.r.o.os_monotonic_time_disable
926 = !sys_init_time_res.have_os_monotonic_time;
927 time_sup.r.o.os_corrected_monotonic_time =
928 sys_init_time_res.have_corrected_os_monotonic_time;
929 time_sup.r.o.os_monotonic_time_func
930 = sys_init_time_res.os_monotonic_time_info.func;
931 time_sup.r.o.os_monotonic_time_clock_id
932 = sys_init_time_res.os_monotonic_time_info.clock_id;
933 time_sup.r.o.os_monotonic_time_locked
934 = sys_init_time_res.os_monotonic_time_info.locked_use;
935 time_sup.r.o.os_monotonic_time_resolution
936 = sys_init_time_res.os_monotonic_time_info.resolution;
937 time_sup.r.o.os_monotonic_time_extended
938 = sys_init_time_res.os_monotonic_time_info.extended;
939 #endif
940 time_sup.r.o.os_system_time_func
941 = sys_init_time_res.os_system_time_info.func;
942 time_sup.r.o.os_system_time_clock_id
943 = sys_init_time_res.os_system_time_info.clock_id;
944 time_sup.r.o.os_system_time_locked
945 = sys_init_time_res.os_system_time_info.locked_use;
946 time_sup.r.o.os_system_time_resolution
947 = sys_init_time_res.os_system_time_info.resolution;
948 }
949
950 int
erts_init_time_sup(int time_correction,ErtsTimeWarpMode time_warp_mode)951 erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode)
952 {
953 ErtsMonotonicTime resolution, ilength, intervals, short_isecs;
954 #if !ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT
955 ErtsMonotonicTime abs_native_offset, native_offset;
956 #endif
957
958 init_time_napi();
959
960 erts_hl_timer_init();
961
962 ASSERT(ERTS_MONOTONIC_TIME_MIN < ERTS_MONOTONIC_TIME_MAX);
963
964 erts_mtx_init(&erts_get_time_mtx, "get_time", NIL,
965 ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC);
966 erts_mtx_init(&runtime_prev.data.mtx, "runtime", NIL,
967 ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC);
968 runtime_prev.data.user = 0;
969 runtime_prev.data.sys = 0;
970
971 time_sup.r.o.correction = time_correction;
972 time_sup.r.o.warp_mode = time_warp_mode;
973
974 if (time_warp_mode == ERTS_SINGLE_TIME_WARP_MODE)
975 erts_atomic32_init_nob(&time_sup.inf.c.preliminary_offset, 1);
976 else
977 erts_atomic32_init_nob(&time_sup.inf.c.preliminary_offset, 0);
978 time_sup.inf.c.shadow_offset = 0;
979
980 #if !ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT
981
982 /*
983 * NOTE! erts_time_sup__.r.o.start *need* to be a multiple
984 * of ERTS_MONOTONIC_TIME_UNIT.
985 */
986
987 #ifdef ARCH_32
988 erts_time_sup__.r.o.start = ((((ErtsMonotonicTime) 1) << 32)-1);
989 erts_time_sup__.r.o.start /= ERTS_MONOTONIC_TIME_UNIT;
990 erts_time_sup__.r.o.start *= ERTS_MONOTONIC_TIME_UNIT;
991 erts_time_sup__.r.o.start += ERTS_MONOTONIC_TIME_UNIT;
992 native_offset = erts_time_sup__.r.o.start - ERTS_MONOTONIC_BEGIN;
993 abs_native_offset = native_offset;
994 #else /* ARCH_64 */
995 if (ERTS_MONOTONIC_TIME_UNIT <= 10*1000*1000) {
996 erts_time_sup__.r.o.start = 0;
997 native_offset = -ERTS_MONOTONIC_BEGIN;
998 abs_native_offset = ERTS_MONOTONIC_BEGIN;
999 }
1000 else {
1001 erts_time_sup__.r.o.start = ((ErtsMonotonicTime) MIN_SMALL);
1002 erts_time_sup__.r.o.start /= ERTS_MONOTONIC_TIME_UNIT;
1003 erts_time_sup__.r.o.start *= ERTS_MONOTONIC_TIME_UNIT;
1004 native_offset = erts_time_sup__.r.o.start - ERTS_MONOTONIC_BEGIN;
1005 abs_native_offset = -1*native_offset;
1006 }
1007 #endif
1008
1009 erts_time_sup__.r.o.start_offset.native = native_offset;
1010 erts_time_sup__.r.o.start_offset.nsec = (ErtsMonotonicTime)
1011 erts_time_unit_conversion((Uint64) abs_native_offset,
1012 (Uint32) ERTS_MONOTONIC_TIME_UNIT,
1013 (Uint32) 1000*1000*1000);
1014 erts_time_sup__.r.o.start_offset.usec = (ErtsMonotonicTime)
1015 erts_time_unit_conversion((Uint64) abs_native_offset,
1016 (Uint32) ERTS_MONOTONIC_TIME_UNIT,
1017 (Uint32) 1000*1000);
1018 erts_time_sup__.r.o.start_offset.msec = (ErtsMonotonicTime)
1019 erts_time_unit_conversion((Uint64) abs_native_offset,
1020 (Uint32) ERTS_MONOTONIC_TIME_UNIT,
1021 (Uint32) 1000);
1022 erts_time_sup__.r.o.start_offset.sec = (ErtsMonotonicTime)
1023 erts_time_unit_conversion((Uint64) abs_native_offset,
1024 (Uint32) ERTS_MONOTONIC_TIME_UNIT,
1025 (Uint32) 1);
1026 if (native_offset < 0) {
1027 erts_time_sup__.r.o.start_offset.nsec *= -1;
1028 erts_time_sup__.r.o.start_offset.usec *= -1;
1029 erts_time_sup__.r.o.start_offset.msec *= -1;
1030 erts_time_sup__.r.o.start_offset.sec *= -1;
1031 }
1032
1033 #endif
1034
1035 resolution = time_sup.r.o.os_system_time_resolution;
1036 #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
1037 if (resolution > time_sup.r.o.os_monotonic_time_resolution)
1038 resolution = time_sup.r.o.os_monotonic_time_resolution;
1039 #endif
1040
1041 time_sup.r.o.adj.large_diff = erts_time_sup__.r.o.monotonic_time_unit;
1042 time_sup.r.o.adj.large_diff *= 50;
1043 time_sup.r.o.adj.large_diff /= resolution;
1044 if (time_sup.r.o.adj.large_diff < ERTS_USEC_TO_MONOTONIC(500))
1045 time_sup.r.o.adj.large_diff = ERTS_USEC_TO_MONOTONIC(500);
1046 time_sup.r.o.adj.small_diff = time_sup.r.o.adj.large_diff/10;
1047
1048 time_sup.r.o.drift_adj.resolution = resolution;
1049
1050 if (time_sup.r.o.os_corrected_monotonic_time) {
1051 time_sup.r.o.drift_adj.use_avg = 0;
1052 time_sup.r.o.drift_adj.intervals = 0;
1053 time_sup.r.o.drift_adj.error = 0;
1054 time_sup.inf.c.parmon.cdata.drift.dirty_counter = -1;
1055 }
1056 else {
1057 /*
1058 * Calculate length of the interval in seconds needed
1059 * in order to get an error that is at most 1 micro second.
1060 * If this interval is longer than the short time correction
1061 * check interval we use the average of all values instead
1062 * of the latest value.
1063 */
1064 short_isecs = ERTS_MONOTONIC_TO_SEC(ERTS_SHORT_TIME_CORRECTION_CHECK);
1065 ilength = ERTS_ASSUMED_PRECISION_DROP * ERTS_MONOTONIC_TIME_UNIT;
1066 ilength /= (resolution * ERTS_USEC_TO_MONOTONIC(1));
1067 time_sup.r.o.drift_adj.use_avg = ilength > short_isecs;
1068
1069 if (ilength == 0)
1070 intervals = 5;
1071 else {
1072 intervals = ilength / short_isecs;
1073 if (intervals > ERTS_MAX_DRIFT_INTERVALS)
1074 intervals = ERTS_MAX_DRIFT_INTERVALS;
1075 else if (intervals < 5)
1076 intervals = 5;
1077 }
1078 time_sup.r.o.drift_adj.intervals = (int) intervals;
1079
1080 /*
1081 * drift_adj.error equals maximum assumed error
1082 * over a short time interval. We use this value also
1083 * when examining a large interval. In this case the
1084 * error will be smaller, but we do not want to
1085 * recalculate this over and over again.
1086 */
1087
1088 time_sup.r.o.drift_adj.error = ERTS_MONOTONIC_TIME_UNIT;
1089 time_sup.r.o.drift_adj.error *= ERTS_ASSUMED_PRECISION_DROP;
1090 time_sup.r.o.drift_adj.error /= resolution * short_isecs;
1091 }
1092 #ifdef ERTS_TIME_CORRECTION_PRINT
1093 erts_fprintf(stderr, "resolution = %b64d\n", resolution);
1094 erts_fprintf(stderr, "adj large diff = %b64d usec\n",
1095 ERTS_MONOTONIC_TO_USEC(time_sup.r.o.adj.large_diff));
1096 erts_fprintf(stderr, "adj small diff = %b64d usec\n",
1097 ERTS_MONOTONIC_TO_USEC(time_sup.r.o.adj.small_diff));
1098 if (!time_sup.r.o.os_corrected_monotonic_time) {
1099 erts_fprintf(stderr, "drift intervals = %d\n",
1100 time_sup.r.o.drift_adj.intervals);
1101 erts_fprintf(stderr, "drift adj error = %b64d usec\n",
1102 ERTS_MONOTONIC_TO_USEC(time_sup.r.o.drift_adj.error));
1103 erts_fprintf(stderr, "drift adj max diff = %b64d nsec\n",
1104 ERTS_MONOTONIC_TO_NSEC(ERTS_TIME_DRIFT_MAX_ADJ_DIFF));
1105 erts_fprintf(stderr, "drift adj min diff = %b64d nsec\n",
1106 ERTS_MONOTONIC_TO_NSEC(ERTS_TIME_DRIFT_MIN_ADJ_DIFF));
1107 }
1108 #endif
1109
1110 if (ERTS_MONOTONIC_TIME_UNIT < ERTS_CLKTCK_RESOLUTION)
1111 ERTS_INTERNAL_ERROR("Too small monotonic time time unit");
1112
1113 #ifndef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
1114 time_sup.r.o.correction = 0;
1115 #else
1116 if (time_sup.r.o.os_monotonic_time_disable)
1117 time_sup.r.o.correction = 0;
1118
1119 if (time_sup.r.o.correction) {
1120 ErtsMonotonicCorrectionData *cdatap;
1121 erts_rwmtx_opt_t rwmtx_opts = ERTS_RWMTX_OPT_DEFAULT_INITER;
1122 ErtsMonotonicTime offset;
1123 erts_os_times(&time_sup.inf.c.minit,
1124 &time_sup.inf.c.sinit);
1125 time_sup.r.o.moffset = -1*time_sup.inf.c.minit;
1126 time_sup.r.o.moffset += ERTS_MONOTONIC_BEGIN;
1127 offset = time_sup.inf.c.sinit;
1128 offset -= ERTS_MONOTONIC_BEGIN;
1129 init_time_offset(offset);
1130
1131 rwmtx_opts.type = ERTS_RWMTX_TYPE_EXTREMELY_FREQUENT_READ;
1132 rwmtx_opts.lived = ERTS_RWMTX_LONG_LIVED;
1133
1134 erts_rwmtx_init_opt(&time_sup.inf.c.parmon.rwmtx, &rwmtx_opts,
1135 "get_corrected_time", NIL,
1136 ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC);
1137
1138 cdatap = &time_sup.inf.c.parmon.cdata;
1139
1140 cdatap->drift.intervals[0].time.sys = time_sup.inf.c.sinit;
1141 cdatap->drift.intervals[0].time.mon = time_sup.inf.c.minit;
1142 cdatap->insts.curr.correction.drift = 0;
1143 cdatap->insts.curr.correction.error = 0;
1144 cdatap->insts.curr.erl_mtime = ERTS_MONOTONIC_BEGIN;
1145 cdatap->insts.curr.os_mtime = time_sup.inf.c.minit;
1146 cdatap->last_check = time_sup.inf.c.minit;
1147 cdatap->short_check_interval = ERTS_INIT_SHORT_INTERVAL_COUNTER;
1148 cdatap->insts.prev = cdatap->insts.curr;
1149
1150 if (!time_sup.r.o.os_corrected_monotonic_time)
1151 time_sup.r.o.get_time = get_corrected_time;
1152 else if (time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE)
1153 time_sup.r.o.get_time = get_os_corrected_time;
1154 else
1155 time_sup.r.o.get_time = get_os_drift_corrected_time;
1156 }
1157 else
1158 #endif
1159 {
1160 ErtsMonotonicTime stime, offset;
1161 time_sup.r.o.get_time = get_not_corrected_time;
1162 stime = time_sup.inf.c.sinit = erts_os_system_time();
1163 offset = stime - ERTS_MONOTONIC_BEGIN;
1164 time_sup.inf.c.not_corrected_moffset = offset;
1165 init_time_offset(offset);
1166 time_sup.f.c.last_not_corrected_time = 0;
1167 }
1168
1169 erts_atomic64_init_nob(&wall_clock_prev.time,
1170 (erts_aint64_t) 0);
1171
1172 erts_atomic64_init_nob(
1173 &now_prev.time,
1174 (erts_aint64_t) ERTS_MONOTONIC_TO_USEC(get_time_offset()));
1175
1176
1177 #ifdef DEBUG
1178 time_sup_initialized = 1;
1179 #endif
1180
1181 return ERTS_CLKTCK_RESOLUTION/1000;
1182 }
1183
1184 void
erts_late_init_time_sup(void)1185 erts_late_init_time_sup(void)
1186 {
1187 erts_late_sys_init_time();
1188 }
1189
1190 void
erts_sched_init_time_sup(ErtsSchedulerData * esdp)1191 erts_sched_init_time_sup(ErtsSchedulerData *esdp)
1192 {
1193 esdp->timer_wheel = erts_create_timer_wheel(esdp);
1194 esdp->next_tmo_ref = erts_get_next_timeout_reference(esdp->timer_wheel);
1195 esdp->timer_service = erts_create_timer_service();
1196 #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
1197 if (esdp->no == 1) {
1198 /* A timer wheel to use must have beeen initialized */
1199 if (time_sup.r.o.get_time != get_not_corrected_time)
1200 late_init_time_correction(esdp);
1201 }
1202 #endif
1203 }
1204
erts_time_warp_mode(void)1205 ErtsTimeWarpMode erts_time_warp_mode(void)
1206 {
1207 return time_sup.r.o.warp_mode;
1208 }
1209
erts_time_offset_state(void)1210 ErtsTimeOffsetState erts_time_offset_state(void)
1211 {
1212 switch (time_sup.r.o.warp_mode) {
1213 case ERTS_NO_TIME_WARP_MODE:
1214 return ERTS_TIME_OFFSET_FINAL;
1215 case ERTS_SINGLE_TIME_WARP_MODE:
1216 if (erts_atomic32_read_nob(&time_sup.inf.c.preliminary_offset))
1217 return ERTS_TIME_OFFSET_PRELIMINARY;
1218 return ERTS_TIME_OFFSET_FINAL;
1219 case ERTS_MULTI_TIME_WARP_MODE:
1220 return ERTS_TIME_OFFSET_VOLATILE;
1221 default:
1222 ERTS_INTERNAL_ERROR("Invalid time warp mode");
1223 return ERTS_TIME_OFFSET_VOLATILE;
1224 }
1225 }
1226
1227 /*
1228 * erts_finalize_time_offset() will only change time offset
1229 * the first time it is called when the emulator has been
1230 * started in "single time warp" mode. Returns previous
1231 * state:
1232 * * ERTS_TIME_OFFSET_PRELIMINARY - Finalization performed
1233 * * ERTS_TIME_OFFSET_FINAL - Already finialized; nothing changed
1234 * * ERTS_TIME_OFFSET_VOLATILE - Not supported, either in
1235 * * no correction mode (or multi time warp mode; not yet implemented).
1236 */
1237
1238 ErtsTimeOffsetState
erts_finalize_time_offset(void)1239 erts_finalize_time_offset(void)
1240 {
1241 switch (time_sup.r.o.warp_mode) {
1242 case ERTS_NO_TIME_WARP_MODE:
1243 return ERTS_TIME_OFFSET_FINAL;
1244 case ERTS_MULTI_TIME_WARP_MODE:
1245 return ERTS_TIME_OFFSET_VOLATILE;
1246 case ERTS_SINGLE_TIME_WARP_MODE: {
1247 ErtsTimeOffsetState res = ERTS_TIME_OFFSET_FINAL;
1248
1249 erts_mtx_lock(&erts_get_time_mtx);
1250
1251 if (erts_atomic32_read_nob(&time_sup.inf.c.preliminary_offset)) {
1252 ErtsMonotonicTime mtime, new_offset;
1253
1254 #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
1255 if (!time_sup.r.o.correction)
1256 #endif
1257 {
1258 ErtsMonotonicTime stime = erts_os_system_time();
1259
1260 mtime = stime - time_sup.inf.c.not_corrected_moffset;
1261
1262 if (mtime >= time_sup.f.c.last_not_corrected_time) {
1263 time_sup.f.c.last_not_corrected_time = mtime;
1264 new_offset = time_sup.inf.c.not_corrected_moffset;
1265 }
1266 else {
1267 mtime = time_sup.f.c.last_not_corrected_time;
1268
1269 ASSERT(time_sup.inf.c.not_corrected_moffset != stime - mtime);
1270 new_offset = stime - mtime;
1271 time_sup.inf.c.not_corrected_moffset = new_offset;
1272 }
1273
1274 }
1275 #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
1276 else {
1277 ErtsSystemTime stime;
1278 mtime = finalize_corrected_time_offset(&stime);
1279 new_offset = stime - mtime;
1280 }
1281 #endif
1282 new_offset = ERTS_MONOTONIC_TO_USEC(new_offset);
1283 new_offset = ERTS_USEC_TO_MONOTONIC(new_offset);
1284
1285 set_time_offset(new_offset);
1286 schedule_send_time_offset_changed_notifications(new_offset);
1287
1288 erts_atomic32_set_nob(&time_sup.inf.c.preliminary_offset, 0);
1289 res = ERTS_TIME_OFFSET_PRELIMINARY;
1290 }
1291
1292 erts_mtx_unlock(&erts_get_time_mtx);
1293
1294 return res;
1295 }
1296 default:
1297 ERTS_INTERNAL_ERROR("Invalid time warp mode");
1298 return ERTS_TIME_OFFSET_VOLATILE;
1299 }
1300 }
1301
1302 /* info functions */
1303
1304 void
erts_runtime_elapsed_both(ErtsMonotonicTime * ms_user,ErtsMonotonicTime * ms_sys,ErtsMonotonicTime * ms_user_diff,ErtsMonotonicTime * ms_sys_diff)1305 erts_runtime_elapsed_both(ErtsMonotonicTime *ms_user, ErtsMonotonicTime *ms_sys,
1306 ErtsMonotonicTime *ms_user_diff, ErtsMonotonicTime *ms_sys_diff)
1307 {
1308 ErtsMonotonicTime prev_user, prev_sys, user, sys;
1309
1310 #ifdef HAVE_GETRUSAGE
1311
1312 struct rusage now;
1313
1314 if (getrusage(RUSAGE_SELF, &now) != 0) {
1315 erts_exit(ERTS_ABORT_EXIT, "getrusage(RUSAGE_SELF, _) failed: %d\n", errno);
1316 return;
1317 }
1318
1319 user = (ErtsMonotonicTime) now.ru_utime.tv_sec;
1320 user *= (ErtsMonotonicTime) 1000000;
1321 user += (ErtsMonotonicTime) now.ru_utime.tv_usec;
1322 user /= (ErtsMonotonicTime) 1000;
1323
1324 sys = (ErtsMonotonicTime) now.ru_stime.tv_sec;
1325 sys *= (ErtsMonotonicTime) 1000000;
1326 sys += (ErtsMonotonicTime) now.ru_stime.tv_usec;
1327 sys /= (ErtsMonotonicTime) 1000;
1328
1329 #else
1330
1331 SysTimes now;
1332
1333 sys_times(&now);
1334 user = (ErtsMonotonicTime) now.tms_utime;
1335 user *= (ErtsMonotonicTime) 1000;
1336 user /= (ErtsMonotonicTime) SYS_CLK_TCK;
1337
1338 sys = (ErtsMonotonicTime) now.tms_stime;
1339 sys *= (ErtsMonotonicTime) 1000;
1340 sys /= (ErtsMonotonicTime) SYS_CLK_TCK;
1341
1342 #endif
1343
1344 if (ms_user)
1345 *ms_user = user;
1346 if (ms_sys)
1347 *ms_sys = sys;
1348
1349 if (ms_user_diff || ms_sys_diff) {
1350
1351 erts_mtx_lock(&runtime_prev.data.mtx);
1352
1353 prev_user = runtime_prev.data.user;
1354 prev_sys = runtime_prev.data.sys;
1355 runtime_prev.data.user = user;
1356 runtime_prev.data.sys = sys;
1357
1358 erts_mtx_unlock(&runtime_prev.data.mtx);
1359
1360 if (ms_user_diff)
1361 *ms_user_diff = user - prev_user;
1362 if (ms_sys_diff)
1363 *ms_sys_diff = sys - prev_sys;
1364 }
1365 }
1366
1367
1368 /* wall clock routines */
1369
1370 void
erts_wall_clock_elapsed_both(ErtsMonotonicTime * ms_total,ErtsMonotonicTime * ms_diff)1371 erts_wall_clock_elapsed_both(ErtsMonotonicTime *ms_total, ErtsMonotonicTime *ms_diff)
1372 {
1373 ErtsMonotonicTime now, elapsed;
1374
1375 now = time_sup.r.o.get_time();
1376 update_last_mtime(NULL, now);
1377
1378 elapsed = ERTS_MONOTONIC_TO_MSEC(now);
1379 elapsed -= ERTS_MONOTONIC_TO_MSEC(ERTS_MONOTONIC_BEGIN);
1380
1381 *ms_total = elapsed;
1382
1383 if (ms_diff) {
1384 ErtsMonotonicTime prev;
1385
1386 prev = ((ErtsMonotonicTime)
1387 erts_atomic64_xchg_mb(&wall_clock_prev.time,
1388 (erts_aint64_t) elapsed));
1389
1390 *ms_diff = elapsed - prev;
1391 }
1392 }
1393
1394 /* get current time */
1395 void
get_time(int * hour,int * minute,int * second)1396 get_time(int *hour, int *minute, int *second)
1397 {
1398 time_t the_clock;
1399 struct tm *tm;
1400 #ifdef HAVE_LOCALTIME_R
1401 struct tm tmbuf;
1402 #endif
1403
1404 the_clock = time((time_t *)0);
1405 #ifdef HAVE_LOCALTIME_R
1406 tm = localtime_r(&the_clock, &tmbuf);
1407 #else
1408 tm = localtime(&the_clock);
1409 #endif
1410 *hour = tm->tm_hour;
1411 *minute = tm->tm_min;
1412 *second = tm->tm_sec;
1413 }
1414
1415 /* get current date */
1416 void
get_date(int * year,int * month,int * day)1417 get_date(int *year, int *month, int *day)
1418 {
1419 time_t the_clock;
1420 struct tm *tm;
1421 #ifdef HAVE_LOCALTIME_R
1422 struct tm tmbuf;
1423 #endif
1424
1425
1426 the_clock = time((time_t *)0);
1427 #ifdef HAVE_LOCALTIME_R
1428 tm = localtime_r(&the_clock, &tmbuf);
1429 #else
1430 tm = localtime(&the_clock);
1431 #endif
1432 *year = tm->tm_year + 1900;
1433 *month = tm->tm_mon +1;
1434 *day = tm->tm_mday;
1435 }
1436
1437 /* get localtime */
1438 void
get_localtime(int * year,int * month,int * day,int * hour,int * minute,int * second)1439 get_localtime(int *year, int *month, int *day,
1440 int *hour, int *minute, int *second)
1441 {
1442 time_t the_clock;
1443 struct tm *tm;
1444 #ifdef HAVE_LOCALTIME_R
1445 struct tm tmbuf;
1446 #endif
1447
1448 the_clock = time((time_t *)0);
1449 #ifdef HAVE_LOCALTIME_R
1450 localtime_r(&the_clock, (tm = &tmbuf));
1451 #else
1452 tm = localtime(&the_clock);
1453 #endif
1454 *year = tm->tm_year + 1900;
1455 *month = tm->tm_mon +1;
1456 *day = tm->tm_mday;
1457 *hour = tm->tm_hour;
1458 *minute = tm->tm_min;
1459 *second = tm->tm_sec;
1460 }
1461
1462
1463 /* get universaltime */
1464 void
get_universaltime(int * year,int * month,int * day,int * hour,int * minute,int * second)1465 get_universaltime(int *year, int *month, int *day,
1466 int *hour, int *minute, int *second)
1467 {
1468 time_t the_clock;
1469 struct tm *tm;
1470 #ifdef HAVE_GMTIME_R
1471 struct tm tmbuf;
1472 #endif
1473
1474 the_clock = time((time_t *)0);
1475 #ifdef HAVE_GMTIME_R
1476 gmtime_r(&the_clock, (tm = &tmbuf));
1477 #else
1478 tm = gmtime(&the_clock);
1479 #endif
1480 *year = tm->tm_year + 1900;
1481 *month = tm->tm_mon +1;
1482 *day = tm->tm_mday;
1483 *hour = tm->tm_hour;
1484 *minute = tm->tm_min;
1485 *second = tm->tm_sec;
1486 }
1487
1488
1489 /* days in month = 1, 2, ..., 12 */
1490 static const int mdays[14] = {0, 31, 28, 31, 30, 31, 30,
1491 31, 31, 30, 31, 30, 31};
1492
1493 #define IN_RANGE(a,x,b) (((a) <= (x)) && ((x) <= (b)))
1494 #define is_leap_year(y) (((((y) % 4) == 0) && \
1495 (((y) % 100) != 0)) || \
1496 (((y) % 400) == 0))
1497
1498 /* This is the earliest year we are sure to be able to handle
1499 on all platforms w/o problems */
1500 #define BASEYEAR 1902
1501
1502 /* A more "clever" mktime
1503 * return 1, if successful
1504 * return -1, if not successful
1505 */
1506
erl_mktime(time_t * c,struct tm * tm)1507 static int erl_mktime(time_t *c, struct tm *tm) {
1508 time_t clock;
1509
1510 clock = mktime(tm);
1511
1512 if (clock != -1) {
1513 *c = clock;
1514 return 1;
1515 }
1516
1517 /* in rare occasions mktime returns -1
1518 * when a correct value has been entered
1519 *
1520 * decrease seconds with one second
1521 * if the result is -2, epochs should be -1
1522 */
1523
1524 tm->tm_sec = tm->tm_sec - 1;
1525 clock = mktime(tm);
1526 tm->tm_sec = tm->tm_sec + 1;
1527
1528 *c = -1;
1529
1530 if (clock == -2) {
1531 return 1;
1532 }
1533
1534 return -1;
1535 }
1536
1537 /*
1538 * gregday
1539 *
1540 * Returns the number of days since Jan 1, 1600, if year is
1541 * greater of equal to 1600 , and month [1-12] and day [1-31]
1542 * are within range. Otherwise it returns -1.
1543 */
gregday(int year,int month,int day)1544 static time_t gregday(int year, int month, int day)
1545 {
1546 Sint ndays = 0;
1547 Sint gyear, pyear, m;
1548
1549 /* number of days in previous years */
1550 gyear = year - 1600;
1551 if (gyear > 0) {
1552 pyear = gyear - 1;
1553 ndays = (pyear/4) - (pyear/100) + (pyear/400) + pyear*365 + 366;
1554 }
1555 /* number of days in all months preceding month */
1556 for (m = 1; m < month; m++)
1557 ndays += mdays[m];
1558 /* Extra day if leap year and March or later */
1559 if (is_leap_year(year) && (month > 2))
1560 ndays++;
1561 ndays += day - 1;
1562 return (time_t) (ndays - 135140); /* 135140 = Jan 1, 1970 */
1563 }
1564
1565 #define SECONDS_PER_MINUTE (60)
1566 #define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE)
1567 #define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR)
1568
seconds_to_univ(Sint64 time,Sint * year,Sint * month,Sint * day,Sint * hour,Sint * minute,Sint * second)1569 int seconds_to_univ(Sint64 time, Sint *year, Sint *month, Sint *day,
1570 Sint *hour, Sint *minute, Sint *second) {
1571
1572 Sint y,mi;
1573 Sint days = time / SECONDS_PER_DAY;
1574 Sint secs = time % SECONDS_PER_DAY;
1575 Sint tmp;
1576
1577 if (secs < 0) {
1578 days--;
1579 secs += SECONDS_PER_DAY;
1580 }
1581
1582 tmp = secs % SECONDS_PER_HOUR;
1583
1584 *hour = secs / SECONDS_PER_HOUR;
1585 *minute = tmp / SECONDS_PER_MINUTE;
1586 *second = tmp % SECONDS_PER_MINUTE;
1587
1588 days += 719468;
1589 y = (10000*((Sint64)days) + 14780) / 3652425;
1590 tmp = days - (365 * y + y/4 - y/100 + y/400);
1591
1592 if (tmp < 0) {
1593 y--;
1594 tmp = days - (365*y + y/4 - y/100 + y/400);
1595 }
1596 mi = (100 * tmp + 52)/3060;
1597 *month = (mi + 2) % 12 + 1;
1598 *year = y + (mi + 2) / 12;
1599 *day = tmp - (mi * 306 + 5)/10 + 1;
1600
1601 return 1;
1602 }
1603
univ_to_seconds(Sint year,Sint month,Sint day,Sint hour,Sint minute,Sint second,Sint64 * time)1604 int univ_to_seconds(Sint year, Sint month, Sint day, Sint hour, Sint minute, Sint second, Sint64 *time) {
1605 Sint days;
1606
1607 if (!(IN_RANGE(1600, year, INT_MAX - 1) &&
1608 IN_RANGE(1, month, 12) &&
1609 IN_RANGE(1, day, (mdays[month] +
1610 (month == 2
1611 && (year % 4 == 0)
1612 && (year % 100 != 0 || year % 400 == 0)))) &&
1613 IN_RANGE(0, hour, 23) &&
1614 IN_RANGE(0, minute, 59) &&
1615 IN_RANGE(0, second, 59))) {
1616 return 0;
1617 }
1618
1619 days = gregday(year, month, day);
1620 *time = SECONDS_PER_DAY;
1621 *time *= days; /* don't try overflow it, it hurts */
1622 *time += SECONDS_PER_HOUR * hour;
1623 *time += SECONDS_PER_MINUTE * minute;
1624 *time += second;
1625
1626 return 1;
1627 }
1628
1629 #if defined(HAVE_TIME2POSIX) && defined(HAVE_DECL_TIME2POSIX) && \
1630 !HAVE_DECL_TIME2POSIX
1631 extern time_t time2posix(time_t);
1632 #endif
1633
1634 int
local_to_univ(Sint * year,Sint * month,Sint * day,Sint * hour,Sint * minute,Sint * second,int isdst)1635 local_to_univ(Sint *year, Sint *month, Sint *day,
1636 Sint *hour, Sint *minute, Sint *second, int isdst)
1637 {
1638 time_t the_clock;
1639 struct tm *tm, t;
1640 #ifdef HAVE_GMTIME_R
1641 struct tm tmbuf;
1642 #endif
1643
1644 if (!(IN_RANGE(BASEYEAR, *year, INT_MAX - 1) &&
1645 IN_RANGE(1, *month, 12) &&
1646 IN_RANGE(1, *day, (mdays[*month] +
1647 (*month == 2
1648 && (*year % 4 == 0)
1649 && (*year % 100 != 0 || *year % 400 == 0)))) &&
1650 IN_RANGE(0, *hour, 23) &&
1651 IN_RANGE(0, *minute, 59) &&
1652 IN_RANGE(0, *second, 59))) {
1653 return 0;
1654 }
1655
1656 t.tm_year = *year - 1900;
1657 t.tm_mon = *month - 1;
1658 t.tm_mday = *day;
1659 t.tm_hour = *hour;
1660 t.tm_min = *minute;
1661 t.tm_sec = *second;
1662 t.tm_isdst = isdst;
1663
1664 /* the nature of mktime makes this a bit interesting,
1665 * up to four mktime calls could happen here
1666 */
1667
1668 if (erl_mktime(&the_clock, &t) < 0) {
1669 if (isdst) {
1670 /* If this is a timezone without DST and the OS (correctly)
1671 refuses to give us a DST time, we simulate the Linux/Solaris
1672 behaviour of giving the same data as if is_dst was not set. */
1673 t.tm_isdst = 0;
1674 if (erl_mktime(&the_clock, &t) < 0) {
1675 /* Failed anyway, something else is bad - will be a badarg */
1676 return 0;
1677 }
1678 } else {
1679 /* Something else is the matter, badarg. */
1680 return 0;
1681 }
1682 }
1683
1684 #ifdef HAVE_TIME2POSIX
1685 the_clock = time2posix(the_clock);
1686 #endif
1687
1688 #ifdef HAVE_GMTIME_R
1689 tm = gmtime_r(&the_clock, &tmbuf);
1690 #else
1691 tm = gmtime(&the_clock);
1692 #endif
1693 if (!tm) {
1694 return 0;
1695 }
1696 *year = tm->tm_year + 1900;
1697 *month = tm->tm_mon +1;
1698 *day = tm->tm_mday;
1699 *hour = tm->tm_hour;
1700 *minute = tm->tm_min;
1701 *second = tm->tm_sec;
1702 return 1;
1703 }
1704 #if defined(HAVE_POSIX2TIME) && defined(HAVE_DECL_POSIX2TIME) && \
1705 !HAVE_DECL_POSIX2TIME
1706 extern time_t posix2time(time_t);
1707 #endif
1708
1709 int
univ_to_local(Sint * year,Sint * month,Sint * day,Sint * hour,Sint * minute,Sint * second)1710 univ_to_local(Sint *year, Sint *month, Sint *day,
1711 Sint *hour, Sint *minute, Sint *second)
1712 {
1713 time_t the_clock;
1714 struct tm *tm;
1715 #ifdef HAVE_LOCALTIME_R
1716 struct tm tmbuf;
1717 #endif
1718
1719 if (!(IN_RANGE(BASEYEAR, *year, INT_MAX - 1) &&
1720 IN_RANGE(1, *month, 12) &&
1721 IN_RANGE(1, *day, (mdays[*month] +
1722 (*month == 2
1723 && (*year % 4 == 0)
1724 && (*year % 100 != 0 || *year % 400 == 0)))) &&
1725 IN_RANGE(0, *hour, 23) &&
1726 IN_RANGE(0, *minute, 59) &&
1727 IN_RANGE(0, *second, 59))) {
1728 return 0;
1729 }
1730
1731 the_clock = *second + 60 * (*minute + 60 * (*hour + 24 *
1732 gregday(*year, *month, *day)));
1733 #ifdef HAVE_POSIX2TIME
1734 /*
1735 * Addition from OpenSource - affects FreeBSD.
1736 * No valid test case /PaN
1737 *
1738 * leap-second correction performed
1739 * if system is configured so;
1740 * do nothing if not
1741 * See FreeBSD 6.x and 7.x
1742 * /usr/src/lib/libc/stdtime/localtime.c
1743 * for the details
1744 */
1745 the_clock = posix2time(the_clock);
1746 #endif
1747
1748 #ifdef HAVE_LOCALTIME_R
1749 tm = localtime_r(&the_clock, &tmbuf);
1750 #else
1751 tm = localtime(&the_clock);
1752 #endif
1753 if (tm) {
1754 *year = tm->tm_year + 1900;
1755 *month = tm->tm_mon +1;
1756 *day = tm->tm_mday;
1757 *hour = tm->tm_hour;
1758 *minute = tm->tm_min;
1759 *second = tm->tm_sec;
1760 return 1;
1761 }
1762 return 0;
1763 }
1764
1765 /* get a timestamp */
1766 void
get_now(Uint * megasec,Uint * sec,Uint * microsec)1767 get_now(Uint* megasec, Uint* sec, Uint* microsec)
1768 {
1769 ErtsMonotonicTime now_megasec, now_sec, now, prev, mtime, time_offset;
1770
1771 mtime = time_sup.r.o.get_time();
1772 time_offset = get_time_offset();
1773 update_last_mtime(NULL, mtime);
1774 now = ERTS_MONOTONIC_TO_USEC(mtime + time_offset);
1775
1776 /* Make sure now time is later than last time */
1777 prev = erts_atomic64_read_nob(&now_prev.time);
1778 while (1) {
1779 ErtsMonotonicTime act;
1780 if (now <= prev)
1781 now = prev + 1;
1782 act = ((ErtsMonotonicTime)
1783 erts_atomic64_cmpxchg_mb(&now_prev.time,
1784 (erts_aint64_t) now,
1785 (erts_aint64_t) prev));
1786 if (act == prev)
1787 break;
1788 prev = act;
1789 }
1790
1791 now_megasec = now / ERTS_MONOTONIC_TIME_TERA;
1792 now_sec = now / ERTS_MONOTONIC_TIME_MEGA;
1793 *megasec = (Uint) now_megasec;
1794 *sec = (Uint) (now_sec - now_megasec*ERTS_MONOTONIC_TIME_MEGA);
1795 *microsec = (Uint) (now - now_sec*ERTS_MONOTONIC_TIME_MEGA);
1796
1797 ASSERT(((ErtsMonotonicTime) *megasec)*ERTS_MONOTONIC_TIME_TERA
1798 + ((ErtsMonotonicTime) *sec)*ERTS_MONOTONIC_TIME_MEGA
1799 + ((ErtsMonotonicTime) *microsec) == now);
1800 }
1801
1802 ErtsMonotonicTime
erts_get_monotonic_time(ErtsSchedulerData * esdp)1803 erts_get_monotonic_time(ErtsSchedulerData *esdp)
1804 {
1805 ErtsMonotonicTime mtime = time_sup.r.o.get_time();
1806 update_last_mtime(esdp, mtime);
1807 return mtime;
1808 }
1809
1810 ErtsMonotonicTime
erts_get_time_offset(void)1811 erts_get_time_offset(void)
1812 {
1813 return get_time_offset();
1814 }
1815
1816 static ERTS_INLINE void
make_timestamp_value(Uint * megasec,Uint * sec,Uint * microsec,ErtsMonotonicTime mtime,ErtsMonotonicTime offset)1817 make_timestamp_value(Uint* megasec, Uint* sec, Uint* microsec,
1818 ErtsMonotonicTime mtime, ErtsMonotonicTime offset)
1819 {
1820 ErtsMonotonicTime stime, as;
1821 Uint ms;
1822
1823 stime = ERTS_MONOTONIC_TO_USEC(mtime + offset);
1824
1825 as = stime / ERTS_MONOTONIC_TIME_MEGA;
1826 *megasec = ms = (Uint) (stime / ERTS_MONOTONIC_TIME_TERA);
1827 *sec = (Uint) (as - (((ErtsMonotonicTime) ms)
1828 * ERTS_MONOTONIC_TIME_MEGA));
1829 *microsec = (Uint) (stime - as*ERTS_MONOTONIC_TIME_MEGA);
1830
1831 ASSERT(((ErtsMonotonicTime) ms)*ERTS_MONOTONIC_TIME_TERA
1832 + ((ErtsMonotonicTime) *sec)*ERTS_MONOTONIC_TIME_MEGA
1833 + *microsec == stime);
1834 }
1835
1836 void
erts_make_timestamp_value(Uint * megasec,Uint * sec,Uint * microsec,ErtsMonotonicTime mtime,ErtsMonotonicTime offset)1837 erts_make_timestamp_value(Uint* megasec, Uint* sec, Uint* microsec,
1838 ErtsMonotonicTime mtime, ErtsMonotonicTime offset)
1839 {
1840 make_timestamp_value(megasec, sec, microsec, mtime, offset);
1841 }
1842
1843 void
get_sys_now(Uint * megasec,Uint * sec,Uint * microsec)1844 get_sys_now(Uint* megasec, Uint* sec, Uint* microsec)
1845 {
1846 ErtsSystemTime stime = erts_os_system_time();
1847 ErtsSystemTime ms, s, us;
1848
1849 us = ERTS_MONOTONIC_TO_USEC(stime);
1850 s = us / (1000*1000);
1851 ms = s / (1000*1000);
1852
1853 *megasec = (Uint) ms;
1854 *sec = (Uint) (s - ms*(1000*1000));
1855 *microsec = (Uint) (us - s*(1000*1000));
1856 }
1857
1858 #ifdef HAVE_ERTS_NOW_CPU
erts_get_now_cpu(Uint * megasec,Uint * sec,Uint * microsec)1859 void erts_get_now_cpu(Uint* megasec, Uint* sec, Uint* microsec) {
1860 SysCpuTime t;
1861 SysTimespec tp;
1862
1863 sys_get_cputime(t, tp);
1864 *microsec = (Uint)(tp.tv_nsec / 1000);
1865 t = (tp.tv_sec / 1000000);
1866 *megasec = (Uint)(t % 1000000);
1867 *sec = (Uint)(tp.tv_sec % 1000000);
1868 }
1869 #endif
1870
1871 #include "big.h"
1872
1873 void
erts_monitor_time_offset(ErtsMonitor * mon)1874 erts_monitor_time_offset(ErtsMonitor *mon)
1875 {
1876 erts_mtx_lock(&erts_get_time_mtx);
1877 erts_monitor_list_insert(&time_offset_monitors, mon);
1878 no_time_offset_monitors++;
1879 erts_mtx_unlock(&erts_get_time_mtx);
1880 }
1881
1882 void
erts_demonitor_time_offset(ErtsMonitor * mon)1883 erts_demonitor_time_offset(ErtsMonitor *mon)
1884 {
1885 ErtsMonitorData *mdp = erts_monitor_to_data(mon);
1886 ASSERT(erts_monitor_is_origin(mon));
1887 ASSERT(mon->type == ERTS_MON_TYPE_TIME_OFFSET);
1888
1889 erts_mtx_lock(&erts_get_time_mtx);
1890
1891 ASSERT(erts_monitor_is_in_table(&mdp->u.target));
1892
1893 erts_monitor_list_delete(&time_offset_monitors, &mdp->u.target);
1894
1895 ASSERT(no_time_offset_monitors > 0);
1896 no_time_offset_monitors--;
1897
1898 erts_mtx_unlock(&erts_get_time_mtx);
1899
1900 erts_monitor_release_both(mdp);
1901 }
1902
1903 typedef struct {
1904 Eterm pid;
1905 Eterm ref;
1906 Eterm heap[ERTS_REF_THING_SIZE];
1907 } ErtsTimeOffsetMonitorInfo;
1908
1909 typedef struct {
1910 Uint ix;
1911 ErtsTimeOffsetMonitorInfo *to_mon_info;
1912 } ErtsTimeOffsetMonitorContext;
1913
1914 static int
save_time_offset_monitor(ErtsMonitor * mon,void * vcntxt,Sint reds)1915 save_time_offset_monitor(ErtsMonitor *mon, void *vcntxt, Sint reds)
1916 {
1917 ErtsTimeOffsetMonitorContext *cntxt;
1918 ErtsMonitorData *mdp = erts_monitor_to_data(mon);
1919 Eterm *from_hp, *to_hp;
1920 Uint mix;
1921 int hix;
1922
1923 cntxt = (ErtsTimeOffsetMonitorContext *) vcntxt;
1924 mix = (cntxt->ix)++;
1925 ASSERT(is_internal_pid(mon->other.item));
1926 cntxt->to_mon_info[mix].pid = mon->other.item;
1927 to_hp = &cntxt->to_mon_info[mix].heap[0];
1928
1929 ASSERT(is_internal_ordinary_ref(mdp->ref));
1930 from_hp = internal_ref_val(mdp->ref);
1931 ASSERT(thing_arityval(*from_hp) + 1 == ERTS_REF_THING_SIZE);
1932
1933 for (hix = 0; hix < ERTS_REF_THING_SIZE; hix++)
1934 to_hp[hix] = from_hp[hix];
1935
1936 cntxt->to_mon_info[mix].ref
1937 = make_internal_ref(&cntxt->to_mon_info[mix].heap[0]);
1938 return 1;
1939 }
1940
1941 static void
send_time_offset_changed_notifications(void * new_offsetp)1942 send_time_offset_changed_notifications(void *new_offsetp)
1943 {
1944 ErtsMonotonicTime new_offset;
1945 ErtsTimeOffsetMonitorInfo *to_mon_info = NULL; /* Shut up faulty warning */
1946 Uint no_monitors;
1947 char *tmp = NULL;
1948
1949 #ifdef ARCH_64
1950 new_offset = (ErtsMonotonicTime) new_offsetp;
1951 #else
1952 new_offset = *((ErtsMonotonicTime *) new_offsetp);
1953 erts_free(ERTS_ALC_T_NEW_TIME_OFFSET, new_offsetp);
1954 #endif
1955 new_offset -= ERTS_MONOTONIC_OFFSET_NATIVE;
1956
1957 erts_mtx_lock(&erts_get_time_mtx);
1958
1959 no_monitors = no_time_offset_monitors;
1960 if (no_monitors) {
1961 ErtsTimeOffsetMonitorContext cntxt;
1962 Uint alloc_sz;
1963
1964 /* Monitor info array size */
1965 alloc_sz = no_monitors*sizeof(ErtsTimeOffsetMonitorInfo);
1966 /* + template max size */
1967 alloc_sz += 6*sizeof(Eterm); /* 5-tuple */
1968 alloc_sz += ERTS_MAX_SINT64_HEAP_SIZE*sizeof(Eterm); /* max offset size */
1969 tmp = erts_alloc(ERTS_ALC_T_TMP, alloc_sz);
1970
1971 to_mon_info = (ErtsTimeOffsetMonitorInfo *) tmp;
1972 cntxt.ix = 0;
1973 cntxt.to_mon_info = to_mon_info;
1974
1975 erts_monitor_list_foreach(time_offset_monitors,
1976 save_time_offset_monitor,
1977 &cntxt);
1978
1979 ASSERT(cntxt.ix == no_monitors);
1980 }
1981
1982 erts_mtx_unlock(&erts_get_time_mtx);
1983
1984 if (no_monitors) {
1985 Eterm *hp, *patch_refp, new_offset_term, message_template;
1986 Uint mix, hsz;
1987
1988 /* Make message template */
1989
1990 hp = (Eterm *) (tmp + no_monitors*sizeof(ErtsTimeOffsetMonitorInfo));
1991
1992 hsz = 6; /* 5-tuple */
1993 hsz += ERTS_REF_THING_SIZE;
1994 hsz += ERTS_SINT64_HEAP_SIZE(new_offset);
1995
1996 if (IS_SSMALL(new_offset))
1997 new_offset_term = make_small(new_offset);
1998 else
1999 new_offset_term = erts_sint64_to_big(new_offset, &hp);
2000 message_template = TUPLE5(hp,
2001 am_CHANGE,
2002 THE_NON_VALUE, /* Patch point for ref */
2003 am_time_offset,
2004 am_clock_service,
2005 new_offset_term);
2006 patch_refp = &hp[2];
2007
2008 ASSERT(*patch_refp == THE_NON_VALUE);
2009
2010 for (mix = 0; mix < no_monitors; mix++) {
2011 *patch_refp = to_mon_info[mix].ref;
2012 erts_proc_sig_send_persistent_monitor_msg(ERTS_MON_TYPE_TIME_OFFSET,
2013 *patch_refp,
2014 am_clock_service,
2015 to_mon_info[mix].pid,
2016 message_template,
2017 hsz);
2018 }
2019
2020 erts_free(ERTS_ALC_T_TMP, tmp);
2021 }
2022 }
2023
2024 static void
schedule_send_time_offset_changed_notifications(ErtsMonotonicTime new_offset)2025 schedule_send_time_offset_changed_notifications(ErtsMonotonicTime new_offset)
2026 {
2027 #ifdef ARCH_64
2028 void *new_offsetp = (void *) new_offset;
2029 ASSERT(sizeof(void *) == sizeof(ErtsMonotonicTime));
2030 #else
2031 void *new_offsetp = erts_alloc(ERTS_ALC_T_NEW_TIME_OFFSET,
2032 sizeof(ErtsMonotonicTime));
2033 *((ErtsMonotonicTime *) new_offsetp) = new_offset;
2034 #endif
2035 erts_schedule_misc_aux_work(1,
2036 send_time_offset_changed_notifications,
2037 new_offsetp);
2038 }
2039
2040 static ERTS_INLINE Eterm
make_time_val(Process * c_p,ErtsMonotonicTime time_val)2041 make_time_val(Process *c_p, ErtsMonotonicTime time_val)
2042 {
2043 Sint64 val = (Sint64) time_val;
2044 Eterm *hp;
2045 Uint sz;
2046
2047 if (IS_SSMALL(val))
2048 return make_small(val);
2049
2050 sz = ERTS_SINT64_HEAP_SIZE(val);
2051 hp = HAlloc(c_p, sz);
2052 return erts_sint64_to_big(val, &hp);
2053 }
2054
2055 Eterm
erts_get_monotonic_start_time(struct process * c_p)2056 erts_get_monotonic_start_time(struct process *c_p)
2057 {
2058 return make_time_val(c_p, ERTS_MONOTONIC_TIME_START_EXTERNAL);
2059 }
2060
2061 Eterm
erts_get_monotonic_end_time(struct process * c_p)2062 erts_get_monotonic_end_time(struct process *c_p)
2063 {
2064 return make_time_val(c_p, ERTS_MONOTONIC_TIME_END_EXTERNAL);
2065 }
2066
2067 static Eterm
bld_monotonic_time_source(Uint ** hpp,Uint * szp,Sint64 os_mtime)2068 bld_monotonic_time_source(Uint **hpp, Uint *szp, Sint64 os_mtime)
2069 {
2070 #ifndef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
2071 return NIL;
2072 #else
2073 int i = 0;
2074 Eterm k[6];
2075 Eterm v[6];
2076
2077 if (time_sup.r.o.os_monotonic_time_disable)
2078 return NIL;
2079
2080 k[i] = erts_bld_atom(hpp, szp, "function");
2081 v[i++] = erts_bld_atom(hpp, szp,
2082 time_sup.r.o.os_monotonic_time_func);
2083
2084 if (time_sup.r.o.os_monotonic_time_clock_id) {
2085 k[i] = erts_bld_atom(hpp, szp, "clock_id");
2086 v[i++] = erts_bld_atom(hpp, szp,
2087 time_sup.r.o.os_monotonic_time_clock_id);
2088 }
2089
2090 k[i] = erts_bld_atom(hpp, szp, "resolution");
2091 v[i++] = erts_bld_uint64(hpp, szp,
2092 time_sup.r.o.os_monotonic_time_resolution);
2093
2094 k[i] = erts_bld_atom(hpp, szp, "extended");
2095 v[i++] = time_sup.r.o.os_monotonic_time_extended ? am_yes : am_no;
2096
2097 k[i] = erts_bld_atom(hpp, szp, "parallel");
2098 v[i++] = time_sup.r.o.os_monotonic_time_locked ? am_no : am_yes;
2099
2100 k[i] = erts_bld_atom(hpp, szp, "time");
2101 v[i++] = erts_bld_sint64(hpp, szp, os_mtime);
2102
2103 return erts_bld_2tup_list(hpp, szp, (Sint) i, k, v);
2104 #endif
2105 }
2106
2107 Eterm
erts_monotonic_time_source(struct process * c_p)2108 erts_monotonic_time_source(struct process *c_p)
2109 {
2110 Uint hsz = 0;
2111 Eterm *hp = NULL;
2112 Sint64 os_mtime = 0;
2113 #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
2114 if (!time_sup.r.o.os_monotonic_time_disable)
2115 os_mtime = (Sint64) erts_os_monotonic_time();
2116 #endif
2117
2118 bld_monotonic_time_source(NULL, &hsz, os_mtime);
2119 if (hsz)
2120 hp = HAlloc(c_p, hsz);
2121 return bld_monotonic_time_source(&hp, NULL, os_mtime);
2122 }
2123
2124 static Eterm
bld_system_time_source(Uint ** hpp,Uint * szp,Sint64 os_stime)2125 bld_system_time_source(Uint **hpp, Uint *szp, Sint64 os_stime)
2126 {
2127 int i = 0;
2128 Eterm k[5];
2129 Eterm v[5];
2130
2131 k[i] = erts_bld_atom(hpp, szp, "function");
2132 v[i++] = erts_bld_atom(hpp, szp,
2133 time_sup.r.o.os_system_time_func);
2134
2135 if (time_sup.r.o.os_system_time_clock_id) {
2136 k[i] = erts_bld_atom(hpp, szp, "clock_id");
2137 v[i++] = erts_bld_atom(hpp, szp,
2138 time_sup.r.o.os_system_time_clock_id);
2139 }
2140
2141 k[i] = erts_bld_atom(hpp, szp, "resolution");
2142 v[i++] = erts_bld_uint64(hpp, szp,
2143 time_sup.r.o.os_system_time_resolution);
2144
2145 k[i] = erts_bld_atom(hpp, szp, "parallel");
2146 v[i++] = am_yes;
2147
2148 k[i] = erts_bld_atom(hpp, szp, "time");
2149 v[i++] = erts_bld_sint64(hpp, szp, os_stime);
2150
2151 return erts_bld_2tup_list(hpp, szp, (Sint) i, k, v);
2152 }
2153
2154 Eterm
erts_system_time_source(struct process * c_p)2155 erts_system_time_source(struct process *c_p)
2156 {
2157 Uint hsz = 0;
2158 Eterm *hp = NULL;
2159 Sint64 os_stime = (Sint64) erts_os_system_time();
2160
2161 bld_system_time_source(NULL, &hsz, os_stime);
2162 if (hsz)
2163 hp = HAlloc(c_p, hsz);
2164 return bld_system_time_source(&hp, NULL, os_stime);
2165 }
2166
2167
2168 #include "bif.h"
2169
2170 static ERTS_INLINE Eterm
time_unit_conversion(Process * c_p,Eterm term,ErtsMonotonicTime val,ErtsMonotonicTime muloff)2171 time_unit_conversion(Process *c_p, Eterm term, ErtsMonotonicTime val, ErtsMonotonicTime muloff)
2172 {
2173 ErtsMonotonicTime result;
2174 BIF_RETTYPE ret;
2175
2176 if (val < 0)
2177 goto trap_to_erlang_code;
2178
2179 /* Convert to common user specified time units */
2180 switch (term) {
2181 case am_second:
2182 case am_seconds:
2183 case make_small(1):
2184 result = ERTS_MONOTONIC_TO_SEC(val) + muloff*ERTS_MONOTONIC_OFFSET_SEC;
2185 ERTS_BIF_PREP_RET(ret, make_time_val(c_p, result));
2186 break;
2187 case am_millisecond:
2188 case am_milli_seconds:
2189 case make_small(1000):
2190 result = ERTS_MONOTONIC_TO_MSEC(val) + muloff*ERTS_MONOTONIC_OFFSET_MSEC;
2191 ERTS_BIF_PREP_RET(ret, make_time_val(c_p, result));
2192 break;
2193 case am_microsecond:
2194 case am_micro_seconds:
2195 case make_small(1000*1000):
2196 result = ERTS_MONOTONIC_TO_USEC(val) + muloff*ERTS_MONOTONIC_OFFSET_USEC;
2197 ERTS_BIF_PREP_RET(ret, make_time_val(c_p, result));
2198 break;
2199 #ifdef ARCH_64
2200 case am_nanosecond:
2201 case am_nano_seconds:
2202 case make_small(1000*1000*1000):
2203 result = ERTS_MONOTONIC_TO_NSEC(val) + muloff*ERTS_MONOTONIC_OFFSET_NSEC;
2204 ERTS_BIF_PREP_RET(ret, make_time_val(c_p, result));
2205 break;
2206 #endif
2207 case am_perf_counter:
2208 goto trap_to_erlang_code;
2209 default: {
2210 Eterm value, native_res;
2211 #ifndef ARCH_64
2212 Sint user_res;
2213 if (term == am_nanosecond || term == am_nano_seconds)
2214 goto to_nano_seconds;
2215 if (term_to_Sint(term, &user_res)) {
2216 if (user_res == 1000*1000*1000) {
2217 to_nano_seconds:
2218 result = (ERTS_MONOTONIC_TO_NSEC(val)
2219 + muloff*ERTS_MONOTONIC_OFFSET_NSEC);
2220 ERTS_BIF_PREP_RET(ret, make_time_val(c_p, result));
2221 break;
2222 }
2223 if (user_res <= 0)
2224 goto badarg;
2225 }
2226 #else
2227 if (is_small(term)) {
2228 if (signed_val(term) <= 0)
2229 goto badarg;
2230 }
2231 #endif
2232 else if (is_big(term)) {
2233 if (big_sign(term))
2234 goto badarg;
2235 }
2236 else {
2237 badarg:
2238 ERTS_BIF_PREP_ERROR(ret, c_p, BADARG);
2239 break;
2240 }
2241
2242 trap_to_erlang_code:
2243 /* Do it in erlang code instead; pass along values to use... */
2244 value = make_time_val(c_p, val + muloff*ERTS_MONOTONIC_OFFSET_NATIVE);
2245 native_res = make_time_val(c_p, ERTS_MONOTONIC_TIME_UNIT);
2246
2247 ERTS_BIF_PREP_TRAP3(ret, erts_convert_time_unit_trap, c_p,
2248 value, native_res, term);
2249
2250 break;
2251 }
2252 }
2253
2254 return ret;
2255 }
2256
2257
2258 /*
2259 * Time Native API (drivers and NIFs)
2260 */
2261
2262 #define ERTS_NAPI_TIME_ERROR ((ErtsMonotonicTime) ERTS_NAPI_TIME_ERROR__)
2263
2264 static void
init_time_napi(void)2265 init_time_napi(void)
2266 {
2267 /* Verify that time native api constants are as expected... */
2268
2269 ASSERT(sizeof(ErtsMonotonicTime) == sizeof(ErlDrvTime));
2270 ASSERT(ERL_DRV_TIME_ERROR == (ErlDrvTime) ERTS_NAPI_TIME_ERROR);
2271 ASSERT(ERL_DRV_TIME_ERROR < (ErlDrvTime) 0);
2272 ASSERT(ERTS_NAPI_SEC__ == (int) ERL_DRV_SEC);
2273 ASSERT(ERTS_NAPI_MSEC__ == (int) ERL_DRV_MSEC);
2274 ASSERT(ERTS_NAPI_USEC__ == (int) ERL_DRV_USEC);
2275 ASSERT(ERTS_NAPI_NSEC__ == (int) ERL_DRV_NSEC);
2276
2277 ASSERT(sizeof(ErtsMonotonicTime) == sizeof(ErlNifTime));
2278 ASSERT(ERL_NIF_TIME_ERROR == (ErlNifTime) ERTS_NAPI_TIME_ERROR);
2279 ASSERT(ERL_NIF_TIME_ERROR < (ErlNifTime) 0);
2280 ASSERT(ERTS_NAPI_SEC__ == (int) ERL_NIF_SEC);
2281 ASSERT(ERTS_NAPI_MSEC__ == (int) ERL_NIF_MSEC);
2282 ASSERT(ERTS_NAPI_USEC__ == (int) ERL_NIF_USEC);
2283 ASSERT(ERTS_NAPI_NSEC__ == (int) ERL_NIF_NSEC);
2284 }
2285
2286 ErtsMonotonicTime
erts_napi_monotonic_time(int time_unit)2287 erts_napi_monotonic_time(int time_unit)
2288 {
2289 ErtsSchedulerData *esdp;
2290 ErtsMonotonicTime mtime;
2291
2292 /* At least for now only allow schedulers to do this... */
2293 esdp = erts_get_scheduler_data();
2294 if (!esdp)
2295 return ERTS_NAPI_TIME_ERROR;
2296
2297 mtime = time_sup.r.o.get_time();
2298 update_last_mtime(esdp, mtime);
2299
2300 switch (time_unit) {
2301 case ERTS_NAPI_SEC__:
2302 mtime = ERTS_MONOTONIC_TO_SEC(mtime);
2303 mtime += ERTS_MONOTONIC_OFFSET_SEC;
2304 break;
2305 case ERTS_NAPI_MSEC__:
2306 mtime = ERTS_MONOTONIC_TO_MSEC(mtime);
2307 mtime += ERTS_MONOTONIC_OFFSET_MSEC;
2308 break;
2309 case ERTS_NAPI_USEC__:
2310 mtime = ERTS_MONOTONIC_TO_USEC(mtime);
2311 mtime += ERTS_MONOTONIC_OFFSET_USEC;
2312 break;
2313 case ERTS_NAPI_NSEC__:
2314 mtime = ERTS_MONOTONIC_TO_NSEC(mtime);
2315 mtime += ERTS_MONOTONIC_OFFSET_NSEC;
2316 break;
2317 default:
2318 return ERTS_NAPI_TIME_ERROR;
2319 }
2320
2321 return mtime;
2322 }
2323
2324 ErtsMonotonicTime
erts_napi_time_offset(int time_unit)2325 erts_napi_time_offset(int time_unit)
2326 {
2327 ErtsSchedulerData *esdp;
2328 ErtsSystemTime offs;
2329
2330 /* At least for now only allow schedulers to do this... */
2331 esdp = erts_get_scheduler_data();
2332 if (!esdp)
2333 return ERTS_NAPI_TIME_ERROR;
2334
2335 offs = get_time_offset();
2336 switch (time_unit) {
2337 case ERTS_NAPI_SEC__:
2338 offs = ERTS_MONOTONIC_TO_SEC(offs);
2339 offs -= ERTS_MONOTONIC_OFFSET_SEC;
2340 break;
2341 case ERTS_NAPI_MSEC__:
2342 offs = ERTS_MONOTONIC_TO_MSEC(offs);
2343 offs -= ERTS_MONOTONIC_OFFSET_MSEC;
2344 break;
2345 case ERTS_NAPI_USEC__:
2346 offs = ERTS_MONOTONIC_TO_USEC(offs);
2347 offs -= ERTS_MONOTONIC_OFFSET_USEC;
2348 break;
2349 case ERTS_NAPI_NSEC__:
2350 offs = ERTS_MONOTONIC_TO_NSEC(offs);
2351 offs -= ERTS_MONOTONIC_OFFSET_NSEC;
2352 break;
2353 default:
2354 return ERTS_NAPI_TIME_ERROR;
2355 }
2356 return offs;
2357 }
2358
2359 ErtsMonotonicTime
erts_napi_convert_time_unit(ErtsMonotonicTime val,int from,int to)2360 erts_napi_convert_time_unit(ErtsMonotonicTime val, int from, int to)
2361 {
2362 ErtsMonotonicTime ffreq, tfreq, denom;
2363 /*
2364 * Convertion between time units using floor function.
2365 *
2366 * Note that this needs to work also for negative
2367 * values. Ordinary integer division on a negative
2368 * value will give ceiling...
2369 */
2370
2371 switch ((int) from) {
2372 case ERTS_NAPI_SEC__: ffreq = 1; break;
2373 case ERTS_NAPI_MSEC__: ffreq = 1000; break;
2374 case ERTS_NAPI_USEC__: ffreq = 1000*1000; break;
2375 case ERTS_NAPI_NSEC__: ffreq = 1000*1000*1000; break;
2376 default: return ERTS_NAPI_TIME_ERROR;
2377 }
2378
2379 switch ((int) to) {
2380 case ERTS_NAPI_SEC__: tfreq = 1; break;
2381 case ERTS_NAPI_MSEC__: tfreq = 1000; break;
2382 case ERTS_NAPI_USEC__: tfreq = 1000*1000; break;
2383 case ERTS_NAPI_NSEC__: tfreq = 1000*1000*1000; break;
2384 default: return ERTS_NAPI_TIME_ERROR;
2385 }
2386
2387 if (tfreq >= ffreq)
2388 return val * (tfreq / ffreq);
2389
2390 denom = ffreq / tfreq;
2391 if (val >= 0)
2392 return val / denom;
2393
2394 return (val - (denom - 1)) / denom;
2395 }
2396
2397 /* Built in functions */
2398
monotonic_time_0(BIF_ALIST_0)2399 BIF_RETTYPE monotonic_time_0(BIF_ALIST_0)
2400 {
2401 ErtsMonotonicTime mtime = time_sup.r.o.get_time();
2402 update_last_mtime(erts_proc_sched_data(BIF_P), mtime);
2403 mtime += ERTS_MONOTONIC_OFFSET_NATIVE;
2404 BIF_RET(make_time_val(BIF_P, mtime));
2405 }
2406
monotonic_time_1(BIF_ALIST_1)2407 BIF_RETTYPE monotonic_time_1(BIF_ALIST_1)
2408 {
2409 ErtsMonotonicTime mtime = time_sup.r.o.get_time();
2410 update_last_mtime(erts_proc_sched_data(BIF_P), mtime);
2411 BIF_RET(time_unit_conversion(BIF_P, BIF_ARG_1, mtime, 1));
2412 }
2413
system_time_0(BIF_ALIST_0)2414 BIF_RETTYPE system_time_0(BIF_ALIST_0)
2415 {
2416 ErtsMonotonicTime mtime, offset;
2417 mtime = time_sup.r.o.get_time();
2418 offset = get_time_offset();
2419 update_last_mtime(erts_proc_sched_data(BIF_P), mtime);
2420 BIF_RET(make_time_val(BIF_P, mtime + offset));
2421 }
2422
system_time_1(BIF_ALIST_0)2423 BIF_RETTYPE system_time_1(BIF_ALIST_0)
2424 {
2425 ErtsMonotonicTime mtime, offset;
2426 mtime = time_sup.r.o.get_time();
2427 offset = get_time_offset();
2428 update_last_mtime(erts_proc_sched_data(BIF_P), mtime);
2429 BIF_RET(time_unit_conversion(BIF_P, BIF_ARG_1, mtime + offset, 0));
2430 }
2431
erts_internal_time_unit_0(BIF_ALIST_0)2432 BIF_RETTYPE erts_internal_time_unit_0(BIF_ALIST_0)
2433 {
2434 BIF_RET(make_time_val(BIF_P, ERTS_MONOTONIC_TIME_UNIT));
2435 }
2436
time_offset_0(BIF_ALIST_0)2437 BIF_RETTYPE time_offset_0(BIF_ALIST_0)
2438 {
2439 ErtsMonotonicTime time_offset = get_time_offset();
2440 time_offset -= ERTS_MONOTONIC_OFFSET_NATIVE;
2441 BIF_RET(make_time_val(BIF_P, time_offset));
2442 }
2443
time_offset_1(BIF_ALIST_1)2444 BIF_RETTYPE time_offset_1(BIF_ALIST_1)
2445 {
2446 BIF_RET(time_unit_conversion(BIF_P, BIF_ARG_1, get_time_offset(), -1));
2447 }
2448
2449
timestamp_0(BIF_ALIST_0)2450 BIF_RETTYPE timestamp_0(BIF_ALIST_0)
2451 {
2452 Eterm *hp, res;
2453 ErtsMonotonicTime mtime, offset;
2454 Uint mega_sec, sec, micro_sec;
2455
2456 mtime = time_sup.r.o.get_time();
2457 offset = get_time_offset();
2458 update_last_mtime(erts_proc_sched_data(BIF_P), mtime);
2459
2460 make_timestamp_value(&mega_sec, &sec, µ_sec, mtime, offset);
2461
2462 /*
2463 * Mega seconds is the only value that potentially
2464 * ever could be a bignum. However, that wont happen
2465 * during at least the next 4 million years...
2466 *
2467 * (System time will also have wrapped in the
2468 * 64-bit integer before we get there...)
2469 */
2470
2471 ASSERT(IS_USMALL(0, mega_sec));
2472 ASSERT(IS_USMALL(0, sec));
2473 ASSERT(IS_USMALL(0, micro_sec));
2474
2475 hp = HAlloc(BIF_P, 4);
2476 res = TUPLE3(hp,
2477 make_small(mega_sec),
2478 make_small(sec),
2479 make_small(micro_sec));
2480 BIF_RET(res);
2481 }
2482
os_system_time_0(BIF_ALIST_0)2483 BIF_RETTYPE os_system_time_0(BIF_ALIST_0)
2484 {
2485 ErtsSystemTime stime = erts_os_system_time();
2486 BIF_RET(make_time_val(BIF_P, stime));
2487 }
2488
os_system_time_1(BIF_ALIST_1)2489 BIF_RETTYPE os_system_time_1(BIF_ALIST_1)
2490 {
2491 ErtsSystemTime stime = erts_os_system_time();
2492 BIF_RET(time_unit_conversion(BIF_P, BIF_ARG_1, stime, 0));
2493 }
2494
2495 BIF_RETTYPE
os_perf_counter_0(BIF_ALIST_0)2496 os_perf_counter_0(BIF_ALIST_0)
2497 {
2498 BIF_RET(make_time_val(BIF_P, erts_sys_perf_counter()));
2499 }
2500
erts_internal_perf_counter_unit_0(BIF_ALIST_0)2501 BIF_RETTYPE erts_internal_perf_counter_unit_0(BIF_ALIST_0)
2502 {
2503 BIF_RET(make_time_val(BIF_P, erts_sys_perf_counter_unit()));
2504 }
2505