@@ -4186,6 +4186,90 @@ pid_t getpid() {
41864186#endif
41874187
41884188#ifdef INTERCEPT_SYSCALL
4189+ #ifdef INTERCEPT_FUTEX
4190+ long handle_futex_syscall (long number , uint32_t * uaddr , int futex_op , uint32_t val , struct timespec * timeout , uint32_t * uaddr2 , uint32_t val3 ) {
4191+ if (timeout == NULL ) {
4192+ // not timeout related, just call the real syscall
4193+ goto futex_fallback ;
4194+ }
4195+
4196+ // if ((futex_op & FUTEX_CMD_MASK) == FUTEX_WAIT_BITSET) {
4197+ if (1 ) {
4198+ clockid_t clk_id = CLOCK_MONOTONIC ;
4199+ if (futex_op & FUTEX_CLOCK_REALTIME )
4200+ clk_id = CLOCK_REALTIME ;
4201+
4202+ struct timespec real_tp , fake_tp ;
4203+
4204+ DONT_FAKE_TIME ((* real_clock_gettime )(clk_id , & real_tp ));
4205+ fake_tp = real_tp ;
4206+ if (fake_clock_gettime (clk_id , & fake_tp ) == -1 ) {
4207+ goto futex_fallback ;
4208+ }
4209+ // Create a corrected timeout by adjusting with the difference between
4210+ // real and fake timestamps
4211+ struct timespec adjusted_timeout , time_diff ;
4212+ timespecsub (& fake_tp , & real_tp , & time_diff );
4213+ timespecsub (timeout , & time_diff , & adjusted_timeout );
4214+ // fprintf(stdout, "libfaketime: adjusted timeout: %ld.%09ld\n", adjusted_timeout.tv_sec, adjusted_timeout.tv_nsec);
4215+ long result ;
4216+ result = real_syscall (number , uaddr , futex_op , val , & adjusted_timeout , uaddr2 , val3 );
4217+ if (result != 0 ) {
4218+ return result ;
4219+ }
4220+
4221+ // Check if the futex timeout has already passed according to fake time
4222+ struct timespec now_fake ;
4223+ if (fake_clock_gettime (clk_id , & now_fake ) != 0 ) {
4224+ return result ;
4225+ }
4226+
4227+ // If the timeout is already passed in fake time, return 0.
4228+ while (!timespeccmp (& now_fake , timeout , >=)) {
4229+ // Calculate how much real time we need to wait
4230+ struct timespec real_now , fake_now , wait_time ;
4231+ DONT_FAKE_TIME ((* real_clock_gettime )(clk_id , & real_now ));
4232+ fake_clock_gettime (clk_id , & fake_now );
4233+
4234+ // Calculate how much fake time is left until the timeout
4235+ struct timespec fake_time_left ;
4236+ timespecsub (timeout , & fake_now , & fake_time_left );
4237+
4238+ // Scale the fake time left by the user rate if set
4239+ if (user_rate_set && !dont_fake ) {
4240+ timespecmul (& fake_time_left , 1.0 / user_rate , & wait_time );
4241+ } else {
4242+ wait_time = fake_time_left ;
4243+ }
4244+
4245+ // Calculate the real timeout by adding the wait time to the current real time
4246+ struct timespec real_timeout ;
4247+ timespecadd (& real_now , & wait_time , & real_timeout );
4248+
4249+ // fprintf(stdout, "libfaketime: recalculated real timeout: %ld.%09ld\n",
4250+ // real_timeout.tv_sec, real_timeout.tv_nsec);
4251+
4252+ // Call the real syscall with the recalculated timeout
4253+ result = real_syscall (number , uaddr , futex_op , val , & real_timeout , uaddr2 , val3 );
4254+ if (result != 0 ) {
4255+ return result ;
4256+ }
4257+
4258+ // Check if the futex timeout has already passed according to fake time
4259+ if (fake_clock_gettime (clk_id , & now_fake ) != 0 ) {
4260+ return result ;
4261+ }
4262+ }
4263+ return 0 ;
4264+ } else {
4265+ return real_syscall (number , uaddr , futex_op , val , timeout , uaddr2 , val3 );
4266+ }
4267+
4268+ futex_fallback :
4269+ return real_syscall (number , uaddr , futex_op , val , timeout , uaddr2 , val3 );
4270+ }
4271+ #endif
4272+
41894273/* see https://github.com/wolfcw/libfaketime/issues/301 */
41904274long syscall (long number , ...) {
41914275 va_list ap ;
@@ -4211,6 +4295,27 @@ long syscall(long number, ...) {
42114295 va_end (ap );
42124296 return clock_gettime (clk_id , tp );
42134297 }
4298+
4299+ #ifdef INTERCEPT_FUTEX
4300+ if (number == __NR_futex ) {
4301+ uint32_t * uaddr ;
4302+ int futex_op ;
4303+ uint32_t val ;
4304+ struct timespec * timeout ; /* or: uint32_t val2 */
4305+ uint32_t * uaddr2 ;
4306+ uint32_t val3 ;
4307+
4308+ uaddr = va_arg (ap , uint32_t * );
4309+ futex_op = va_arg (ap , int );
4310+ val = va_arg (ap , uint32_t );
4311+ timeout = va_arg (ap , struct timespec * );
4312+ uaddr2 = va_arg (ap , uint32_t * );
4313+ val3 = va_arg (ap , uint32_t );
4314+ va_end (ap );
4315+
4316+ return handle_futex_syscall (number , uaddr , futex_op , val , timeout , uaddr2 , val3 );
4317+ }
4318+ #endif
42144319
42154320 variadic_promotion_t a [syscall_max_args ];
42164321 for (int i = 0 ; i < syscall_max_args ; i ++ )
0 commit comments