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, &micro_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