aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/sys/win32
diff options
context:
space:
mode:
authorRickard Green <[email protected]>2015-03-24 16:56:08 +0100
committerRickard Green <[email protected]>2015-03-24 16:56:08 +0100
commit5345727d647ea65b7a0417c87b94cf958ef9ee13 (patch)
treebcc1c75102741e9768c88b1481390e40e32586e7 /erts/emulator/sys/win32
parenta11cec66e37c039d33091db056c0ae44405043ac (diff)
parentc20482023b70768bd84d25f1e34dbbc2fe09cf31 (diff)
downloadotp-5345727d647ea65b7a0417c87b94cf958ef9ee13.tar.gz
otp-5345727d647ea65b7a0417c87b94cf958ef9ee13.tar.bz2
otp-5345727d647ea65b7a0417c87b94cf958ef9ee13.zip
Merge branch 'rickard/time_api/OTP-11997'
* rickard/time_api/OTP-11997: Better OS system time implementation Documentation adjustments Fix zero timout timers erts_sys_hrtime() for lcnt Better support for poor os monotonic sources Conflicts: erts/preloaded/ebin/erlang.beam
Diffstat (limited to 'erts/emulator/sys/win32')
-rw-r--r--erts/emulator/sys/win32/erl_win_sys.h14
-rw-r--r--erts/emulator/sys/win32/sys_time.c185
2 files changed, 164 insertions, 35 deletions
diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h
index 33aa88ab5f..9aeb460720 100644
--- a/erts/emulator/sys/win32/erl_win_sys.h
+++ b/erts/emulator/sys/win32/erl_win_sys.h
@@ -172,13 +172,19 @@ typedef long long Sint64;
# endif
typedef long long ErtsMonotonicTime;
+typedef long long ErtsSysHrTime;
#else
typedef ULONGLONG Uint64;
typedef LONGLONG Sint64;
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)
@@ -187,6 +193,7 @@ typedef LONGLONG ErtsMonotonicTime;
struct erts_sys_time_read_only_data__ {
ErtsMonotonicTime (*os_monotonic_time)(void);
+ ErtsSysHrTime (*sys_hrtime)(void);
};
typedef struct {
@@ -201,6 +208,7 @@ typedef struct {
extern ErtsSysTimeData__ erts_sys_time_data__;
ERTS_GLB_INLINE ErtsMonotonicTime erts_os_monotonic_time(void);
+ERTS_GLB_INLINE ErtsSysHrTime erts_sys_hrtime(void);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
@@ -210,6 +218,12 @@ erts_os_monotonic_time(void)
return (*erts_sys_time_data__.r.o.os_monotonic_time)();
}
+ERTS_GLB_INLINE ErtsSysHrTime
+erts_sys_hrtime(void)
+{
+ return (*erts_sys_time_data__.r.o.sys_hrtime)();
+}
+
#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
extern void sys_gettimeofday(SysTimeval *tv);
diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c
index 3a10125c81..da9c4d2e29 100644
--- a/erts/emulator/sys/win32/sys_time.c
+++ b/erts/emulator/sys/win32/sys_time.c
@@ -25,6 +25,8 @@
#endif
#include "sys.h"
#include "assert.h"
+#include "erl_os_monotonic_time_extender.h"
+#include "erl_time.h"
#define LL_LITERAL(X) ERTS_I64_LITERAL(X)
@@ -71,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()
*/
@@ -78,6 +82,12 @@ static int days_in_month[2][13] = {
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__ {
+ ErtsOsMonotonicTimeExtendState os_mtime_xtnd;
};
struct sys_time_internal_state_write_freq__ {
@@ -94,6 +104,12 @@ __declspec(align(ASSUMED_CACHE_LINE_SIZE)) struct {
* ASSUMED_CACHE_LINE_SIZE];
} r;
union {
+ struct sys_time_internal_state_read_mostly__ m;
+ char align__[(((sizeof(struct sys_time_internal_state_read_mostly__) - 1)
+ / ASSUMED_CACHE_LINE_SIZE) + 1)
+ * ASSUMED_CACHE_LINE_SIZE];
+ } wr;
+ union {
struct sys_time_internal_state_write_freq__ f;
char align__[(((sizeof(struct sys_time_internal_state_write_freq__) - 1)
/ ASSUMED_CACHE_LINE_SIZE) + 1)
@@ -114,29 +130,63 @@ os_monotonic_time_qpc(void)
return (ErtsMonotonicTime) pc.QuadPart;
}
+static Uint32
+get_tick_count(void)
+{
+ return (Uint32) GetTickCount();
+}
+
static ErtsMonotonicTime
os_monotonic_time_gtc32(void)
{
- ULONGLONG res, ticks;
+ Uint32 ticks = (Uint32) GetTickCount();
+ ERTS_CHK_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd,
+ tick_count);
+ return ERTS_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd,
+ ticks) << 10;
+}
- erts_smp_mtx_lock(&internal_state.w.f.mtime_mtx);
+static ErtsMonotonicTime
+os_monotonic_time_gtc64(void)
+{
+ ULONGLONG ticks = (*internal_state.r.o.pGetTickCount64)();
+ return (ErtsMonotonicTime) ticks << 10;
+}
- ticks = (ULONGLONG) (GetTickCount() & 0x7FFFFFFF);
- if (ticks < internal_state.w.f.last_tick_count)
- internal_state.w.f.wrap += (ULONGLONG) LL_LITERAL(1) << 31;
- internal_state.w.f.last_tick_count = ticks;
- res = ticks + internal_state.w.f.wrap;
+static ErtsSysHrTime
+sys_hrtime_qpc(void)
+{
+ LARGE_INTEGER pc;
- erts_smp_mtx_unlock(&internal_state.w.f.mtime_mtx);
+ if (!(*internal_state.r.o.pQueryPerformanceCounter)(&pc))
+ erl_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n");
- return (ErtsMonotonicTime) res*1000;
+ ASSERT(pc.QuadPart > 0);
+
+ return (ErtsSysHrTime) erts_time_unit_conversion((Uint64) pc.QuadPart,
+ internal_state.r.o.pcf,
+ (Uint32) 1000*1000*1000);
}
-static ErtsMonotonicTime
-os_monotonic_time_gtc64(void)
+static ErtsSysHrTime
+sys_hrtime_gtc32(void)
{
- ULONGLONG ticks = (*internal_state.r.o.pGetTickCount64)();
- return (ErtsMonotonicTime) ticks*1000;
+ ErtsSysHrTime time;
+ Uint32 ticks = (Uint32) GetTickCount();
+ ERTS_CHK_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd,
+ tick_count);
+ time = (ErtsSysHrTime) ERTS_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd,
+ ticks);
+ time *= (ErtsSysHrTime) (1000 * 1000);
+ return time;
+}
+
+static ErtsSysHrTime
+sys_hrtime_gtc64(void)
+{
+ ErtsSysHrTime time = (*internal_state.r.o.pGetTickCount64)();
+ time *= (ErtsSysHrTime) (1000*1000);
+ return time;
}
/*
@@ -147,11 +197,12 @@ void
sys_init_time(ErtsSysInitTimeResult *init_resp)
{
ErtsMonotonicTime (*os_mtime_func)(void);
+ ErtsSysHrTime (*sys_hrtime_func)(void) = NULL;
ErtsMonotonicTime time_unit;
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) {
@@ -161,11 +212,20 @@ 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_info.resolution = 1000;
- time_unit = (ErtsMonotonicTime) 1000*1000;
+ 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_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_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 */
+ if (!sys_hrtime_func)
+ sys_hrtime_func = sys_hrtime_gtc32;
}
else {
int major, minor, build;
@@ -182,11 +242,16 @@ 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_info.resolution = 1000;
- time_unit = (ErtsMonotonicTime) 1000*1000;
+ 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_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;
}
else { /* Vista or newer... */
@@ -199,40 +264,59 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
goto get_tick_count64;
if (!(*QPF)(&pf))
goto get_tick_count64;
- /*
- * We only use QueryPerformanceCounter() if
- * its frequency is equal to, or larger than
- * GHz in order to ensure that the user wont
- * be able to observe faulty order between
- * values retrieved on different threads.
- */
- if (pf.QuadPart < (LONGLONG) 1000*1000*1000)
- goto get_tick_count64;
+
internal_state.r.o.pQueryPerformanceCounter
= ((BOOL (WINAPI *)(LARGE_INTEGER *))
GetProcAddress(module, "QueryPerformanceCounter"));
if (!internal_state.r.o.pQueryPerformanceCounter)
goto get_tick_count64;
- init_resp->os_monotonic_info.func = "QueryPerformanceCounter";
- init_resp->os_monotonic_info.locked_use = 0;
+ if (pf.QuadPart < (((LONGLONG) 1) << 32)) {
+ internal_state.r.o.pcf = (Uint32) pf.QuadPart;
+ sys_hrtime_func = sys_hrtime_qpc;
+ }
+
+ /*
+ * We only use QueryPerformanceCounter() for
+ * os-monotonic-time if its frequency is equal
+ * to, or larger than GHz in order to ensure
+ * that the user wont be able to observe faulty
+ * order between values retrieved on different threads.
+ */
+ if (pf.QuadPart < (LONGLONG) 1000*1000*1000)
+ goto get_tick_count64;
+
+ 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
+erts_late_sys_init_time(void)
+{
+ if (erts_sys_time_data__.r.o.os_monotonic_time == os_monotonic_time_gtc32)
+ erts_late_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd);
}
/* Returns a switchtimes for DST as UTC filetimes given data from a
@@ -513,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() /