diff --git a/src/Makefile b/src/Makefile index eb58ef5..d40c90b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -49,13 +49,24 @@ # # INTERCEPT_SYSCALL # - (On GNU/Linux only) intercept glibc's syscall() for known relevant syscalls. -# If enabled, this currently only works to divert the getrandom syscall. +# If enabled, this currently only works a few types of syscalls, +# including FUTEX (see below), clock_gettime, etc. # # - note that on unusual architectures, if INTERCEPT_SYSCALL is set, you may # need to explicitly define variadic_promotion_t (e.g. by putting # -Dvariadic_promotion_t=int into CFLAGS). See src/faketime_common.h for # more info. # +# INTERCEPT_FUTEX +# - (On GNU/Linux only) intercept glibc's syscall() for relevant FUTEX syscalls. +# If enabled, FUTEX syscalls will be intercepted and translated correspondingly. +# - when FUTEX_WAIT_BITSET (with absolute deadline) is set, the deadline will +# be adjusted based on the faketime. +# - when FUTEX_WAKE (with relative deadline) is set, the deadline will be +# adjusted based on the time rate alone. +# - for other FUTEX operations, no adjustment is made for now. +# +# # FAKE_STATELESS # - Remove support for any functionality that requires sharing state across # threads of a process, or different processes. This decreases the risk of diff --git a/src/libfaketime.c b/src/libfaketime.c index b88c46f..50c5e62 100644 --- a/src/libfaketime.c +++ b/src/libfaketime.c @@ -4445,12 +4445,13 @@ long handle_futex_syscall(long number, uint32_t* uaddr, int futex_op, uint32_t v goto futex_fallback; } - // if ((futex_op & FUTEX_CMD_MASK) == FUTEX_WAIT_BITSET) { - if (1) { - clockid_t clk_id = CLOCK_MONOTONIC; - if (futex_op & FUTEX_CLOCK_REALTIME) - clk_id = CLOCK_REALTIME; + int futex_cmd = futex_op & FUTEX_CMD_MASK; + clockid_t clk_id = CLOCK_MONOTONIC; + if (futex_op & FUTEX_CLOCK_REALTIME) + clk_id = CLOCK_REALTIME; + if (futex_cmd == FUTEX_WAIT_BITSET) { + // FUTEX_WAIT_BITSET uses absolute timeout struct timespec real_tp, fake_tp; DONT_FAKE_TIME((*real_clock_gettime)(clk_id, &real_tp)); @@ -4513,8 +4514,20 @@ long handle_futex_syscall(long number, uint32_t* uaddr, int futex_op, uint32_t v } } return 0; + } else if (futex_cmd == FUTEX_WAIT) { + // FUTEX_WAIT uses relative timeout - scale by time rate + struct timespec adjusted_timeout; + + if (user_rate_set && !dont_fake && ((clk_id == CLOCK_REALTIME) || (clk_id == CLOCK_MONOTONIC))) { + timespecmul(timeout, 1.0 / user_rate, &adjusted_timeout); + } else { + adjusted_timeout = *timeout; + } + + return real_syscall(number, uaddr, futex_op, val, &adjusted_timeout, uaddr2, val3); } else { - return real_syscall(number, uaddr, futex_op, val, timeout, uaddr2, val3); + // Other futex operations - pass through unchanged + goto futex_fallback; } futex_fallback: