File 8212-erts-Improve-checking-of-monotonic-time.patch of Package erlang
From 122c5d5d7da34d63b0fa6b215137b6a5585a8d56 Mon Sep 17 00:00:00 2001
From: Rickard Green <rickard@erlang.org>
Date: Tue, 26 Mar 2024 14:41:12 +0100
Subject: [PATCH 2/3] [erts] Improve checking of monotonic time
---
erts/emulator/beam/erl_process.c | 3 +
erts/emulator/beam/erl_process.h | 3 +
erts/emulator/beam/erl_time.h | 6 ++
erts/emulator/beam/erl_time_sup.c | 120 ++++++++++++++++++++++--------
4 files changed, 100 insertions(+), 32 deletions(-)
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index ab39507bd3..a6297a9518 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -5943,6 +5943,9 @@ init_scheduler_data(ErtsSchedulerData* esdp, int num,
erts_init_atom_cache_map(&esdp->atom_cache_map);
esdp->last_monotonic_time = 0;
+#ifdef ERTS_CHECK_MONOTONIC_TIME
+ esdp->last_os_monotonic_time = ERTS_SINT64_MIN;
+#endif
esdp->check_time_reds = 0;
esdp->thr_id = (Uint32) num;
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index a112229067..a4a37d691d 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -704,6 +704,9 @@ struct ErtsSchedulerData_ {
ErtsAtomCacheMap atom_cache_map;
ErtsMonotonicTime last_monotonic_time;
+#ifdef ERTS_CHECK_MONOTONIC_TIME
+ ErtsMonotonicTime last_os_monotonic_time;
+#endif
int check_time_reds;
Uint32 thr_id;
diff --git a/erts/emulator/beam/erl_time.h b/erts/emulator/beam/erl_time.h
index 968f21fd51..568899b144 100644
--- a/erts/emulator/beam/erl_time.h
+++ b/erts/emulator/beam/erl_time.h
@@ -98,6 +98,12 @@ void erts_p_slpq(void);
/* time_sup */
+/*
+ * If ERTS_CHECK_MONOTONIC_TIME is defined we will check that Erlang
+ * and OS monotonic time are monotonic on a per thread basis...
+ */
+#define ERTS_CHECK_MONOTONIC_TIME 1
+
#if (defined(HAVE_GETHRVTIME) || defined(HAVE_CLOCK_GETTIME_CPU_TIME))
# ifndef HAVE_ERTS_NOW_CPU
# define HAVE_ERTS_NOW_CPU
diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c
index 0e1d4b087f..5c5ab22172 100644
--- a/erts/emulator/beam/erl_time_sup.c
+++ b/erts/emulator/beam/erl_time_sup.c
@@ -82,7 +82,7 @@ static void
schedule_send_time_offset_changed_notifications(ErtsMonotonicTime new_offset);
struct time_sup_read_only__ {
- ErtsMonotonicTime (*get_time)(void);
+ ErtsMonotonicTime (*get_time)(ErtsSchedulerData *esdp);
int correction;
ErtsTimeWarpMode warp_mode;
#ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
@@ -214,17 +214,17 @@ get_time_offset(void)
static ERTS_INLINE void
update_last_mtime(ErtsSchedulerData *esdp, ErtsMonotonicTime mtime)
{
- if (!esdp)
- esdp = erts_get_scheduler_data();
if (esdp) {
-#if 1
- if (mtime < esdp->last_monotonic_time)
+#ifdef ERTS_CHECK_MONOTONIC_TIME
+ if (esdp->last_monotonic_time > mtime) {
+ ERTS_ASSERT(esdp == erts_get_scheduler_data());
erts_exit(ERTS_ABORT_EXIT,
- "Monotonic time stepped backwards!\n"
+ "Erlang monotonic time stepped backwards!\n"
"Previous time: %b64d\n"
"Current time: %b64d\n",
esdp->last_monotonic_time,
mtime);
+ }
#endif
ASSERT(mtime >= esdp->last_monotonic_time);
esdp->last_monotonic_time = mtime;
@@ -232,6 +232,26 @@ update_last_mtime(ErtsSchedulerData *esdp, ErtsMonotonicTime mtime)
}
}
+static ERTS_INLINE void
+check_os_monotonic_time(ErtsSchedulerData *esdp, ErtsMonotonicTime mtime)
+{
+#ifdef ERTS_CHECK_MONOTONIC_TIME
+ if (esdp) {
+ if (esdp->last_os_monotonic_time > mtime) {
+ ERTS_ASSERT(esdp == erts_get_scheduler_data());
+ erts_exit(ERTS_ABORT_EXIT,
+ "OS monotonic time stepped backwards!\n"
+ "Previous time: %b64d\n"
+ "Current time: %b64d\n",
+ esdp->last_os_monotonic_time,
+ mtime);
+ }
+ esdp->last_os_monotonic_time = mtime;
+ }
+#endif
+}
+
+
#ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT
/*
@@ -283,7 +312,7 @@ calc_corrected_erl_mtime(ErtsMonotonicTime os_mtime,
}
static ERTS_INLINE ErtsMonotonicTime
-read_corrected_time(int os_drift_corrected)
+read_corrected_time(int os_drift_corrected, ErtsSchedulerData *esdp)
{
ErtsMonotonicTime os_mtime;
ErtsMonotonicCorrectionInstance ci;
@@ -303,18 +332,20 @@ read_corrected_time(int os_drift_corrected)
erts_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx);
+ check_os_monotonic_time(esdp, os_mtime);
+
return calc_corrected_erl_mtime(os_mtime, &ci, NULL,
os_drift_corrected);
}
-static ErtsMonotonicTime get_os_drift_corrected_time(void)
+static ErtsMonotonicTime get_os_drift_corrected_time(ErtsSchedulerData *esdp)
{
- return read_corrected_time(!0);
+ return read_corrected_time(!0, esdp);
}
-static ErtsMonotonicTime get_corrected_time(void)
+static ErtsMonotonicTime get_corrected_time(ErtsSchedulerData *esdp)
{
- return read_corrected_time(0);
+ return read_corrected_time(0, esdp);
}
#ifdef ERTS_TIME_CORRECTION_PRINT
@@ -379,6 +410,9 @@ check_time_correction(void *vesdp)
int os_drift_corrected = time_sup.r.o.os_corrected_monotonic_time;
int set_new_correction = 0, begin_short_intervals = 0;
+ if (!esdp)
+ esdp = erts_get_scheduler_data();
+
erts_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx);
erts_os_times(&os_mtime, &os_stime);
@@ -387,6 +421,8 @@ check_time_correction(void *vesdp)
erts_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx);
+ check_os_monotonic_time(esdp, os_mtime);
+
if (os_mtime < ci.os_mtime)
erts_exit(ERTS_ABORT_EXIT,
"OS monotonic time stepped backwards\n");
@@ -677,10 +713,9 @@ check_time_correction(void *vesdp)
time_sup.inf.c.parmon.cdata.insts.curr.correction = new_correction;
erts_rwmtx_rwunlock(&time_sup.inf.c.parmon.rwmtx);
- }
- if (!esdp)
- esdp = erts_get_scheduler_data();
+ check_os_monotonic_time(esdp, os_mtime);
+ }
erts_twheel_set_timer(esdp->timer_wheel,
&time_sup.inf.c.parmon.timer,
@@ -689,10 +724,13 @@ check_time_correction(void *vesdp)
timeout_pos);
}
-static ErtsMonotonicTime get_os_corrected_time(void)
+static ErtsMonotonicTime get_os_corrected_time(ErtsSchedulerData *esdp)
{
+ ErtsMonotonicTime os_mtime;
ASSERT(time_sup.r.o.warp_mode == ERTS_MULTI_TIME_WARP_MODE);
- return erts_os_monotonic_time() + time_sup.r.o.moffset;
+ os_mtime = erts_os_monotonic_time();
+ check_os_monotonic_time(esdp, os_mtime);
+ return os_mtime + time_sup.r.o.moffset;
}
static void
@@ -706,6 +744,8 @@ check_time_offset(void *vesdp)
erts_os_times(&os_mtime, &os_stime);
+ check_os_monotonic_time(esdp, os_mtime);
+
erl_mtime = os_mtime + time_sup.r.o.moffset;
time_offset = get_time_offset();
erl_stime = erl_mtime + time_offset;
@@ -754,6 +794,11 @@ init_check_time_correction(void *vesdp)
erts_os_times(&mtime, &stime);
+ check_os_monotonic_time((!vesdp
+ ? erts_get_scheduler_data()
+ : (ErtsSchedulerData *) vesdp),
+ mtime);
+
mtime_diff = mtime - old_mtime;
stime_diff = stime - old_stime;
smtime_diff = stime_diff - mtime_diff;
@@ -802,6 +847,8 @@ finalize_corrected_time_offset(ErtsSystemTime *stimep)
erts_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx);
+ check_os_monotonic_time(erts_get_scheduler_data(), os_mtime);
+
if (os_mtime < ci.os_mtime)
erts_exit(ERTS_ABORT_EXIT,
"OS monotonic time stepped backwards\n");
@@ -849,7 +896,7 @@ late_init_time_correction(ErtsSchedulerData *esdp)
#endif /* ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT */
-static ErtsMonotonicTime get_not_corrected_time(void)
+static ErtsMonotonicTime get_not_corrected_time(ErtsSchedulerData *esdp)
{
ErtsMonotonicTime stime, mtime;
@@ -1120,8 +1167,7 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode)
ErtsMonotonicCorrectionData *cdatap;
erts_rwmtx_opt_t rwmtx_opts = ERTS_RWMTX_OPT_DEFAULT_INITER;
ErtsMonotonicTime offset;
- erts_os_times(&time_sup.inf.c.minit,
- &time_sup.inf.c.sinit);
+ erts_os_times(&time_sup.inf.c.minit, &time_sup.inf.c.sinit);
time_sup.r.o.moffset = -1*time_sup.inf.c.minit;
time_sup.r.o.moffset += ERTS_MONOTONIC_BEGIN;
offset = time_sup.inf.c.sinit;
@@ -1371,9 +1417,10 @@ void
erts_wall_clock_elapsed_both(ErtsMonotonicTime *ms_total, ErtsMonotonicTime *ms_diff)
{
ErtsMonotonicTime now, elapsed;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
- now = time_sup.r.o.get_time();
- update_last_mtime(NULL, now);
+ now = time_sup.r.o.get_time(esdp);
+ update_last_mtime(esdp, now);
elapsed = ERTS_MONOTONIC_TO_MSEC(now);
elapsed -= ERTS_MONOTONIC_TO_MSEC(ERTS_MONOTONIC_BEGIN);
@@ -1740,10 +1787,11 @@ void
get_now(Uint* megasec, Uint* sec, Uint* microsec)
{
ErtsMonotonicTime now_megasec, now_sec, now, prev, mtime, time_offset;
-
- mtime = time_sup.r.o.get_time();
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+
+ mtime = time_sup.r.o.get_time(esdp);
time_offset = get_time_offset();
- update_last_mtime(NULL, mtime);
+ update_last_mtime(esdp, mtime);
now = ERTS_MONOTONIC_TO_USEC(mtime + time_offset);
/* Make sure now time is later than last time */
@@ -1775,7 +1823,10 @@ get_now(Uint* megasec, Uint* sec, Uint* microsec)
ErtsMonotonicTime
erts_get_monotonic_time(ErtsSchedulerData *esdp)
{
- ErtsMonotonicTime mtime = time_sup.r.o.get_time();
+ ErtsMonotonicTime mtime;
+ if (!esdp)
+ esdp = erts_get_scheduler_data();
+ mtime = time_sup.r.o.get_time(esdp);
update_last_mtime(esdp, mtime);
return mtime;
}
@@ -2267,7 +2318,7 @@ erts_napi_monotonic_time(int time_unit)
if (!esdp)
return ERTS_NAPI_TIME_ERROR;
- mtime = time_sup.r.o.get_time();
+ mtime = time_sup.r.o.get_time(esdp);
update_last_mtime(esdp, mtime);
switch (time_unit) {
@@ -2371,7 +2422,8 @@ erts_napi_convert_time_unit(ErtsMonotonicTime val, int from, int to)
BIF_RETTYPE monotonic_time_0(BIF_ALIST_0)
{
- ErtsMonotonicTime mtime = time_sup.r.o.get_time();
+ ErtsSchedulerData *esdp = erts_proc_sched_data(BIF_P);
+ ErtsMonotonicTime mtime = time_sup.r.o.get_time(esdp);
update_last_mtime(erts_proc_sched_data(BIF_P), mtime);
mtime += ERTS_MONOTONIC_OFFSET_NATIVE;
BIF_RET(make_time_val(BIF_P, mtime));
@@ -2379,26 +2431,29 @@ BIF_RETTYPE monotonic_time_0(BIF_ALIST_0)
BIF_RETTYPE monotonic_time_1(BIF_ALIST_1)
{
- ErtsMonotonicTime mtime = time_sup.r.o.get_time();
- update_last_mtime(erts_proc_sched_data(BIF_P), mtime);
+ ErtsSchedulerData *esdp = erts_proc_sched_data(BIF_P);
+ ErtsMonotonicTime mtime = time_sup.r.o.get_time(esdp);
+ update_last_mtime(esdp, mtime);
BIF_RET(time_unit_conversion(BIF_P, BIF_ARG_1, mtime, 1));
}
BIF_RETTYPE system_time_0(BIF_ALIST_0)
{
ErtsMonotonicTime mtime, offset;
- mtime = time_sup.r.o.get_time();
+ ErtsSchedulerData *esdp = erts_proc_sched_data(BIF_P);
+ mtime = time_sup.r.o.get_time(esdp);
offset = get_time_offset();
- update_last_mtime(erts_proc_sched_data(BIF_P), mtime);
+ update_last_mtime(esdp, mtime);
BIF_RET(make_time_val(BIF_P, mtime + offset));
}
BIF_RETTYPE system_time_1(BIF_ALIST_0)
{
ErtsMonotonicTime mtime, offset;
- mtime = time_sup.r.o.get_time();
+ ErtsSchedulerData *esdp = erts_proc_sched_data(BIF_P);
+ mtime = time_sup.r.o.get_time(esdp);
offset = get_time_offset();
- update_last_mtime(erts_proc_sched_data(BIF_P), mtime);
+ update_last_mtime(esdp, mtime);
BIF_RET(time_unit_conversion(BIF_P, BIF_ARG_1, mtime + offset, 0));
}
@@ -2425,10 +2480,11 @@ BIF_RETTYPE timestamp_0(BIF_ALIST_0)
Eterm *hp, res;
ErtsMonotonicTime mtime, offset;
Uint mega_sec, sec, micro_sec;
+ ErtsSchedulerData *esdp = erts_proc_sched_data(BIF_P);
- mtime = time_sup.r.o.get_time();
+ mtime = time_sup.r.o.get_time(esdp);
offset = get_time_offset();
- update_last_mtime(erts_proc_sched_data(BIF_P), mtime);
+ update_last_mtime(esdp, mtime);
make_timestamp_value(&mega_sec, &sec, µ_sec, mtime, offset);
--
2.35.3