Skip to content

Commit 1231a00

Browse files
authored
Merge pull request #522 from rbalint/fake-syscall-clock-nanosleep
Fake the clock_nanosleep syscall
2 parents 949b36e + 3109728 commit 1231a00

File tree

3 files changed

+116
-0
lines changed

3 files changed

+116
-0
lines changed

src/libfaketime.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4485,6 +4485,8 @@ long syscall(long number, ...) {
44854485
}
44864486
#endif
44874487
// static int (*real_clock_gettime) (clockid_t clk_id, struct timespec *tp);
4488+
/* Intercept clock_gettime syscall if available */
4489+
#ifdef __NR_clock_gettime
44884490
if (number == __NR_clock_gettime && (getenv("FAKETIME") || getenv("FAKETIME_TIMESTAMP_FILE"))) {
44894491
clockid_t clk_id;
44904492
struct timespec *tp;
@@ -4493,6 +4495,87 @@ long syscall(long number, ...) {
44934495
va_end(ap);
44944496
return clock_gettime(clk_id, tp);
44954497
}
4498+
#endif
4499+
4500+
#ifdef FAKE_SLEEP
4501+
#ifdef __NR_clock_nanosleep
4502+
/* Intercept raw clock_nanosleep syscall */
4503+
if (number == __NR_clock_nanosleep && (getenv("FAKETIME") || getenv("FAKETIME_TIMESTAMP_FILE")))
4504+
{
4505+
clockid_t clk_id;
4506+
int flags;
4507+
const struct timespec *req;
4508+
struct timespec *rem;
4509+
4510+
clk_id = va_arg(ap, clockid_t);
4511+
flags = va_arg(ap, int);
4512+
req = va_arg(ap, const struct timespec*);
4513+
rem = va_arg(ap, struct timespec*);
4514+
va_end(ap);
4515+
4516+
if (req == NULL)
4517+
{
4518+
/* Pass through invalid input to maintain behavior */
4519+
return real_syscall(number, clk_id, flags, req, rem);
4520+
}
4521+
4522+
struct timespec real_req;
4523+
4524+
if (flags & TIMER_ABSTIME)
4525+
{
4526+
/* Sleep until absolute fake time 'req': convert to corresponding real abstime */
4527+
struct timespec tdiff, timeadj;
4528+
/* time difference between target fake abstime and fake base */
4529+
timespecsub(req, &user_faked_time_timespec, &timeadj);
4530+
if (user_rate_set) {
4531+
timespecmul(&timeadj, 1.0 / user_rate, &tdiff);
4532+
} else {
4533+
tdiff = timeadj;
4534+
}
4535+
4536+
if (clk_id == CLOCK_REALTIME)
4537+
{
4538+
timespecadd(&ftpl_starttime.real, &tdiff, &real_req);
4539+
} else if (clk_id == CLOCK_MONOTONIC)
4540+
{
4541+
get_fake_monotonic_setting(&fake_monotonic_clock);
4542+
if (fake_monotonic_clock) {
4543+
timespecadd(&ftpl_starttime.mon, &tdiff, &real_req);
4544+
} else {
4545+
/* leave untouched if monotonic faking disabled */
4546+
real_req = *req;
4547+
}
4548+
} else {
4549+
/* other clocks: leave untouched */
4550+
real_req = *req;
4551+
}
4552+
} else
4553+
{
4554+
/* Relative sleep: scale by 1/rate for realtime/monotonic when faking */
4555+
if (user_rate_set && !dont_fake && ((clk_id == CLOCK_REALTIME) || (clk_id == CLOCK_MONOTONIC)))
4556+
{
4557+
timespecmul(req, 1.0 / user_rate, &real_req);
4558+
} else {
4559+
real_req = *req;
4560+
}
4561+
}
4562+
4563+
long rc = real_syscall(number, clk_id, flags, &real_req, rem);
4564+
if (rc != 0)
4565+
{
4566+
return rc;
4567+
}
4568+
if (rem != NULL && (rem->tv_sec != 0 || rem->tv_nsec != 0))
4569+
{
4570+
if (user_rate_set && !dont_fake)
4571+
{
4572+
timespecmul(rem, user_rate, rem);
4573+
}
4574+
}
4575+
return rc;
4576+
}
4577+
#endif /* __NR_clock_nanosleep */
4578+
#endif /* FAKE_SLEEP */
44964579

44974580
#ifdef INTERCEPT_FUTEX
44984581
if (number == __NR_futex) {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* Test raw syscall(__NR_clock_nanosleep): relative and TIMER_ABSTIME */
2+
#ifdef __NR_clock_nanosleep
3+
struct timespec start_fake, end_fake_rel, end_fake_abs;
4+
struct timespec req_rel = {0, 200 * 1000 * 1000}; /* 200ms fake sleep */
5+
struct timespec req_abs;
6+
long ret;
7+
8+
/* Capture starting time (fake view) */
9+
clock_gettime(CLOCK_REALTIME, &start_fake);
10+
11+
/* Relative sleep via syscall */
12+
ret = syscall(__NR_clock_nanosleep, CLOCK_REALTIME, 0, &req_rel, NULL);
13+
clock_gettime(CLOCK_REALTIME, &end_fake_rel);
14+
15+
/* Absolute sleep target: 300ms after start_fake *./test_variable_data.sh */
16+
req_abs.tv_sec = start_fake.tv_sec;
17+
req_abs.tv_nsec = start_fake.tv_nsec + 300 * 1000 * 1000;
18+
if (req_abs.tv_nsec >= 1000000000) { req_abs.tv_sec += 1; req_abs.tv_nsec -= 1000000000; }
19+
20+
/* Absolute sleep via syscall */
21+
ret = syscall(__NR_clock_nanosleep, CLOCK_REALTIME, TIMER_ABSTIME, &req_abs, NULL);
22+
clock_gettime(CLOCK_REALTIME, &end_fake_abs);
23+
24+
/* Report durations (fake view). */
25+
long rel_ns = (end_fake_rel.tv_sec - start_fake.tv_sec) * 1000000000L + (end_fake_rel.tv_nsec - start_fake.tv_nsec);
26+
long abs_ns = (end_fake_abs.tv_sec - start_fake.tv_sec) * 1000000000L + (end_fake_abs.tv_nsec - start_fake.tv_nsec);
27+
printf("[%s] syscall(clock_nanosleep) relative 200ms -> ~%ld ns, absolute +300ms -> ~%ld ns\n", where, rel_ns, abs_ns);
28+
return ret;
29+
#else
30+
printf("[%s] __NR_clock_nanosleep not defined on this platform\n", where);
31+
#endif
32+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FAKETIME 2020-01-01 00:00:00

0 commit comments

Comments
 (0)