2011-04-24 19:55:43 +02:00
/*
* Copyright ( C ) 2003 , 2007 Wolfgang Hommel
*
* This file is part of the FakeTime Preload Library .
*
2012-08-26 22:34:39 +03:00
* The FakeTime Preload Library is free software ; you can redistribute it
* and / or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of the
2011-04-24 19:55:43 +02:00
* License , or ( at your option ) any later version .
*
2012-08-26 22:34:39 +03:00
* The FakeTime Preload Library is distributed in the hope that it will
* be useful , but WITHOUT ANY WARRANTY ; without even the implied warranty
2011-04-24 19:55:43 +02:00
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with the FakeTime Preload Library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2017-12-31 02:23:56 +01:00
# define _GNU_SOURCE
2026-03-27 16:09:02 -03:00
# include <fcntl.h>
2011-04-24 19:55:43 +02:00
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
2011-04-27 19:47:34 +02:00
# include <sys/time.h>
2011-04-24 19:55:43 +02:00
# include <sys/timeb.h>
2019-08-21 18:42:05 +02:00
# ifndef __APPLE__
2011-04-24 19:55:43 +02:00
# ifdef FAKE_STAT
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
# endif
2019-08-21 18:42:05 +02:00
# else
# include <unistd.h>
# endif
2011-04-24 19:55:43 +02:00
2013-09-30 16:36:13 +02:00
# ifndef __APPLE__
2017-12-31 02:23:56 +01:00
# include <pthread.h>
# include <errno.h>
2013-09-30 16:36:13 +02:00
# include <signal.h>
2025-06-13 17:06:33 -04:00
# include <string.h>
2026-03-30 09:56:22 -03:00
# include <utime.h>
2025-06-13 17:06:33 -04:00
# define MONO_FIX_TIMEOUT_SECONDS 1
# define MONO_FIX_TOLERANCE_SECONDS 0.25 // Increased tolerance slightly for CI environments
# define MONO_FIX_LOWER_BOUND (MONO_FIX_TIMEOUT_SECONDS - MONO_FIX_TOLERANCE_SECONDS)
# define MONO_FIX_UPPER_BOUND (MONO_FIX_TIMEOUT_SECONDS + MONO_FIX_TOLERANCE_SECONDS)
2013-09-30 16:36:13 +02:00
2013-10-01 13:12:34 +02:00
# define VERBOSE 0
2013-10-20 17:28:25 +02:00
# define SIG SIGUSR1
2025-06-13 17:06:33 -04:00
# ifdef __ARM_ARCH
static int fake_monotonic_clock = 0 ;
# else
static int fake_monotonic_clock = 1 ;
# endif
2026-03-30 09:56:22 -03:00
static void test_utime_now ( void )
{
char path [ ] = " /tmp/libfaketime-utime-XXXXXX " ;
int fd ;
fd = mkstemp ( path ) ;
if ( fd = = - 1 )
{
perror ( " mkstemp " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( utime ( path , NULL ) = = - 1 )
{
perror ( " utime(NULL) " ) ;
close ( fd ) ;
unlink ( path ) ;
exit ( EXIT_FAILURE ) ;
}
if ( utimes ( path , NULL ) = = - 1 )
{
perror ( " utimes(NULL) " ) ;
close ( fd ) ;
unlink ( path ) ;
exit ( EXIT_FAILURE ) ;
}
if ( close ( fd ) = = - 1 )
{
perror ( " close " ) ;
unlink ( path ) ;
exit ( EXIT_FAILURE ) ;
}
if ( unlink ( path ) = = - 1 )
{
perror ( " unlink " ) ;
exit ( EXIT_FAILURE ) ;
}
printf ( " utime()/utimes(): NOW handling passed \n " ) ;
}
2026-03-27 16:09:02 -03:00
static void test_utimens_now ( void )
{
char path [ ] = " /tmp/libfaketime-utimensat-XXXXXX " ;
struct timespec now_times [ 2 ] ;
int fd ;
fd = mkstemp ( path ) ;
if ( fd = = - 1 )
{
perror ( " mkstemp " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( utimensat ( AT_FDCWD , path , NULL , 0 ) = = - 1 )
{
perror ( " utimensat(NULL) " ) ;
unlink ( path ) ;
exit ( EXIT_FAILURE ) ;
}
if ( futimens ( fd , NULL ) = = - 1 )
{
perror ( " futimens(NULL) " ) ;
close ( fd ) ;
unlink ( path ) ;
exit ( EXIT_FAILURE ) ;
}
now_times [ 0 ] . tv_sec = now_times [ 1 ] . tv_sec = 0 ;
now_times [ 0 ] . tv_nsec = now_times [ 1 ] . tv_nsec = UTIME_NOW ;
if ( utimensat ( AT_FDCWD , path , now_times , 0 ) = = - 1 )
{
perror ( " utimensat(UTIME_NOW) " ) ;
close ( fd ) ;
unlink ( path ) ;
exit ( EXIT_FAILURE ) ;
}
if ( futimens ( fd , now_times ) = = - 1 )
{
perror ( " futimens(UTIME_NOW) " ) ;
close ( fd ) ;
unlink ( path ) ;
exit ( EXIT_FAILURE ) ;
}
if ( close ( fd ) = = - 1 )
{
perror ( " close " ) ;
unlink ( path ) ;
exit ( EXIT_FAILURE ) ;
}
if ( unlink ( path ) = = - 1 )
{
perror ( " unlink " ) ;
exit ( EXIT_FAILURE ) ;
}
printf ( " utimensat()/futimens(): NOW handling passed \n " ) ;
}
2013-09-30 16:36:13 +02:00
static void
handler ( int sig , siginfo_t * si , void * uc )
{
/* Note: calling printf() from a signal handler is not
strictly correct , since printf ( ) is not async - signal - safe ;
see signal ( 7 ) */
2013-10-06 13:12:39 +02:00
if ( ( si = = NULL ) | | ( si ! = uc ) )
{
printf ( " Caught signal %d \n " , sig ) ;
}
2013-09-30 16:36:13 +02:00
}
2017-12-31 02:23:56 +01:00
2025-06-13 17:06:33 -04:00
static void get_fake_monotonic_setting ( int * current_value )
{
char * tmp_env ;
if ( ( tmp_env = getenv ( " FAKETIME_DONT_FAKE_MONOTONIC " ) ) ! = NULL
| | ( tmp_env = getenv ( " DONT_FAKE_MONOTONIC " ) ) ! = NULL )
{
if ( 0 = = strcmp ( tmp_env , " 1 " ) )
{
( * current_value ) = 0 ;
}
else
{
( * current_value ) = 1 ;
}
}
}
2017-12-31 02:23:56 +01:00
void * pthread_test ( void * args )
{
2025-06-13 17:06:33 -04:00
pthread_mutex_t fake_mtx = PTHREAD_MUTEX_INITIALIZER ;
pthread_cond_t fake_cond = PTHREAD_COND_INITIALIZER ;
2017-12-31 02:23:56 +01:00
pthread_cond_t monotonic_cond ;
pthread_condattr_t attr ;
2025-06-13 17:06:33 -04:00
struct timespec time_to_wait , now ;
2017-12-31 02:23:56 +01:00
int rt ;
args = args ; // silence compiler warning about unused argument
clock_gettime ( CLOCK_REALTIME , & now ) ;
2025-06-13 17:06:33 -04:00
time_to_wait . tv_sec = now . tv_sec + 1 ;
time_to_wait . tv_nsec = now . tv_nsec ;
2017-12-31 02:23:56 +01:00
printf ( " pthread_cond_timedwait: CLOCK_REALTIME test \n " ) ;
printf ( " (Intentionally sleeping 1 second...) \n " ) ;
fflush ( stdout ) ;
2025-06-13 17:06:33 -04:00
pthread_mutex_lock ( & fake_mtx ) ;
rt = pthread_cond_timedwait ( & fake_cond , & fake_mtx , & time_to_wait ) ;
2017-12-31 02:23:56 +01:00
if ( rt ! = ETIMEDOUT )
{
printf ( " pthread_cond_timedwait failed \n " ) ;
2025-06-13 17:06:33 -04:00
pthread_mutex_unlock ( & fake_mtx ) ;
2017-12-31 02:23:56 +01:00
exit ( EXIT_FAILURE ) ;
}
2025-06-13 17:06:33 -04:00
pthread_mutex_unlock ( & fake_mtx ) ;
2017-12-31 02:23:56 +01:00
pthread_condattr_init ( & attr ) ;
pthread_condattr_setclock ( & attr , CLOCK_MONOTONIC ) ;
pthread_cond_init ( & monotonic_cond , & attr ) ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
2025-06-13 17:06:33 -04:00
time_to_wait . tv_sec = now . tv_sec + 1 ;
time_to_wait . tv_nsec = now . tv_nsec ;
2017-12-31 02:23:56 +01:00
printf ( " pthread_cond_timedwait: CLOCK_MONOTONIC test \n " ) ;
2022-02-25 21:36:38 +01:00
printf ( " (Intentionally sleeping 1 second...) \n " ) ;
printf ( " (If this test hangs for more than a few seconds, please report \n your glibc version and system details as FORCE_MONOTONIC_FIX \n issue at https://github.com/wolfcw/libfaketime) \n " ) ;
2017-12-31 02:23:56 +01:00
fflush ( stdout ) ;
2025-06-13 17:06:33 -04:00
pthread_mutex_lock ( & fake_mtx ) ;
rt = pthread_cond_timedwait ( & monotonic_cond , & fake_mtx , & time_to_wait ) ;
2017-12-31 02:23:56 +01:00
if ( rt ! = ETIMEDOUT )
{
printf ( " pthread_cond_timedwait failed \n " ) ;
2025-06-13 17:06:33 -04:00
pthread_mutex_unlock ( & fake_mtx ) ;
2017-12-31 02:23:56 +01:00
exit ( EXIT_FAILURE ) ;
}
2025-06-13 17:06:33 -04:00
pthread_mutex_unlock ( & fake_mtx ) ;
get_fake_monotonic_setting ( & fake_monotonic_clock ) ;
if ( ! fake_monotonic_clock )
{
printf ( " pthread_cond_timedwait: using real CLOCK_MONOTONIC test \n " ) ;
struct timespec mono_after_wait ;
2017-12-31 02:23:56 +01:00
2025-06-13 17:06:33 -04:00
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
time_to_wait . tv_sec = now . tv_sec + MONO_FIX_TIMEOUT_SECONDS ;
time_to_wait . tv_nsec = now . tv_nsec ;
struct timespec current_real_time ;
clock_gettime ( CLOCK_REALTIME , & current_real_time ) ;
struct timespec new_real_time = current_real_time ;
new_real_time . tv_sec + = 3600 ; // Advance by one hour
clock_settime ( CLOCK_REALTIME , & new_real_time ) ;
pthread_mutex_lock ( & fake_mtx ) ;
rt = pthread_cond_timedwait ( & monotonic_cond , & fake_mtx , & time_to_wait ) ;
clock_gettime ( CLOCK_MONOTONIC , & mono_after_wait ) ;
pthread_mutex_unlock ( & fake_mtx ) ;
double elapsed_wall_time = ( mono_after_wait . tv_sec - now . tv_sec ) +
( mono_after_wait . tv_nsec - now . tv_nsec ) / 1000000000.0 ;
if ( rt = = ETIMEDOUT & & ( elapsed_wall_time > = MONO_FIX_LOWER_BOUND & & elapsed_wall_time < = MONO_FIX_UPPER_BOUND ) )
{
printf ( " pthread_cond_timedwait with real CLOCK_MONOTONIC passed: elapsed time = %.2f seconds \n " , elapsed_wall_time ) ;
}
else
{
printf ( " pthread_cond_timedwait with real CLOCK_MONOTONIC FAILED: elapsed time = %.2f seconds, return code = %d \n " , elapsed_wall_time , rt ) ;
exit ( EXIT_FAILURE ) ;
}
}
2017-12-31 02:23:56 +01:00
pthread_cond_destroy ( & monotonic_cond ) ;
return NULL ;
}
2013-09-30 16:36:13 +02:00
# endif
2011-04-24 19:55:43 +02:00
2013-11-07 19:35:18 +01:00
int main ( int argc , char * * argv )
{
2011-04-24 19:55:43 +02:00
time_t now ;
struct timeb tb ;
struct timeval tv ;
2011-07-30 10:58:12 +02:00
# ifndef __APPLE__
2011-04-24 19:55:43 +02:00
struct timespec ts ;
2013-09-30 16:36:13 +02:00
timer_t timerid1 = 0 , timerid2 ;
struct sigevent sev ;
struct itimerspec its ;
sigset_t mask ;
struct sigaction sa ;
2011-07-30 10:58:12 +02:00
# endif
2019-08-21 18:42:05 +02:00
# ifndef __APPLE__
2011-04-24 19:55:43 +02:00
# ifdef FAKE_STAT
struct stat buf ;
# endif
2019-08-21 18:42:05 +02:00
# endif
/* silence compiler warnings */
printf ( " %s " , 0 = = 1 ? argv [ 0 ] : " " ) ;
2011-04-24 19:55:43 +02:00
2013-09-30 16:36:13 +02:00
# ifndef __APPLE__
2017-12-31 02:23:56 +01:00
pthread_t thread ;
void * ret ;
pthread_create ( & thread , NULL , pthread_test , NULL ) ;
pthread_join ( thread , & ret ) ;
2013-09-30 16:36:13 +02:00
sa . sa_flags = SA_SIGINFO ;
sa . sa_sigaction = handler ;
sigemptyset ( & sa . sa_mask ) ;
2013-11-07 19:35:18 +01:00
if ( sigaction ( SIGUSR1 , & sa , NULL ) = = - 1 )
{
2013-09-30 16:36:13 +02:00
perror ( " sigaction " ) ;
exit ( EXIT_FAILURE ) ;
}
2013-11-07 19:35:18 +01:00
/* Block timer signal temporarily */
2013-10-20 17:28:25 +02:00
printf ( " Blocking signal %d \n " , SIGUSR1 ) ;
2013-09-30 16:36:13 +02:00
sigemptyset ( & mask ) ;
2013-10-20 17:28:25 +02:00
sigaddset ( & mask , SIGUSR1 ) ;
2013-11-07 19:35:18 +01:00
if ( sigprocmask ( SIG_SETMASK , & mask , NULL ) = = - 1 )
{
2013-09-30 16:36:13 +02:00
perror ( " sigaction " ) ;
exit ( EXIT_FAILURE ) ;
2013-11-07 19:35:18 +01:00
}
2013-09-30 16:36:13 +02:00
/* Create the timer */
sev . sigev_notify = SIGEV_SIGNAL ;
2013-10-20 17:28:25 +02:00
sev . sigev_signo = SIGUSR1 ;
2013-09-30 16:36:13 +02:00
sev . sigev_value . sival_ptr = & timerid1 ;
2013-11-07 19:35:18 +01:00
if ( timer_create ( CLOCK_REALTIME , & sev , & timerid1 ) = = - 1 )
{
2013-09-30 16:36:13 +02:00
perror ( " timer_create " ) ;
exit ( EXIT_FAILURE ) ;
}
/* Start timer1 */
/* start timer ticking after one second */
its . it_value . tv_sec = 1 ;
its . it_value . tv_nsec = 0 ;
/* fire in every 0.3 seconds */
its . it_interval . tv_sec = 0 ;
its . it_interval . tv_nsec = 300000000 ;
2013-11-07 19:35:18 +01:00
if ( timer_settime ( timerid1 , 0 , & its , NULL ) = = - 1 )
{
2013-09-30 16:36:13 +02:00
perror ( " timer_settime " ) ;
exit ( EXIT_FAILURE ) ;
}
sev . sigev_value . sival_ptr = & timerid2 ;
2013-11-07 19:35:18 +01:00
if ( timer_create ( CLOCK_REALTIME , & sev , & timerid2 ) = = - 1 )
{
2013-09-30 16:36:13 +02:00
perror ( " timer_create " ) ;
exit ( EXIT_FAILURE ) ;
}
/* Start timer2 */
clock_gettime ( CLOCK_REALTIME , & its . it_value ) ;
/* start timer ticking after one second */
its . it_value . tv_sec + = 3 ;
/* fire once */
its . it_interval . tv_sec = 0 ;
its . it_interval . tv_nsec = 0 ;
2013-11-07 19:35:18 +01:00
if ( timer_settime ( timerid2 , TIMER_ABSTIME , & its , NULL ) = = - 1 )
{
2013-09-30 16:36:13 +02:00
perror ( " timer_settime " ) ;
exit ( EXIT_FAILURE ) ;
}
# endif
2011-04-24 19:55:43 +02:00
time ( & now ) ;
printf ( " time() : Current date and time: %s " , ctime ( & now ) ) ;
2011-04-27 19:51:05 +02:00
printf ( " time(NULL) : Seconds since Epoch : %u \n " , ( unsigned int ) time ( NULL ) ) ;
2011-04-24 19:55:43 +02:00
2020-05-28 23:09:07 +02:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
2011-04-24 19:55:43 +02:00
ftime ( & tb ) ;
2020-05-28 23:09:07 +02:00
# pragma GCC diagnostic pop
2011-04-24 19:55:43 +02:00
printf ( " ftime() : Current date and time: %s " , ctime ( & tb . time ) ) ;
printf ( " (Intentionally sleeping 2 seconds...) \n " ) ;
fflush ( stdout ) ;
2013-10-06 13:12:39 +02:00
if ( argc < 3 )
{
sleep ( 1 ) ;
usleep ( 1000000 ) ;
}
2011-04-24 19:55:43 +02:00
gettimeofday ( & tv , NULL ) ;
printf ( " gettimeofday() : Current date and time: %s " , ctime ( & tv . tv_sec ) ) ;
2011-07-30 10:58:12 +02:00
# ifndef __APPLE__
2026-03-30 09:56:22 -03:00
test_utime_now ( ) ;
2026-03-27 16:09:02 -03:00
test_utimens_now ( ) ;
2013-11-07 19:35:18 +01:00
if ( sigprocmask ( SIG_UNBLOCK , & mask , NULL ) = = - 1 )
{
2013-09-30 16:36:13 +02:00
perror ( " sigprocmask " ) ;
exit ( EXIT_FAILURE ) ;
}
2011-04-24 19:55:43 +02:00
clock_gettime ( CLOCK_REALTIME , & ts ) ;
printf ( " clock_gettime(): Current date and time: %s " , ctime ( & ts . tv_sec ) ) ;
2013-09-30 16:36:13 +02:00
2013-10-01 13:12:34 +02:00
int timer_getoverrun_timerid1 = timer_getoverrun ( timerid1 ) ;
2013-11-07 19:35:18 +01:00
if ( timer_getoverrun_timerid1 ! = 3 )
{
2021-02-12 16:59:42 +01:00
# ifdef __GNU__
printf ( " (Timer overruns are assumed to be fine on Hurd) \n " ) ;
# else
2013-10-01 13:12:34 +02:00
printf ( " timer_getoverrun(timerid1) FAILED, must be 3 but got: %d \n " , timer_getoverrun_timerid1 ) ;
2021-02-12 16:59:42 +01:00
# endif
2013-10-01 13:12:34 +02:00
}
2013-09-30 16:36:13 +02:00
timer_gettime ( timerid1 , & its ) ;
2013-11-07 19:35:18 +01:00
if ( VERBOSE = = 1 )
{
2013-10-01 13:12:34 +02:00
printf ( " timer_gettime(timerid1, &its); its = {{%ld, %ld}, {%ld, %ld}}} \n " ,
2015-03-09 08:39:06 +01:00
( long ) its . it_interval . tv_sec , ( long ) its . it_interval . tv_nsec ,
( long ) its . it_value . tv_sec , ( long ) its . it_value . tv_nsec ) ;
2013-10-01 13:12:34 +02:00
}
int timer_getoverrun_timerid2 = timer_getoverrun ( timerid2 ) ;
2013-11-07 19:35:18 +01:00
if ( timer_getoverrun_timerid2 ! = 0 )
{
2013-10-01 13:12:34 +02:00
printf ( " timer_getoverrun(timerid2) FAILED, must be 0 but got: %d \n " , timer_getoverrun_timerid2 ) ;
}
2013-09-30 16:36:13 +02:00
timer_gettime ( timerid2 , & its ) ;
2013-11-07 19:35:18 +01:00
if ( VERBOSE = = 1 )
{
2013-10-01 13:12:34 +02:00
printf ( " timer_gettime(timerid2, &its); its = {{%ld, %ld}, {%ld, %ld}}} \n " ,
2015-03-09 08:39:06 +01:00
( long ) its . it_interval . tv_sec , ( long ) its . it_interval . tv_nsec ,
( long ) its . it_value . tv_sec , ( long ) its . it_value . tv_nsec ) ;
2013-10-01 13:12:34 +02:00
}
2011-07-30 10:58:12 +02:00
# endif
2011-04-24 19:55:43 +02:00
2019-08-21 18:42:05 +02:00
# ifndef __APPLE__
2011-04-24 19:55:43 +02:00
# ifdef FAKE_STAT
lstat ( argv [ 0 ] , & buf ) ;
printf ( " stat(): mod. time of file '%s': %s " , argv [ 0 ] , ctime ( & buf . st_mtime ) ) ;
2019-08-21 18:42:05 +02:00
# endif
2011-04-24 19:55:43 +02:00
# endif
return 0 ;
}
2013-11-07 19:35:18 +01:00
/*
* Editor modelines
*
* Local variables :
* c - basic - offset : 2
* tab - width : 2
* indent - tabs - mode : nil
* End :
*
* vi : set shiftwidth = 2 tabstop = 2 expandtab :
* : indentSize = 2 : tabSize = 2 : noTabs = true :
*/
/* eof */