Added FAKETIME_XRESET to smoothen run-time transition between 'x' modifier values (#198)

This commit is contained in:
Wolfgang Hommel
2019-08-22 00:49:21 +02:00
parent 5ddb237842
commit 52108dba7a
2 changed files with 93 additions and 0 deletions

35
README
View File

@@ -376,6 +376,41 @@ LD_PRELOAD=/path/to/libfaketime.so.1 \
touch -t 2002290123.45 /tmp/my-demo-file.tmp
Changing the 'x' modifier during run-time
-----------------------------------------
Using FAKETIME_TIMESTAMP_FILE allows for easily changing the FAKETIME setting
while a program is running:
echo "+0 x1" > /tmp/my-faketime.rc
LD_PRELOAD=libfaketime.so.1 FAKETIME_TIMESTAMP_FILE="/tmp/my-faketime.rc" \
FAKETIME_NO_CACHE=1 ./some-program &
sleep 10 ; echo "+0 x10" > /tmp/my-faketime.rc
Changing the speed of the wall clock time, i.e., using a different 'x' modifier
during run-time, by default can lead to greater jumps that may confuse the
program. For example, if the program has been running for 10 seconds on 'x1',
and then the setting is changed to 'x10', the faked time will look to the
program as if it has been running for more than 100 instead of just more than
10 seconds.
By setting the environment variable FAKETIME_XRESET to any value, transitions
between different 'x' modifier values will be significantly smoothed:
LD_PRELOAD=libfaketime.so.1 FAKETIME_TIMESTAMP_FILE="/tmp/my-faketime.rc" \
FAKETIME_NO_CACHE=1 FAKETIME_XRESET=1 ./some-program &
Setting FAKETIME_XRESET ensures that wall clock time begins to run faster
only after the 'x' modifier has been changed (when increasing it) and also
ensures that the reported faked time does not jump back to past values
(when decreasing it).
Please note that FAKETIME_XRESET internally works by resetting libfaketime's
internal time-keeping data structures, which may have side effects on reported
file timestamps. Using FAKETIME_XRESET should be considered experimental at
the moment.
4f) Faking the date and time system-wide
----------------------------------------

View File

@@ -248,8 +248,12 @@ static int cache_duration = 10; /* cache fake time input for 10 seconds */
*/
#ifndef CLOCK_BOOTTIME
static struct system_time_s ftpl_starttime = {{0, -1}, {0, -1}, {0, -1}};
static struct system_time_s ftpl_timecache = {{0, -1}, {0, -1}, {0, -1}};
static struct system_time_s ftpl_faketimecache = {{0, -1}, {0, -1}, {0, -1}};
#else
static struct system_time_s ftpl_starttime = {{0, -1}, {0, -1}, {0, -1}, {0, -1}};
static struct system_time_s ftpl_timecache = {{0, -1}, {0, -1}, {0, -1}, {0, -1}};
static struct system_time_s ftpl_faketimecache = {{0, -1}, {0, -1}, {0, -1}, {0, -1}};
#endif
static char user_faked_time_fmt[BUFSIZ] = {0};
@@ -1951,6 +1955,22 @@ parse_modifiers:
{
user_rate = atof(strchr(user_faked_time, 'x')+1);
user_rate_set = true;
if (NULL != getenv("FAKETIME_XRESET")) {
if (ftpl_timecache.real.tv_nsec >= 0) {
user_faked_time_timespec.tv_sec = ftpl_faketimecache.real.tv_sec;
user_faked_time_timespec.tv_nsec = ftpl_faketimecache.real.tv_nsec;
ftpl_starttime.real.tv_sec = ftpl_timecache.real.tv_sec;
ftpl_starttime.real.tv_nsec = ftpl_timecache.real.tv_nsec;
ftpl_starttime.mon.tv_sec = ftpl_timecache.mon.tv_sec;
ftpl_starttime.mon.tv_nsec = ftpl_timecache.mon.tv_nsec;
ftpl_starttime.mon_raw.tv_sec = ftpl_timecache.mon_raw.tv_sec;
ftpl_starttime.mon_raw.tv_nsec = ftpl_timecache.mon_raw.tv_nsec;
#ifdef CLOCK_BOOTTIME
ftpl_starttime.boot.tv_sec = ftpl_timecache.boot.tv_sec;
ftpl_starttime.boot.tv_nsec = ftpl_timecache.boot.tv_nsec;
#endif
}
}
}
else if (NULL != (tmp_time_fmt = strchr(user_faked_time, 'i')))
{
@@ -2363,6 +2383,11 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
static time_t last_data_fetch = 0; /* not fetched previously at first call */
static int cache_expired = 1; /* considered expired at first call */
/* create a copy of the timespec containing the real system time for clk_id */
struct timespec tp_save;
tp_save.tv_sec = tp->tv_sec;
tp_save.tv_nsec = tp->tv_nsec;
if (dont_fake) return 0;
/* Per process timers are only sped up or slowed down */
if ((clk_id == CLOCK_PROCESS_CPUTIME_ID ) || (clk_id == CLOCK_THREAD_CPUTIME_ID))
@@ -2595,6 +2620,39 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
pthread_cleanup_pop(1);
#endif
save_time(tp);
/* Cache this most recent real and faked time we encountered */
if (clk_id == CLOCK_REALTIME)
{
ftpl_timecache.real.tv_sec = tp_save.tv_sec;
ftpl_timecache.real.tv_nsec = tp_save.tv_nsec;
ftpl_faketimecache.real.tv_sec = tp->tv_sec;
ftpl_faketimecache.real.tv_nsec = tp->tv_nsec;
}
else if (clk_id == CLOCK_MONOTONIC)
{
ftpl_timecache.mon.tv_sec = tp_save.tv_sec;
ftpl_timecache.mon.tv_nsec = tp_save.tv_nsec;
ftpl_faketimecache.mon.tv_sec = tp->tv_sec;
ftpl_faketimecache.mon.tv_nsec = tp->tv_nsec;
}
else if (clk_id == CLOCK_MONOTONIC_RAW)
{
ftpl_timecache.mon_raw.tv_sec = tp_save.tv_sec;
ftpl_timecache.mon_raw.tv_nsec = tp_save.tv_nsec;
ftpl_faketimecache.mon_raw.tv_sec = tp->tv_sec;
ftpl_faketimecache.mon_raw.tv_nsec = tp->tv_nsec;
}
#ifdef CLOCK_BOOTTIME
else if (clk_id == CLOCK_BOOTTIME)
{
ftpl_timecache.boot.tv_sec = tp_save.tv_sec;
ftpl_timecache.boot.tv_nsec = tp_save.tv_nsec;
ftpl_faketimecache.boot.tv_sec = tp->tv_sec;
ftpl_faketimecache.boot.tv_nsec = tp->tv_nsec;
}
#endif
return 0;
}