static void init_tolerant_timeofday(void) { /* Should be in sys.c */ #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF) if (sysconf(_SC_NPROCESSORS_CONF) > 1) { char b[1024]; int maj,min,build; os_flavor(b,1024); os_version(&maj,&min,&build); if (!strcmp(b,"sunos") && maj <= 5 && min <= 7) { erts_disable_tolerant_timeofday = 1; } } #endif hr_init_time = sys_gethrtime(); hr_last_correction_check = hr_last_time = hr_init_time; hr_correction = 0; }
void sys_init_time(ErtsSysInitTimeResult *init_resp) { #if defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) int major, minor, build, vsn; #endif #if defined(ERTS_MACH_CLOCKS) mach_clocks_init(); #endif #if !defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) init_resp->have_os_monotonic_time = 0; #else /* defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) */ #ifdef ERTS_HAVE_CORRECTED_OS_MONOTONIC_TIME init_resp->have_corrected_os_monotonic_time = 1; #else init_resp->have_corrected_os_monotonic_time = 0; #endif 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) { 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; } } #elif defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(MONOTONIC_CLOCK_ID) init_resp->os_monotonic_time_info.resolution = mach_clock_getres(&internal_state.r.o.mach.clock.monotonic); #endif #ifdef MONOTONIC_CLOCK_ID_STR init_resp->os_monotonic_time_info.clock_id = MONOTONIC_CLOCK_ID_STR; #else init_resp->os_monotonic_time_info.clock_id = NULL; #endif init_resp->os_monotonic_time_info.locked_use = 0; #if defined(OS_MONOTONIC_TIME_USING_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_time_info.func = "clock_get_time"; #elif defined(OS_MONOTONIC_TIME_USING_GETHRTIME) init_resp->os_monotonic_time_info.func = "gethrtime"; #elif defined(OS_MONOTONIC_TIME_USING_TIMES) init_resp->os_monotonic_time_info.func = "times"; #else # error Unknown erts_os_monotonic_time() implementation #endif init_resp->have_os_monotonic_time = 1; os_version(&major, &minor, &build); vsn = ERTS_MK_VSN_INT(major, minor, build); #if defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) if (vsn >= ERTS_MK_VSN_INT(2, 6, 33)) { erts_sys_time_data__.r.o.os_monotonic_time = clock_gettime_monotonic; #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) erts_sys_time_data__.r.o.os_times = clock_gettime_times; #endif } else { /* * Linux versions prior to 2.6.33 have a * known bug that sometimes cause the NTP * adjusted monotonic clock to take small * steps backwards. Use raw monotonic clock * if it is present; otherwise, fall back * on locked verification of values. */ init_resp->have_corrected_os_monotonic_time = 0; #if defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) /* We know that CLOCK_MONOTONIC_RAW is defined, but we don't know if we got a kernel that supports it. Support for CLOCK_MONOTONIC_RAW appeared in kernel 2.6.28... */ if (vsn >= ERTS_MK_VSN_INT(2, 6, 28)) { erts_sys_time_data__.r.o.os_monotonic_time = clock_gettime_monotonic_raw; #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) erts_sys_time_data__.r.o.os_times = clock_gettime_times_raw; #endif init_resp->os_monotonic_time_info.clock_id = "CLOCK_MONOTONIC_RAW"; } else #endif /* defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW) */ { erts_sys_time_data__.r.o.os_monotonic_time = clock_gettime_monotonic_verified; #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) erts_sys_time_data__.r.o.os_times = clock_gettime_times_verified; #endif erts_smp_mtx_init(&internal_state.w.f.mtx, "os_monotonic_time"); internal_state.w.f.last_delivered = clock_gettime_monotonic(); init_resp->os_monotonic_time_info.locked_use = 1; } } #else /* !(defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)) */ { char flavor[1024]; os_flavor(flavor, sizeof(flavor)); if (sys_strcmp(flavor, "sunos") == 0) { /* * Don't trust hrtime on multi processors * on SunOS prior to SunOS 5.8 */ if (vsn < ERTS_MK_VSN_INT(5, 8, 0)) { #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF) if (sysconf(_SC_NPROCESSORS_CONF) > 1) #endif init_resp->have_os_monotonic_time = 0; } } } #endif /* !(defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)) */ #endif /* defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) */ #ifdef ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT init_resp->os_monotonic_time_unit = ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT; #endif init_resp->sys_clock_resolution = SYS_CLOCK_RESOLUTION; /* * This (erts_sys_time_data__.r.o.ticks_per_sec) is only for * times() (CLK_TCK), the resolution is always one millisecond.. */ if ((erts_sys_time_data__.r.o.ticks_per_sec = TICKS_PER_SEC()) < 0) erl_exit(ERTS_ABORT_EXIT, "Can't get clock ticks/sec\n"); #if defined(OS_MONOTONIC_TIME_USING_TIMES) #if ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT # error Time unit is supposed to be determined at runtime... #endif { ErtsMonotonicTime resolution = erts_sys_time_data__.r.o.ticks_per_sec; ErtsMonotonicTime time_unit = resolution; int shift = 0; while (time_unit < 1000*1000) { time_unit <<= 1; shift++; } init_resp->os_monotonic_time_info.resolution = resolution; init_resp->os_monotonic_time_unit = time_unit; 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, get_tick_count, (1 << 29) / resolution); } #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; } } #elif defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(WALL_CLOCK_ID) init_resp->os_system_time_info.resolution = mach_clock_getres(&internal_state.r.o.mach.clock.wall); #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() implementation #endif }