diff options
author | Rickard Green <[email protected]> | 2015-03-24 15:28:11 +0100 |
---|---|---|
committer | Rickard Green <[email protected]> | 2015-03-24 16:14:07 +0100 |
commit | c20482023b70768bd84d25f1e34dbbc2fe09cf31 (patch) | |
tree | d6f8725463f3b8f02661ac1d7e56ece7a055ac86 /erts/emulator | |
parent | 052695858c07477db480d25d2d858540088d04c3 (diff) | |
download | otp-c20482023b70768bd84d25f1e34dbbc2fe09cf31.tar.gz otp-c20482023b70768bd84d25f1e34dbbc2fe09cf31.tar.bz2 otp-c20482023b70768bd84d25f1e34dbbc2fe09cf31.zip |
Better OS system time implementation
Diffstat (limited to 'erts/emulator')
-rw-r--r-- | erts/emulator/beam/erl_bif_info.c | 2 | ||||
-rw-r--r-- | erts/emulator/beam/erl_time.h | 1 | ||||
-rw-r--r-- | erts/emulator/beam/erl_time_sup.c | 214 | ||||
-rw-r--r-- | erts/emulator/beam/sys.h | 10 | ||||
-rw-r--r-- | erts/emulator/sys/unix/erl_unix_sys.h | 4 | ||||
-rw-r--r-- | erts/emulator/sys/unix/sys_time.c | 167 | ||||
-rw-r--r-- | erts/emulator/sys/win32/erl_win_sys.h | 4 | ||||
-rw-r--r-- | erts/emulator/sys/win32/sys_time.c | 73 |
8 files changed, 350 insertions, 125 deletions
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 70062b2305..8491c01b75 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -2120,6 +2120,8 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) } } else if (ERTS_IS_ATOM_STR("os_monotonic_time_source", BIF_ARG_1)) { BIF_RET(erts_monotonic_time_source(BIF_P)); + } else if (ERTS_IS_ATOM_STR("os_system_time_source", BIF_ARG_1)) { + BIF_RET(erts_system_time_source(BIF_P)); } else if (ERTS_IS_ATOM_STR("time_correction", BIF_ARG_1)) { BIF_RET(erts_has_time_correction() ? am_true : am_false); } else if (ERTS_IS_ATOM_STR("start_time", BIF_ARG_1)) { diff --git a/erts/emulator/beam/erl_time.h b/erts/emulator/beam/erl_time.h index 35a1442dbd..7f8c4e0ed5 100644 --- a/erts/emulator/beam/erl_time.h +++ b/erts/emulator/beam/erl_time.h @@ -148,6 +148,7 @@ ErtsTimeOffsetState erts_finalize_time_offset(void); struct process; Eterm erts_get_monotonic_start_time(struct process *c_p); Eterm erts_monotonic_time_source(struct process*c_p); +Eterm erts_system_time_source(struct process*c_p); #ifdef SYS_CLOCK_RESOLUTION #define ERTS_CLKTCK_RESOLUTION ((ErtsMonotonicTime) (SYS_CLOCK_RESOLUTION*1000)) diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index d961fae81a..ef39f4b5f4 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -133,12 +133,17 @@ struct time_sup_read_only__ { ErtsTimeWarpMode warp_mode; #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT ErtsMonotonicTime moffset; - int os_monotonic_disable; - char *os_monotonic_func; - char *os_monotonic_clock_id; - int os_monotonic_locked; - Uint64 os_monotonic_resolution; - Uint64 os_monotonic_extended; + int os_monotonic_time_disable; + char *os_monotonic_time_func; + char *os_monotonic_time_clock_id; + int os_monotonic_time_locked; + Uint64 os_monotonic_time_resolution; + Uint64 os_monotonic_time_extended; + char *os_system_time_func; + char *os_system_time_clock_id; + int os_system_time_locked; + Uint64 os_system_time_resolution; + Uint64 os_system_time_extended; #endif #if !ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT ErtsMonotonicTime start; @@ -209,7 +214,7 @@ struct time_sup_infrequently_changed__ { ErtsMonotonicTime minit; #endif int finalized_offset; - SysTimeval inittv; /* Used everywhere, the initial time-of-day */ + ErtsSystemTime sinit; ErtsMonotonicTime not_corrected_moffset; erts_atomic64_t offset; }; @@ -242,10 +247,8 @@ ErtsTimeSupData erts_time_sup__ erts_align_attribute(ERTS_CACHE_LINE_SIZE); erts_approx_time_t erts_get_approx_time(void) { - SysTimeval tv; - sys_gettimeofday(&tv); - - return (erts_approx_time_t) tv.tv_sec; + ErtsSystemTime stime = erts_os_system_time(); + return (erts_approx_time_t) ERTS_MONOTONIC_TO_SEC(stime); } static ERTS_INLINE void @@ -403,7 +406,6 @@ check_time_correction(void *unused) ErtsMonotonicTime mdiff, sdiff, os_mtime, erl_mtime, os_stime, erl_stime, time_offset; Uint timeout; - SysTimeval tod; int set_new_correction, begin_short_intervals = 0; erts_smp_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx); @@ -411,7 +413,7 @@ check_time_correction(void *unused) ASSERT(time_sup.inf.c.finalized_offset); os_mtime = erts_os_monotonic_time(); - sys_gettimeofday(&tod); + os_stime = erts_os_system_time(); cdata = time_sup.inf.c.parmon.cdata; @@ -426,9 +428,6 @@ check_time_correction(void *unused) time_offset = get_time_offset(); erl_stime = erl_mtime + time_offset; - os_stime = ERTS_SEC_TO_MONOTONIC(tod.tv_sec); - os_stime += ERTS_USEC_TO_MONOTONIC(tod.tv_usec); - sdiff = erl_stime - os_stime; new_correction = cip->correction; @@ -686,7 +685,6 @@ init_check_time_correction(void *unused) ErtsMonotonicTime old_mtime, old_stime, mtime, stime, mtime_diff, stime_diff; int ix; - SysTimeval tod; ddp = &time_sup.inf.c.parmon.cdata.drift; ix = ddp->ix; @@ -694,10 +692,7 @@ init_check_time_correction(void *unused) old_stime = ddp->intervals[0].time.sys; mtime = erts_os_monotonic_time(); - sys_gettimeofday(&tod); - - stime = ERTS_SEC_TO_MONOTONIC(tod.tv_sec); - stime += ERTS_USEC_TO_MONOTONIC(tod.tv_usec); + stime = erts_os_system_time(); mtime_diff = mtime - old_mtime; stime_diff = stime - old_stime; @@ -729,7 +724,7 @@ init_check_time_correction(void *unused) #endif static ErtsMonotonicTime -finalize_corrected_time_offset(SysTimeval *todp) +finalize_corrected_time_offset(ErtsSystemTime *stimep) { ErtsMonotonicTime os_mtime; ErtsMonotonicCorrectionData cdata; @@ -738,7 +733,7 @@ finalize_corrected_time_offset(SysTimeval *todp) erts_smp_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx); os_mtime = erts_os_monotonic_time(); - sys_gettimeofday(todp); + *stimep = erts_os_system_time(); cdata = time_sup.inf.c.parmon.cdata; @@ -774,15 +769,11 @@ late_init_time_correction(void) static ErtsMonotonicTime get_not_corrected_time(void) { - SysTimeval tmp_tv; ErtsMonotonicTime stime, mtime; erts_smp_mtx_lock(&erts_get_time_mtx); - sys_gettimeofday(&tmp_tv); - - stime = ERTS_SEC_TO_MONOTONIC(tmp_tv.tv_sec); - stime += ERTS_USEC_TO_MONOTONIC(tmp_tv.tv_usec); + stime = erts_os_system_time(); mtime = stime - time_sup.inf.c.not_corrected_moffset; @@ -820,7 +811,7 @@ int erts_check_time_adj_support(int time_correction, /* User wants time correction */ #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT - return !time_sup.r.o.os_monotonic_disable; + return !time_sup.r.o.os_monotonic_time_disable; #else return 0; #endif @@ -849,24 +840,33 @@ void erts_init_sys_time_sup(void) #endif #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT - time_sup.r.o.os_monotonic_disable - = !sys_init_time_res.have_os_monotonic; - time_sup.r.o.os_monotonic_func - = sys_init_time_res.os_monotonic_info.func; - time_sup.r.o.os_monotonic_clock_id - = sys_init_time_res.os_monotonic_info.clock_id; - time_sup.r.o.os_monotonic_locked - = sys_init_time_res.os_monotonic_info.locked_use; - time_sup.r.o.os_monotonic_resolution - = sys_init_time_res.os_monotonic_info.resolution; - time_sup.r.o.os_monotonic_extended - = sys_init_time_res.os_monotonic_info.extended; + time_sup.r.o.os_monotonic_time_disable + = !sys_init_time_res.have_os_monotonic_time; + time_sup.r.o.os_monotonic_time_func + = sys_init_time_res.os_monotonic_time_info.func; + time_sup.r.o.os_monotonic_time_clock_id + = sys_init_time_res.os_monotonic_time_info.clock_id; + time_sup.r.o.os_monotonic_time_locked + = sys_init_time_res.os_monotonic_time_info.locked_use; + time_sup.r.o.os_monotonic_time_resolution + = sys_init_time_res.os_monotonic_time_info.resolution; + time_sup.r.o.os_monotonic_time_extended + = sys_init_time_res.os_monotonic_time_info.extended; + time_sup.r.o.os_system_time_func + = sys_init_time_res.os_system_time_info.func; + time_sup.r.o.os_system_time_clock_id + = sys_init_time_res.os_system_time_info.clock_id; + time_sup.r.o.os_system_time_locked + = sys_init_time_res.os_system_time_info.locked_use; + time_sup.r.o.os_system_time_resolution + = sys_init_time_res.os_system_time_info.resolution; #endif } int erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode) { + ErtsMonotonicTime resolution; #if !ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT ErtsMonotonicTime abs_native_offset, native_offset; #endif @@ -935,11 +935,15 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode) #endif + resolution = time_sup.r.o.os_monotonic_time_resolution; + if (resolution > time_sup.r.o.os_system_time_resolution) + resolution = time_sup.r.o.os_system_time_resolution; + time_sup.r.o.adj.large_diff = erts_time_sup__.r.o.monotonic_time_unit; time_sup.r.o.adj.large_diff *= 50; - time_sup.r.o.adj.large_diff /= time_sup.r.o.os_monotonic_resolution; - if (time_sup.r.o.adj.large_diff < ERTS_MSEC_TO_MONOTONIC(5)) - time_sup.r.o.adj.large_diff = ERTS_MSEC_TO_MONOTONIC(5); + time_sup.r.o.adj.large_diff /= resolution; + if (time_sup.r.o.adj.large_diff < ERTS_USEC_TO_MONOTONIC(500)) + time_sup.r.o.adj.large_diff = ERTS_USEC_TO_MONOTONIC(500); time_sup.r.o.adj.small_diff = time_sup.r.o.adj.large_diff/10; #ifdef ERTS_TIME_CORRECTION_PRINT @@ -961,7 +965,7 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode) #ifndef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT time_sup.r.o.correction = 0; #else - if (time_sup.r.o.os_monotonic_disable) + if (time_sup.r.o.os_monotonic_time_disable) time_sup.r.o.correction = 0; if (time_sup.r.o.correction) { @@ -969,10 +973,9 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode) erts_smp_rwmtx_opt_t rwmtx_opts = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; ErtsMonotonicTime offset; time_sup.inf.c.minit = erts_os_monotonic_time(); - sys_gettimeofday(&time_sup.inf.c.inittv); + time_sup.inf.c.sinit = erts_os_system_time(); time_sup.r.o.moffset = -1*time_sup.inf.c.minit; - offset = ERTS_SEC_TO_MONOTONIC(time_sup.inf.c.inittv.tv_sec); - offset += ERTS_USEC_TO_MONOTONIC(time_sup.inf.c.inittv.tv_usec); + offset = time_sup.inf.c.sinit; offset -= ERTS_MONOTONIC_TIME_UNIT; init_time_offset(offset); @@ -985,10 +988,7 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode) cdatap = &time_sup.inf.c.parmon.cdata; #ifndef ERTS_HAVE_CORRECTED_OS_MONOTONIC - cdatap->drift.intervals[0].time.sys - = ERTS_SEC_TO_MONOTONIC(time_sup.inf.c.inittv.tv_sec); - cdatap->drift.intervals[0].time.sys - += ERTS_USEC_TO_MONOTONIC(time_sup.inf.c.inittv.tv_usec); + cdatap->drift.intervals[0].time.sys = time_sup.inf.c.sinit; cdatap->drift.intervals[0].time.mon = time_sup.inf.c.minit; cdatap->curr.correction.drift = 0; #endif @@ -1006,9 +1006,7 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode) { ErtsMonotonicTime stime, offset; time_sup.r.o.get_time = get_not_corrected_time; - sys_gettimeofday(&time_sup.inf.c.inittv); - stime = ERTS_SEC_TO_MONOTONIC(time_sup.inf.c.inittv.tv_sec); - stime += ERTS_USEC_TO_MONOTONIC(time_sup.inf.c.inittv.tv_usec); + stime = time_sup.inf.c.sinit = erts_os_system_time(); offset = stime - ERTS_MONOTONIC_TIME_UNIT; time_sup.inf.c.not_corrected_moffset = offset; init_time_offset(offset); @@ -1085,17 +1083,12 @@ erts_finalize_time_offset(void) if (!time_sup.inf.c.finalized_offset) { ErtsMonotonicTime mtime, new_offset; - SysTimeval tv; #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT if (!time_sup.r.o.correction) #endif { - ErtsMonotonicTime stime; - sys_gettimeofday(&tv); - - stime = ERTS_SEC_TO_MONOTONIC(tv.tv_sec); - stime += ERTS_USEC_TO_MONOTONIC(tv.tv_usec); + ErtsMonotonicTime stime = erts_os_system_time(); mtime = stime - time_sup.inf.c.not_corrected_moffset; @@ -1114,11 +1107,9 @@ erts_finalize_time_offset(void) } #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT else { - mtime = finalize_corrected_time_offset(&tv); - new_offset = ERTS_SEC_TO_MONOTONIC(tv.tv_sec); - new_offset += ERTS_USEC_TO_MONOTONIC(tv.tv_usec); - new_offset -= mtime; - + ErtsSystemTime stime; + mtime = finalize_corrected_time_offset(&stime); + new_offset = stime - mtime; } #endif new_offset = ERTS_MONOTONIC_TO_USEC(new_offset); @@ -1613,13 +1604,16 @@ erts_get_monotonic_time(void) void get_sys_now(Uint* megasec, Uint* sec, Uint* microsec) { - SysTimeval now; - - sys_gettimeofday(&now); - - *megasec = (Uint) (now.tv_sec / 1000000); - *sec = (Uint) (now.tv_sec % 1000000); - *microsec = (Uint) (now.tv_usec); + ErtsSystemTime stime = erts_os_system_time(); + ErtsSystemTime ms, s, us; + + us = ERTS_MONOTONIC_TO_USEC(stime); + s = us / (1000*1000); + ms = s / (1000*1000); + + *megasec = (Uint) ms; + *sec = (Uint) (s - ms*(1000*1000)); + *microsec = (Uint) (us - s*(1000*1000)); } #ifdef HAVE_ERTS_NOW_CPU @@ -1848,25 +1842,28 @@ bld_monotonic_time_source(Uint **hpp, Uint *szp, Sint64 os_mtime) Eterm k[6]; Eterm v[6]; - if (time_sup.r.o.os_monotonic_disable) + if (time_sup.r.o.os_monotonic_time_disable) return NIL; k[i] = erts_bld_atom(hpp, szp, "function"); - v[i++] = erts_bld_atom(hpp, szp, time_sup.r.o.os_monotonic_func); + v[i++] = erts_bld_atom(hpp, szp, + time_sup.r.o.os_monotonic_time_func); - if (time_sup.r.o.os_monotonic_clock_id) { + if (time_sup.r.o.os_monotonic_time_clock_id) { k[i] = erts_bld_atom(hpp, szp, "clock_id"); - v[i++] = erts_bld_atom(hpp, szp, time_sup.r.o.os_monotonic_clock_id); + v[i++] = erts_bld_atom(hpp, szp, + time_sup.r.o.os_monotonic_time_clock_id); } k[i] = erts_bld_atom(hpp, szp, "resolution"); - v[i++] = erts_bld_uint64(hpp, szp, time_sup.r.o.os_monotonic_resolution); + v[i++] = erts_bld_uint64(hpp, szp, + time_sup.r.o.os_monotonic_time_resolution); k[i] = erts_bld_atom(hpp, szp, "extended"); - v[i++] = time_sup.r.o.os_monotonic_extended ? am_yes : am_no; + v[i++] = time_sup.r.o.os_monotonic_time_extended ? am_yes : am_no; k[i] = erts_bld_atom(hpp, szp, "parallel"); - v[i++] = time_sup.r.o.os_monotonic_locked ? am_no : am_yes; + v[i++] = time_sup.r.o.os_monotonic_time_locked ? am_no : am_yes; k[i] = erts_bld_atom(hpp, szp, "time"); v[i++] = erts_bld_sint64(hpp, szp, os_mtime); @@ -1882,7 +1879,7 @@ erts_monotonic_time_source(struct process *c_p) Eterm *hp = NULL; Sint64 os_mtime = 0; #ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT - if (!time_sup.r.o.os_monotonic_disable) + if (!time_sup.r.o.os_monotonic_time_disable) os_mtime = (Sint64) erts_os_monotonic_time(); #endif @@ -1892,6 +1889,49 @@ erts_monotonic_time_source(struct process *c_p) return bld_monotonic_time_source(&hp, NULL, os_mtime); } +static Eterm +bld_system_time_source(Uint **hpp, Uint *szp, Sint64 os_stime) +{ + int i = 0; + Eterm k[5]; + Eterm v[5]; + + k[i] = erts_bld_atom(hpp, szp, "function"); + v[i++] = erts_bld_atom(hpp, szp, + time_sup.r.o.os_system_time_func); + + if (time_sup.r.o.os_system_time_clock_id) { + k[i] = erts_bld_atom(hpp, szp, "clock_id"); + v[i++] = erts_bld_atom(hpp, szp, + time_sup.r.o.os_system_time_clock_id); + } + + k[i] = erts_bld_atom(hpp, szp, "resolution"); + v[i++] = erts_bld_uint64(hpp, szp, + time_sup.r.o.os_system_time_resolution); + + k[i] = erts_bld_atom(hpp, szp, "parallel"); + v[i++] = am_yes; + + k[i] = erts_bld_atom(hpp, szp, "time"); + v[i++] = erts_bld_sint64(hpp, szp, os_stime); + + return erts_bld_2tup_list(hpp, szp, (Sint) i, k, v); +} + +Eterm +erts_system_time_source(struct process *c_p) +{ + Uint hsz = 0; + Eterm *hp = NULL; + Sint64 os_stime = (Sint64) erts_os_system_time(); + + bld_system_time_source(NULL, &hsz, os_stime); + if (hsz) + hp = HAlloc(c_p, hsz); + return bld_system_time_source(&hp, NULL, os_stime); +} + #include "bif.h" @@ -2066,21 +2106,13 @@ BIF_RETTYPE timestamp_0(BIF_ALIST_0) BIF_RETTYPE os_system_time_0(BIF_ALIST_0) { - ErtsMonotonicTime stime; - SysTimeval tod; - sys_gettimeofday(&tod); - stime = ERTS_SEC_TO_MONOTONIC(tod.tv_sec); - stime += ERTS_USEC_TO_MONOTONIC(tod.tv_usec); + ErtsSystemTime stime = erts_os_system_time(); BIF_RET(make_time_val(BIF_P, stime)); } BIF_RETTYPE os_system_time_1(BIF_ALIST_0) { - ErtsMonotonicTime stime; - SysTimeval tod; - sys_gettimeofday(&tod); - stime = ERTS_SEC_TO_MONOTONIC(tod.tv_sec); - stime += ERTS_USEC_TO_MONOTONIC(tod.tv_usec); + ErtsSystemTime stime = erts_os_system_time(); BIF_RET(time_unit_conversion(BIF_P, BIF_ARG_1, stime, 0)); } diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index c51b665db9..27a55e0ec7 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -684,7 +684,7 @@ typedef enum { } ErtsTimeWarpMode; typedef struct { - int have_os_monotonic; + int have_os_monotonic_time; ErtsMonotonicTime os_monotonic_time_unit; ErtsMonotonicTime sys_clock_resolution; struct { @@ -693,7 +693,13 @@ typedef struct { char *clock_id; int locked_use; int extended; - } os_monotonic_info; + } os_monotonic_time_info; + struct { + Uint64 resolution; + char *func; + char *clock_id; + int locked_use; + } os_system_time_info; } ErtsSysInitTimeResult; #define ERTS_SYS_INIT_TIME_RESULT_INITER \ diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h index a14a4b3eae..5394e94c8c 100644 --- a/erts/emulator/sys/unix/erl_unix_sys.h +++ b/erts/emulator/sys/unix/erl_unix_sys.h @@ -169,6 +169,10 @@ typedef long long ErtsSysHrTime; #error No signed 64-bit type found... #endif +typedef ErtsMonotonicTime ErtsSystemTime; + +ErtsSystemTime erts_os_system_time(void); + #define ERTS_MONOTONIC_TIME_MIN (((ErtsMonotonicTime) 1) << 63) #define ERTS_MONOTONIC_TIME_MAX (~ERTS_MONOTONIC_TIME_MIN) diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c index 134e3a67b0..d6591a8296 100644 --- a/erts/emulator/sys/unix/sys_time.c +++ b/erts/emulator/sys/unix/sys_time.c @@ -150,44 +150,46 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) { #if !defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) - init_resp->have_os_monotonic = 0; + init_resp->have_os_monotonic_time = 0; #else /* defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) */ int major, minor, build, vsn; - init_resp->os_monotonic_info.resolution = (Uint64) 1000*1000*1000; + init_resp->os_monotonic_time_info.resolution = (Uint64) 1000*1000*1000; #if defined(HAVE_CLOCK_GETRES) && defined(MONOTONIC_CLOCK_ID) { struct timespec ts; - if (clock_getres(MONOTONIC_CLOCK_ID, &ts) == 0 - && ts.tv_sec == 0 && ts.tv_nsec != 0) { - init_resp->os_monotonic_info.resolution /= ts.tv_nsec; + if (clock_getres(MONOTONIC_CLOCK_ID, &ts) == 0) { + if (ts.tv_sec == 0 && ts.tv_nsec != 0) + init_resp->os_monotonic_time_info.resolution /= ts.tv_nsec; + else if (ts.tv_sec >= 1) + init_resp->os_monotonic_time_info.resolution = 1; } } #endif #ifdef MONOTONIC_CLOCK_ID_STR - init_resp->os_monotonic_info.clock_id = MONOTONIC_CLOCK_ID_STR; + init_resp->os_monotonic_time_info.clock_id = MONOTONIC_CLOCK_ID_STR; #else - init_resp->os_monotonic_info.clock_id = NULL; + init_resp->os_monotonic_time_info.clock_id = NULL; #endif - init_resp->os_monotonic_info.locked_use = 0; + init_resp->os_monotonic_time_info.locked_use = 0; #if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) - init_resp->os_monotonic_info.func = "clock_gettime"; + init_resp->os_monotonic_time_info.func = "clock_gettime"; #elif defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) - init_resp->os_monotonic_info.func = "clock_get_time"; + init_resp->os_monotonic_time_info.func = "clock_get_time"; #elif defined(OS_MONOTONIC_TIME_USING_GETHRTIME) - init_resp->os_monotonic_info.func = "gethrtime"; + init_resp->os_monotonic_time_info.func = "gethrtime"; #elif defined(OS_MONOTONIC_TIME_USING_TIMES) - init_resp->os_monotonic_info.func = "times"; + init_resp->os_monotonic_time_info.func = "times"; #else # error Unknown erts_os_monotonic_time() implementation #endif - init_resp->have_os_monotonic = 1; + init_resp->have_os_monotonic_time = 1; os_version(&major, &minor, &build); @@ -210,7 +212,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) "os_monotonic_time"); internal_state.w.f.last_delivered = clock_gettime_monotonic_raw(); - init_resp->os_monotonic_info.locked_use = 1; + init_resp->os_monotonic_time_info.locked_use = 1; } #else /* !(defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)) */ { @@ -227,7 +229,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF) if (sysconf(_SC_NPROCESSORS_CONF) > 1) #endif - init_resp->have_os_monotonic = 0; + init_resp->have_os_monotonic_time = 0; } } } @@ -261,9 +263,9 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) shift++; } - init_resp->os_monotonic_info.resolution = resolution; + init_resp->os_monotonic_time_info.resolution = resolution; init_resp->os_monotonic_time_unit = time_unit; - init_resp->os_monotonic_info.extended = 1; + init_resp->os_monotonic_time_info.extended = 1; internal_state.r.o.times_shift = shift; erts_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd, @@ -272,6 +274,38 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) } #endif /* defined(OS_MONOTONIC_TIME_USING_TIMES) */ +#ifdef WALL_CLOCK_ID_STR + init_resp->os_system_time_info.clock_id = WALL_CLOCK_ID_STR; +#else + init_resp->os_system_time_info.clock_id = NULL; +#endif + + init_resp->os_system_time_info.locked_use = 0; + init_resp->os_system_time_info.resolution = (Uint64) 1000*1000*1000; +#if defined(HAVE_CLOCK_GETRES) && defined(WALL_CLOCK_ID) + { + struct timespec ts; + if (clock_getres(WALL_CLOCK_ID, &ts) == 0) { + if (ts.tv_sec == 0 && ts.tv_nsec != 0) + init_resp->os_system_time_info.resolution /= ts.tv_nsec; + else if (ts.tv_sec >= 1) + init_resp->os_system_time_info.resolution = 1; + } + } +#endif + +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) + init_resp->os_system_time_info.func = "clock_gettime"; +#elif defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) + init_resp->os_system_time_info.func = "clock_get_time"; +#elif defined(OS_SYSTEM_TIME_GETTIMEOFDAY) + init_resp->os_system_time_info.func = "gettimeofday"; + init_resp->os_system_time_info.resolution = 1000*1000; + init_resp->os_system_time_info.clock_id = NULL; +#else +# error Missing erts_os_system_time() implmenentation +#endif + } void @@ -282,6 +316,105 @@ erts_late_sys_init_time(void) #endif } +static ERTS_INLINE ErtsSystemTime +adj_stime_time_unit(ErtsSystemTime stime, Uint32 res) +{ + if (res == ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT) + return stime; + if (res == (Uint32) 1000*1000*1000 + && ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT == 1000*1000) + return stime/1000; + if (res == (Uint32) 1000*1000 + && ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT == 1000*1000*1000) + return stime*1000; + return ((ErtsSystemTime) + erts_time_unit_conversion(stime, + (Uint32) res, + (Uint32) ERTS_MONOTONIC_TIME_UNIT)); +} + +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) + +ErtsSystemTime +erts_os_system_time(void) +{ + ErtsSystemTime stime; + struct timespec ts; + + if (clock_gettime(WALL_CLOCK_ID,&ts) != 0) { + int err = errno; + char *errstr = err ? strerror(err) : "unknown"; + erl_exit(ERTS_ABORT_EXIT, + "clock_gettime(%s, _) failed: %s (%d)\n", + WALL_CLOCK_ID_STR, errstr, err); + + } + + stime = (ErtsSystemTime) ts.tv_sec; + stime *= (ErtsSystemTime) 1000*1000*1000; + stime += (ErtsSystemTime) ts.tv_nsec; + return adj_stime_time_unit(stime, (Uint32) 1000*1000*1000); +} + +#elif defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) + +ErtsSystemTime +erts_os_system_time(void) +{ + ErtsSystemTime stime; + kern_return_t res; + clock_serv_t clk_srv; + mach_timespec_t time_spec; + int err; + + host_get_clock_service(mach_host_self(), + WALL_CLOCK_ID, + &clk_srv); + errno = 0; + res = clock_get_time(clk_srv, &time_spec); + err = errno; + mach_port_deallocate(mach_task_self(), clk_srv); + if (res != KERN_SUCCESS) { + char *errstr = err ? strerror(err) : "unknown"; + erl_exit(ERTS_ABORT_EXIT, + "clock_get_time(%s, _) failed: %s (%d)\n", + MONOTONIC_CLOCK_ID_STR, errstr, err); + } + + stime = (ErtsSystemTime) time_spec.tv_sec; + stime *= (ErtsSystemTime) 1000*1000*1000; + stime += (ErtsSystemTime) time_spec.tv_nsec; + + return adj_stime_time_unit(stime, (Uint32) 1000*1000*1000); +} + +#elif defined(OS_SYSTEM_TIME_GETTIMEOFDAY) + +ErtsSystemTime +erts_os_system_time(void) +{ + ErtsSystemTime stime; + struct timeval tv; + + if (gettimeofday(&tv, NULL) != 0) { + int err = errno; + char *errstr = err ? strerror(err) : "unknown"; + erl_exit(ERTS_ABORT_EXIT, + "gettimeofday(_, NULL) failed: %s (%d)\n", + errstr, err); + } + + stime = (ErtsSystemTime) tv.tv_sec; + stime *= (ErtsSystemTime) 1000*1000; + stime += (ErtsSystemTime) tv.tv_usec; + + return adj_stime_time_unit(stime, (Uint32) 1000*1000); +} + +#else +# error Missing erts_os_system_time() implmenentation +#endif + #if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) static ERTS_INLINE ErtsMonotonicTime diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h index febf3b5cca..d214ba002c 100644 --- a/erts/emulator/sys/win32/erl_win_sys.h +++ b/erts/emulator/sys/win32/erl_win_sys.h @@ -181,6 +181,10 @@ typedef LONGLONG ErtsMonotonicTime; typedef LONGLONG ErtsSysHrTime; #endif +typedef ErtsMonotonicTime ErtsSystemTime; + +ErtsSystemTime erts_os_system_time(void); + #define ERTS_MONOTONIC_TIME_MIN (((ErtsMonotonicTime) 1) << 63) #define ERTS_MONOTONIC_TIME_MAX (~ERTS_MONOTONIC_TIME_MIN) diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c index ea180f067f..da9c4d2e29 100644 --- a/erts/emulator/sys/win32/sys_time.c +++ b/erts/emulator/sys/win32/sys_time.c @@ -73,6 +73,8 @@ static int days_in_month[2][13] = { {0,31,28,31,30,31,30,31,31,30,31,30,31}, {0,31,29,31,30,31,30,31,31,30,31,30,31}}; +#define ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT 10 + /* * erts_os_monotonic_time() */ @@ -81,6 +83,7 @@ struct sys_time_internal_state_read_only__ { ULONGLONG (WINAPI *pGetTickCount64)(void); BOOL (WINAPI *pQueryPerformanceCounter)(LARGE_INTEGER *); Sint32 pcf; + int using_get_tick_count_time_unit; }; struct sys_time_internal_state_read_mostly__ { @@ -199,7 +202,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) char kernel_dll_name[] = "kernel32"; HMODULE module; - init_resp->os_monotonic_info.clock_id = NULL; + init_resp->os_monotonic_time_info.clock_id = NULL; module = GetModuleHandle(kernel_dll_name); if (!module) { @@ -209,13 +212,15 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) internal_state.w.f.wrap = 0; internal_state.w.f.last_tick_count = 0; - init_resp->os_monotonic_info.func = "GetTickCount"; - init_resp->os_monotonic_info.locked_use = 1; + init_resp->os_monotonic_time_info.func = "GetTickCount"; + init_resp->os_monotonic_time_info.locked_use = 1; /* 10-16 ms resolution according to MicroSoft documentation */ - init_resp->os_monotonic_info.resolution = 100; /* 10 ms */ - time_unit = (ErtsMonotonicTime) (1000 << 10); + init_resp->os_monotonic_time_info.resolution = 100; /* 10 ms */ + time_unit = (ErtsMonotonicTime) 1000; + time_unit <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + internal_state.r.o.using_get_tick_count_time_unit = 1; os_mtime_func = os_monotonic_time_gtc32; - init_resp->os_monotonic_info.extended = 1; + init_resp->os_monotonic_time_info.extended = 1; erts_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd, get_tick_count, 60*60*24*7); /* Check once a week */ @@ -237,11 +242,13 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) if (!internal_state.r.o.pGetTickCount64) goto get_tick_count; - init_resp->os_monotonic_info.func = "GetTickCount64"; - init_resp->os_monotonic_info.locked_use = 0; + init_resp->os_monotonic_time_info.func = "GetTickCount64"; + init_resp->os_monotonic_time_info.locked_use = 0; /* 10-16 ms resolution according to MicroSoft documentation */ - init_resp->os_monotonic_info.resolution = 100; /* 10 ms */ - time_unit = (ErtsMonotonicTime) (1000 << 10); + init_resp->os_monotonic_time_info.resolution = 100; /* 10 ms */ + time_unit = (ErtsMonotonicTime) 1000; + time_unit <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + internal_state.r.o.using_get_tick_count_time_unit = 1; os_mtime_func = os_monotonic_time_gtc64; if (!sys_hrtime_func) sys_hrtime_func = sys_hrtime_gtc64; @@ -279,25 +286,30 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) if (pf.QuadPart < (LONGLONG) 1000*1000*1000) goto get_tick_count64; - init_resp->os_monotonic_info.func = "QueryPerformanceCounter"; - init_resp->os_monotonic_info.locked_use = 0; + init_resp->os_monotonic_time_info.func = "QueryPerformanceCounter"; + init_resp->os_monotonic_time_info.locked_use = 0; time_unit = (ErtsMonotonicTime) pf.QuadPart; - init_resp->os_monotonic_info.resolution = time_unit; + internal_state.r.o.using_get_tick_count_time_unit = 0; + init_resp->os_monotonic_time_info.resolution = time_unit; os_mtime_func = os_monotonic_time_qpc; } } erts_sys_time_data__.r.o.os_monotonic_time = os_mtime_func; init_resp->os_monotonic_time_unit = time_unit; - init_resp->have_os_monotonic = 1; + init_resp->have_os_monotonic_time = 1; init_resp->sys_clock_resolution = 1; + init_resp->os_system_time_info.func = "GetSystemTime"; + init_resp->os_system_time_info.clock_id = NULL; + init_resp->os_system_time_info.resolution = 100; + init_resp->os_system_time_info.locked_use = 0; + if(GetTimeZoneInformation(&static_tzi) && static_tzi.StandardDate.wMonth != 0 && static_tzi.DaylightDate.wMonth != 0) { have_static_tzi = 1; } - } void @@ -585,6 +597,37 @@ sys_gettimeofday(SysTimeval *tv) EPOCH_JULIAN_DIFF); } +ErtsSystemTime +erts_os_system_time(void) +{ + SYSTEMTIME t; + FILETIME ft; + ULARGE_INTEGER ull; + ErtsSystemTime stime; + + GetSystemTime(&t); + SystemTimeToFileTime(&t, &ft); + FILETIME_TO_ULI(ull,ft); + + /* now in 100 ns units */ + + stime = (ErtsSystemTime) ull.QuadPart; + stime -= (((ErtsSystemTime) EPOCH_JULIAN_DIFF) + * ((ErtsSystemTime) (10*1000*1000))); + stime /= (ErtsSystemTime) (10*1000); + + if (internal_state.r.o.using_get_tick_count_time_unit) { + stime <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + return stime; + } + + return ((ErtsSystemTime) + erts_time_unit_conversion(stime, + (Uint32) 1000, + (Uint32) ERTS_MONOTONIC_TIME_UNIT)); +} + + clock_t sys_times(SysTimes *buffer) { clock_t kernel_ticks = (GetTickCount() / |