Skip to content

Commit 3343efd

Browse files
committed
hacking on tapering
1 parent a08fc39 commit 3343efd

File tree

1 file changed

+161
-40
lines changed

1 file changed

+161
-40
lines changed

src/libfaketime.c

+161-40
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,9 @@ static int outfile = -1;
341341
static bool limited_faking = false;
342342
static long callcounter = 0;
343343

344-
static long long ft_keep_before_nsec_since_epoch = -1;
344+
static bool ft_taper = 0;
345+
static long long ft_taper_begin_nsec_since_epoch = -1;
346+
static long long ft_taper_end_nsec_since_epoch = -1;
345347

346348
static long ft_start_after_secs = -1;
347349
static long ft_stop_after_secs = -1;
@@ -1159,6 +1161,133 @@ int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct
11591161
}
11601162
#endif
11611163

1164+
static long long faketime_offset() {
1165+
return ((long long)user_offset.tv_sec) * 1000000000 + (long long)user_offset.tv_nsec;
1166+
}
1167+
1168+
// (a * b + c) / d, but do something to avoid multiplication overflow
1169+
// (only "mostly" prevents overflow, not if the values are already
1170+
// over 2^62)
1171+
//
1172+
// precondition: a < d, r < d (b is not constrained)
1173+
static long long mad_div_avoid_overflow_inner(long long a, long long b, long long c, long long d)
1174+
{
1175+
if (a <= 1 || b <= 1) {
1176+
return (a * b + c) / d;
1177+
}
1178+
// how many multiples of [a] we need to make a full [d]
1179+
long long k = (d + a - 1) / a; // 2 <= k <= d/2+1
1180+
long long rem_per_f = a * k - d;
1181+
// how many occurrences of [a*k] (and therefore [d]) we can
1182+
// easily take from [a*b]
1183+
long long f = b / k;
1184+
// remaining: rem_per_f * f + (b % k) * a + c
1185+
long long rem = (b % k) * a + c;
1186+
long long res = f + rem / d;
1187+
rem = rem % d;
1188+
return res + mad_div_avoid_overflow_inner(rem_per_f, f, rem, d);
1189+
}
1190+
1191+
static long long mult_div_avoid_overflow(long long a, long long b, long long d)
1192+
{
1193+
long long res = a / d;
1194+
return res + mad_div_avoid_overflow_inner(a%d, b, 0, d);
1195+
}
1196+
1197+
static long long faketime_do_tapered_offset(long long t) {
1198+
if (!ft_taper) {
1199+
return t + faketime_offset();
1200+
}
1201+
if (t <= ft_taper_begin_nsec_since_epoch) {
1202+
return t;
1203+
}
1204+
if (t >= ft_taper_end_nsec_since_epoch) {
1205+
return t + faketime_offset();
1206+
}
1207+
long long taper_range = ft_taper_end_nsec_since_epoch - ft_taper_begin_nsec_since_epoch;
1208+
long long offset_range = faketime_offset() + taper_range;
1209+
// [offset_range] virtual time passes over [taper_range] real time
1210+
long long dt = t - ft_taper_begin_nsec_since_epoch;
1211+
// so we're looking for dt * offset_range / taper_range, doing
1212+
long long dvt = mult_div_avoid_overflow(dt, offset_range, taper_range);
1213+
// something complicated to avoid overflow.
1214+
long long res = ft_taper_begin_nsec_since_epoch + dvt;
1215+
return res;
1216+
}
1217+
1218+
static long long faketime_undo_tapered_offset(long long t) {
1219+
if (!ft_taper) {
1220+
return t - faketime_offset();
1221+
}
1222+
long long ft_reverse_taper_begin_nsec_since_epoch = ft_taper_begin_nsec_since_epoch;
1223+
long long ft_reverse_taper_end_nsec_since_epoch = ft_taper_end_nsec_since_epoch + faketime_offset();
1224+
if (t <= ft_reverse_taper_begin_nsec_since_epoch) {
1225+
return t;
1226+
}
1227+
if (t >= ft_reverse_taper_end_nsec_since_epoch) {
1228+
return t - faketime_offset();
1229+
}
1230+
long long taper_range = ft_reverse_taper_end_nsec_since_epoch - ft_reverse_taper_begin_nsec_since_epoch;
1231+
long long offset_range = taper_range - faketime_offset();
1232+
// [offset_range] virtual time passes over [taper_range] real time
1233+
long long dt = t - ft_reverse_taper_begin_nsec_since_epoch;
1234+
// so we're looking for dt * offset_range / taper_range, doing
1235+
long long dvt = mult_div_avoid_overflow(dt, offset_range, taper_range);
1236+
// something complicated to avoid overflow.
1237+
long long res = ft_reverse_taper_begin_nsec_since_epoch + dvt;
1238+
return res;
1239+
}
1240+
1241+
void faketime_div_mod(long long ns, long long d, long long *res, long long *rem) {
1242+
*res = ns / d;
1243+
*rem = ns % d;
1244+
if(*rem < 0) {
1245+
(*rem) += d;
1246+
(*res)--;
1247+
}
1248+
}
1249+
1250+
struct timeval faketime_undo_tapered_offset_timeval(struct timeval t) {
1251+
long long nsec = ((long long)t.tv_sec) * 1000000000 + ((long long)t.tv_usec) * 1000;
1252+
nsec = faketime_undo_tapered_offset(nsec);
1253+
long long sec;
1254+
long long nsec_rem;
1255+
faketime_div_mod(nsec, 1000000000, &sec, &nsec_rem);
1256+
t.tv_sec = sec;
1257+
t.tv_usec = nsec_rem / 1000;
1258+
return t;
1259+
}
1260+
1261+
struct timespec faketime_undo_tapered_offset_timespec(struct timespec t) {
1262+
long long nsec = ((long long)t.tv_sec) * 1000000000 + ((long long)t.tv_nsec);
1263+
nsec = faketime_undo_tapered_offset(nsec);
1264+
long long sec;
1265+
long long nsec_rem;
1266+
faketime_div_mod(nsec, 1000000000, &sec, &nsec_rem);
1267+
t.tv_sec = sec;
1268+
t.tv_nsec = nsec_rem;
1269+
return t;
1270+
}
1271+
1272+
1273+
struct timespec faketime_do_tapered_offset_timespec(struct timespec t) {
1274+
long long nsec = ((long long)t.tv_sec) * 1000000000 + ((long long)t.tv_nsec);
1275+
nsec = faketime_do_tapered_offset(nsec);
1276+
long long sec;
1277+
long long nsec_rem;
1278+
faketime_div_mod(nsec, 1000000000, &sec, &nsec_rem);
1279+
t.tv_sec = sec;
1280+
t.tv_nsec = nsec_rem;
1281+
return t;
1282+
}
1283+
1284+
1285+
int faketime_undo_tapered_offset_sec(int t) {
1286+
long long nsec = ((long long)t) * 1000000000;
1287+
nsec = faketime_undo_tapered_offset(nsec);
1288+
return nsec / 1000000000;
1289+
}
1290+
11621291
#ifdef FAKE_FILE_TIMESTAMPS
11631292
#ifdef MACOS_DYLD_INTERPOSE
11641293
int macos_utime(const char *filename, const struct utimbuf *times)
@@ -1184,17 +1313,9 @@ int utime(const char *filename, const struct utimbuf *times)
11841313
ntbuf.actime = times->actime - user_offset.tv_sec;
11851314
ntbuf.modtime = times->modtime - user_offset.tv_sec;
11861315

1187-
long long ac_nsec = ((long long)ntbuf.actime) * 1000000000;
1188-
long long mod_nsec = ((long long)ntbuf.modtime) * 1000000000;
1189-
if (ft_keep_before_nsec_since_epoch != -1 &&
1190-
ac_nsec < ft_keep_before_nsec_since_epoch)
1191-
{
1192-
ntbuf.actime = times->actime;
1193-
}
1194-
if (ft_keep_before_nsec_since_epoch != -1 &&
1195-
mod_nsec < ft_keep_before_nsec_since_epoch)
1196-
{
1197-
ntbuf.modtime = times->modtime;
1316+
if (ft_taper) {
1317+
ntbuf.actime = faketime_undo_tapered_offset_sec(times->actime);
1318+
ntbuf.modtime = faketime_undo_tapered_offset_sec(times->modtime);
11981319
}
11991320

12001321
times = &ntbuf;
@@ -1234,17 +1355,9 @@ int utimes(const char *filename, const struct timeval times[2])
12341355
user_offset2.tv_usec = user_offset.tv_nsec / 1000;
12351356
timersub(&times[0], &user_offset2, &tn[0]);
12361357
timersub(&times[1], &user_offset2, &tn[1]);
1237-
long long tn0_nsec = timernsec(&tn[0], u);
1238-
long long tn1_nsec = timernsec(&tn[1], u);
1239-
if (ft_keep_before_nsec_since_epoch != -1 &&
1240-
tn0_nsec < ft_keep_before_nsec_since_epoch)
1241-
{
1242-
tn[0] = times[0];
1243-
}
1244-
if (ft_keep_before_nsec_since_epoch != -1 &&
1245-
tn1_nsec < ft_keep_before_nsec_since_epoch)
1246-
{
1247-
tn[1] = times[1];
1358+
if (ft_taper) {
1359+
tn[0] = faketime_undo_tapered_offset_timeval(times[0]);
1360+
tn[1] = faketime_undo_tapered_offset_timeval(times[1]);
12481361
}
12491362
times = tn;
12501363
}
@@ -1290,12 +1403,10 @@ static void fake_two_timespec(const struct timespec in_times[2], struct timespec
12901403
else
12911404
{
12921405
timersub2(&in_times[j], &user_offset, &out_times[j], n);
1293-
long long out_nsec = timernsec(&out_times[j], n);
1294-
if (ft_keep_before_nsec_since_epoch != -1 &&
1295-
out_nsec < ft_keep_before_nsec_since_epoch)
1296-
{
1297-
out_times[j] = in_times[j];
1406+
if (ft_taper) {
1407+
out_times[j] = faketime_undo_tapered_offset_timespec(in_times[j]);
12981408
}
1409+
12991410
}
13001411
}
13011412
}
@@ -2932,9 +3043,22 @@ static void ftpl_really_init(void)
29323043
}
29333044
}
29343045

2935-
if ((tmp_env = getenv("FAKETIME_KEEP_BEFORE_NSEC_SINCE_EPOCH")) != NULL)
3046+
if ((tmp_env = getenv("FAKETIME_TAPER_BEGIN_NSEC_SINCE_EPOCH")) != NULL)
29363047
{
2937-
ft_keep_before_nsec_since_epoch = atoll(tmp_env);
3048+
ft_taper_begin_nsec_since_epoch = atoll(tmp_env);
3049+
if(!ft_taper) {
3050+
ft_taper = true;
3051+
ft_taper_end_nsec_since_epoch = ft_taper_begin_nsec_since_epoch;
3052+
}
3053+
limited_faking = true;
3054+
}
3055+
if ((tmp_env = getenv("FAKETIME_TAPER_END_NSEC_SINCE_EPOCH")) != NULL)
3056+
{
3057+
ft_taper_end_nsec_since_epoch = atoll(tmp_env);
3058+
if(!ft_taper) {
3059+
ft_taper = true;
3060+
ft_taper_begin_nsec_since_epoch = ft_taper_end_nsec_since_epoch;
3061+
}
29383062
limited_faking = true;
29393063
}
29403064
if ((tmp_env = getenv("FAKETIME_START_AFTER_SECONDS")) != NULL)
@@ -3262,15 +3386,6 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
32623386
}
32633387
if (limited_faking)
32643388
{
3265-
if (ft_keep_before_nsec_since_epoch != -1)
3266-
{
3267-
long long tp_nsec = ((long long)tp->tv_sec) * 1000000000 + ((long long)tp->tv_nsec);
3268-
if (tp_nsec < ft_keep_before_nsec_since_epoch)
3269-
{
3270-
ret = 0;
3271-
goto abort;
3272-
}
3273-
}
32743389
/* Check whether we actually should be faking the returned timestamp. */
32753390
/* fprintf(stderr, "(libfaketime limits -> runtime: %lu, callcounter: %lu\n", (*time_tptr - ftpl_starttime), callcounter); */
32763391
if (((ft_start_after_secs != -1) && (tmp_ts.tv_sec < ft_start_after_secs))
@@ -3421,7 +3536,13 @@ int fake_clock_gettime(clockid_t clk_id, struct timespec *tp)
34213536
{
34223537
timeadj = tdiff;
34233538
}
3424-
timespecadd(&user_faked_time_timespec, &timeadj, tp);
3539+
3540+
if(ft_taper) {
3541+
*tp = faketime_do_tapered_offset_timespec(*tp);
3542+
}
3543+
else {
3544+
timespecadd(&user_faked_time_timespec, &timeadj, tp);
3545+
}
34253546
}
34263547
break;
34273548

0 commit comments

Comments
 (0)