diff options
author | Wolfgang Hommel <wolfgang.hommel@lrz.de> | 2013-10-02 15:36:07 +0200 |
---|---|---|
committer | Wolfgang Hommel <wolfgang.hommel@lrz.de> | 2013-10-02 15:36:07 +0200 |
commit | 338ec2e3df1c6ec6058a93c4288a3fbba7ba0dcb (patch) | |
tree | 2f9d78d29f098761b9dd87b5efe8fa14e1e0786a | |
parent | cda19e4cb767a6c2bdde03c1502e3a9acec59078 (diff) | |
parent | bb87fb619e01814ec9930eeb8dd0e62ee2cdff0b (diff) | |
download | libfaketime-338ec2e3df1c6ec6058a93c4288a3fbba7ba0dcb.tar.gz |
Merge branch 'develop'
-rw-r--r-- | src/Makefile | 9 | ||||
-rw-r--r-- | src/Makefile.OSX | 2 | ||||
-rw-r--r-- | src/libfaketime.c | 254 | ||||
-rw-r--r-- | src/libfaketime.map | 10 | ||||
-rwxr-xr-x | test/test.sh | 22 | ||||
-rw-r--r-- | test/timetest.c | 112 |
6 files changed, 342 insertions, 67 deletions
diff --git a/src/Makefile b/src/Makefile index d4d5be2..2ae30bd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -50,9 +50,9 @@ INSTALL ?= install PREFIX ?= /usr/local -CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -DFAKE_SLEEP -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"' +CFLAGS += -std=gnu99 -Wall -DFAKE_STAT -DFAKE_SLEEP -DFAKE_TIMERS -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"' LIB_LDFLAGS += -shared -LDFLAGS += -lrt +LDFLAGS += -lrt -Wl,--version-script=libfaketime.map LDADD += -ldl -lm -lpthread SRC = libfaketime.c @@ -69,9 +69,12 @@ faketimeMT.o: EXTRA_FLAGS := -DPTHREAD -DPTHREAD_SINGLETHREADED_TIME ${LIBS_OBJ}: libfaketime.c ${CC} -o $@ -c ${CFLAGS} ${EXTRA_FLAGS} $< -%.so.${SONAME}: %.o +%.so.${SONAME}: %.o libfaketime.map ${CC} -o $@ -Wl,-soname,$@ ${LDFLAGS} ${LIB_LDFLAGS} $< ${LDADD} +${BINS}: faketime.c + ${CC} -o $@ -c ${CFLAGS} ${EXTRA_FLAGS} $< + clean: @rm -f ${LIBS_OBJ} ${LIBS} ${BINS} diff --git a/src/Makefile.OSX b/src/Makefile.OSX index f3a0ceb..8b414c4 100644 --- a/src/Makefile.OSX +++ b/src/Makefile.OSX @@ -48,7 +48,7 @@ PREFIX ?= /usr/local # 10.5 #CFLAGS = -dynamiclib -arch i386 -arch ppc # 10.6 -CFLAGS = -dynamiclib -DFAKE_SLEEP -arch i386 -arch x86_64 -DPREFIX='"'$(PREFIX)'"' +CFLAGS = -dynamiclib -DFAKE_SLEEP -DFAKE_TIMERS -arch i386 -arch x86_64 -DPREFIX='"'$(PREFIX)'"' LIB_SRC = libfaketime.c SONAME = 1 diff --git a/src/libfaketime.c b/src/libfaketime.c index 4cadc64..a26e22f 100644 --- a/src/libfaketime.c +++ b/src/libfaketime.c @@ -118,9 +118,15 @@ static int (*real_gettimeofday) (struct timeval *, void *); static int (*real_clock_gettime) (clockid_t clk_id, struct timespec *tp); #ifndef __APPLE__ #ifdef FAKE_TIMERS -static int (*real_timer_settime) (timer_t timerid, int flags, const struct itimerspec *new_value, - struct itimerspec * old_value); -static int (*real_timer_gettime) (timer_t timerid, struct itimerspec *curr_value); +static int (*real_timer_settime_22) (int timerid, int flags, const struct itimerspec *new_value, + struct itimerspec * old_value); +static int (*real_timer_settime_233) (timer_t timerid, int flags, + const struct itimerspec *new_value, + struct itimerspec * old_value); +static int (*real_timer_gettime_22) (int timerid, + struct itimerspec *curr_value); +static int (*real_timer_gettime_233) (timer_t timerid, + struct itimerspec *curr_value); #endif #endif #ifdef FAKE_SLEEP @@ -923,21 +929,31 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) #ifndef __APPLE__ #ifdef FAKE_TIMERS + +/* timer related functions and structures */ +typedef union { + int int_member; + timer_t timer_t_member; +} timer_t_or_int; + +/* + * Faketime's function implementation's compatibility mode + */ +typedef enum {FT_COMPAT_GLIBC_2_2, FT_COMPAT_GLIBC_2_3_3} ft_lib_compat; + + /* * Faked timer_settime() * Does not affect timer speed when stepping clock with each time() call. */ -int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, - struct itimerspec *old_value) +static int +timer_settime_common(timer_t_or_int timerid, int flags, + const struct itimerspec *new_value, + struct itimerspec *old_value, ft_lib_compat compat) { int result; - struct itimerspec new_real, old_real; - struct itimerspec *new_real_pt = &new_real, *old_real_pt = &old_real; - - if (real_timer_settime == NULL) - { - return -1; - } + struct itimerspec new_real; + struct itimerspec *new_real_pt = &new_real; if (new_value == NULL) { @@ -950,40 +966,63 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value } else { - // TODO fake - struct timespec tdiff, timeadj; - timespecsub(&new_value->it_value, &user_faked_time_timespec, &timeadj); - if (user_rate_set) + /* set it_value */ + if ((new_value->it_value.tv_sec != 0) || + (new_value->it_value.tv_nsec != 0)) { - timespecmul(&timeadj, 1.0/user_rate, &tdiff); + if (flags & TIMER_ABSTIME) + { + struct timespec tdiff, timeadj; + timespecsub(&new_value->it_value, &user_faked_time_timespec, &timeadj); + if (user_rate_set) + { + timespecmul(&timeadj, 1.0/user_rate, &tdiff); + } + else + { + tdiff = timeadj; + } + /* only CLOCK_REALTIME is handled */ + timespecadd(&ftpl_starttime.real, &tdiff, &new_real.it_value); + } + else + { + if (user_rate_set) + { + timespecmul(&new_value->it_value, 1.0/user_rate, &new_real.it_value); + } + else + { + new_real.it_value = new_value->it_value; + } + } } else { - tdiff = timeadj; + new_real.it_value = new_value->it_value; } - /* only CLOCK_REALTIME is handled */ - timespecadd(&ftpl_starttime.real, &tdiff, &new_real.it_value); - - new_real.it_value = new_value->it_value; - if (user_rate_set) + /* set it_interval */ + if (user_rate_set && ((new_value->it_interval.tv_sec != 0) || + (new_value->it_interval.tv_nsec != 0))) { timespecmul(&new_value->it_interval, 1.0/user_rate, &new_real.it_interval); } + else + { + new_real.it_interval = new_value->it_interval; + } } - if (old_value == NULL) - { - old_real_pt = NULL; - } - else if (dont_fake) - { - old_real_pt = old_value; - } - else + + switch (compat) { - old_real = *old_value; + case FT_COMPAT_GLIBC_2_2: + DONT_FAKE_TIME(result = (*real_timer_settime_22)(timerid.int_member, flags, + new_real_pt, old_value)); + case FT_COMPAT_GLIBC_2_3_3: + DONT_FAKE_TIME(result = (*real_timer_settime_233)(timerid.timer_t_member, + flags, new_real_pt, old_value)); } - DONT_FAKE_TIME(result = (*real_timer_settime)(timerid, flags, new_real_pt, old_real_pt)); if (result == -1) { return result; @@ -992,30 +1031,79 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value /* fake returned parts */ if ((old_value != NULL) && !dont_fake) { - result = fake_clock_gettime(CLOCK_REALTIME, &old_real.it_value); - if (user_rate_set) + if ((old_value->it_value.tv_sec != 0) || + (old_value->it_value.tv_nsec != 0)) + { + result = fake_clock_gettime(CLOCK_REALTIME, &old_value->it_value); + } + if (user_rate_set && ((old_value->it_interval.tv_sec != 0) || + (old_value->it_interval.tv_nsec != 0))) { - timespecmul(&old_real.it_interval, user_rate, &old_value->it_interval); + timespecmul(&old_value->it_interval, user_rate, &old_value->it_interval); } } + /* return the result to the caller */ return result; } -/** +/* + * Faked timer_settime() compatible with implementation in GLIBC 2.2 + */ +int timer_settime_22(int timerid, int flags, + const struct itimerspec *new_value, + struct itimerspec *old_value) +{ + if (real_timer_settime_22 == NULL) + { + return -1; + } + else + { + return (timer_settime_common((timer_t_or_int)timerid, flags, new_value, old_value, + FT_COMPAT_GLIBC_2_2)); + } +} + +/* + * Faked timer_settime() compatible with implementation in GLIBC 2.3.3 + */ +int timer_settime_233(timer_t timerid, int flags, + const struct itimerspec *new_value, + struct itimerspec *old_value) +{ + if (real_timer_settime_233 == NULL) + { + return -1; + } + else + { + return (timer_settime_common((timer_t_or_int)timerid, flags, new_value, old_value, + FT_COMPAT_GLIBC_2_3_3)); + } +} + +/* * Faked timer_gettime() * Does not affect timer speed when stepping clock with each time() call. */ -int timer_gettime(timer_t timerid, struct itimerspec *curr_value) +int timer_gettime_common(timer_t_or_int timerid, struct itimerspec *curr_value, ft_lib_compat compat) { int result; - if (real_timer_gettime == NULL) + if (real_timer_gettime_233 == NULL) { return -1; } - DONT_FAKE_TIME(result = (*real_timer_gettime)(timerid, curr_value)); + switch (compat) + { + case FT_COMPAT_GLIBC_2_2: + DONT_FAKE_TIME(result = (*real_timer_gettime_22)(timerid.int_member, curr_value)); + case FT_COMPAT_GLIBC_2_3_3: + DONT_FAKE_TIME(result = (*real_timer_gettime_233)(timerid.timer_t_member, curr_value)); + } + if (result == -1) { return result; @@ -1033,6 +1121,44 @@ int timer_gettime(timer_t timerid, struct itimerspec *curr_value) /* return the result to the caller */ return result; } + +/* + * Faked timer_gettime() compatible with implementation in GLIBC 2.2 + */ +int timer_gettime_22(timer_t timerid, struct itimerspec *curr_value) +{ + if (real_timer_gettime_22 == NULL) + { + return -1; + } + else + { + return (timer_gettime_common((timer_t_or_int)timerid, curr_value, + FT_COMPAT_GLIBC_2_2)); + } +} + +/* + * Faked timer_gettime() compatible with implementation in GLIBC 2.3.3 + */ +int timer_gettime_233(timer_t timerid, struct itimerspec *curr_value) +{ + if (real_timer_gettime_233 == NULL) + { + return -1; + } + else + { + return (timer_gettime_common((timer_t_or_int)timerid, curr_value, + FT_COMPAT_GLIBC_2_3_3)); + } +} + +__asm__(".symver timer_gettime_22, timer_gettime@GLIBC_2.2"); +__asm__(".symver timer_gettime_233, timer_gettime@@GLIBC_2.3.3"); +__asm__(".symver timer_settime_22, timer_settime@GLIBC_2.2"); +__asm__(".symver timer_settime_233, timer_settime@@GLIBC_2.3.3"); + #endif #endif @@ -1247,33 +1373,35 @@ void __attribute__ ((constructor)) ftpl_init(void) char *tmp_env; /* Look up all real_* functions. NULL will mark missing ones. */ - real_stat = dlsym(RTLD_NEXT, "__xstat"); - real_fstat = dlsym(RTLD_NEXT, "__fxstat"); - real_fstatat = dlsym(RTLD_NEXT, "__fxstatat"); - real_lstat = dlsym(RTLD_NEXT, "__lxstat"); - real_stat64 = dlsym(RTLD_NEXT,"__xstat64"); - real_fstat64 = dlsym(RTLD_NEXT, "__fxstat64"); - real_fstatat64 = dlsym(RTLD_NEXT, "__fxstatat64"); - real_lstat64 = dlsym(RTLD_NEXT, "__lxstat64"); - real_time = dlsym(RTLD_NEXT, "time"); - real_ftime = dlsym(RTLD_NEXT, "ftime"); - real_gettimeofday = dlsym(RTLD_NEXT, "gettimeofday"); + real_stat = dlsym(RTLD_NEXT, "__xstat"); + real_fstat = dlsym(RTLD_NEXT, "__fxstat"); + real_fstatat = dlsym(RTLD_NEXT, "__fxstatat"); + real_lstat = dlsym(RTLD_NEXT, "__lxstat"); + real_stat64 = dlsym(RTLD_NEXT,"__xstat64"); + real_fstat64 = dlsym(RTLD_NEXT, "__fxstat64"); + real_fstatat64 = dlsym(RTLD_NEXT, "__fxstatat64"); + real_lstat64 = dlsym(RTLD_NEXT, "__lxstat64"); + real_time = dlsym(RTLD_NEXT, "time"); + real_ftime = dlsym(RTLD_NEXT, "ftime"); + real_gettimeofday = dlsym(RTLD_NEXT, "gettimeofday"); #ifdef FAKE_SLEEP - real_nanosleep = dlsym(RTLD_NEXT, "nanosleep"); - real_usleep = dlsym(RTLD_NEXT, "usleep"); - real_sleep = dlsym(RTLD_NEXT, "sleep"); - real_alarm = dlsym(RTLD_NEXT, "alarm"); - real_poll = dlsym(RTLD_NEXT, "poll"); - real_ppoll = dlsym(RTLD_NEXT, "ppoll"); + real_nanosleep = dlsym(RTLD_NEXT, "nanosleep"); + real_usleep = dlsym(RTLD_NEXT, "usleep"); + real_sleep = dlsym(RTLD_NEXT, "sleep"); + real_alarm = dlsym(RTLD_NEXT, "alarm"); + real_poll = dlsym(RTLD_NEXT, "poll"); + real_ppoll = dlsym(RTLD_NEXT, "ppoll"); #endif #ifdef __APPLE__ - real_clock_get_time = dlsym(RTLD_NEXT, "clock_get_time"); - real_clock_gettime = apple_clock_gettime; + real_clock_get_time = dlsym(RTLD_NEXT, "clock_get_time"); + real_clock_gettime = apple_clock_gettime; #else - real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime"); + real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime"); #ifdef FAKE_TIMERS - real_timer_settime = dlsym(RTLD_NEXT, "timer_settime"); - real_timer_gettime = dlsym(RTLD_NEXT, "timer_gettime"); + real_timer_settime_22 = dlvsym(RTLD_NEXT, "timer_settime","GLIBC_2.2"); + real_timer_settime_233 = dlvsym(RTLD_NEXT, "timer_settime","GLIBC_2.3.3"); + real_timer_gettime_22 = dlvsym(RTLD_NEXT, "timer_gettime","GLIBC_2.2"); + real_timer_gettime_233 = dlvsym(RTLD_NEXT, "timer_gettime","GLIBC_2.3.3"); #endif #endif diff --git a/src/libfaketime.map b/src/libfaketime.map new file mode 100644 index 0000000..6e008cf --- /dev/null +++ b/src/libfaketime.map @@ -0,0 +1,10 @@ +GLIBC_2.2 { + global: + + timer_gettime; timer_settime; + local: timer_settime_*; timer_gettime_*; +}; +GLIBC_2.3.3 { + # Changed timer_t. + timer_gettime; timer_settime; +} GLIBC_2.2; diff --git a/test/test.sh b/test/test.sh index 4014b99..c83807a 100755 --- a/test/test.sh +++ b/test/test.sh @@ -12,33 +12,55 @@ else echo fi +echo "=============================================================================" +echo + echo "Running the test program with absolute date 2003-01-01 10:00:05 specified" echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"2003-01-01 10:00:05\" ./timetest" LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="2003-01-01 10:00:05" ./timetest echo +echo "=============================================================================" +echo + echo "Running the test program with START date @2005-03-29 14:14:14 specified" echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"@2005-03-29 14:14:14\" ./timetest" LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="@2005-03-29 14:14:14" ./timetest echo +echo "=============================================================================" +echo + echo "Running the test program with 10 days negative offset specified" echo "LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"-10d\" ./timetest" LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="-10d" ./timetest echo +echo "=============================================================================" +echo + echo "Running the test program with 10 days negative offset specified, and FAKE_STAT disabled" echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"-10d\" NO_FAKE_STAT=1 ./timetest" LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="-10d" NO_FAKE_STAT=1 ./timetest +echo + +echo "=============================================================================" +echo echo "Running the test program with 10 days postive offset specified, and sped up 2 times" echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"+10d x2\" ./timetest" LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="+10d x2" NO_FAKE_STAT=1 ./timetest echo +echo "=============================================================================" +echo + echo "Running the 'date' command with 15 days negative offset specified" echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"-15d\" date" LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="-15d" date echo +echo "=============================================================================" +echo "Testing finished." + exit 0 diff --git a/test/timetest.c b/test/timetest.c index 139d171..b30afef 100644 --- a/test/timetest.c +++ b/test/timetest.c @@ -30,6 +30,22 @@ #include <unistd.h> #endif +#ifndef __APPLE__ +#include <signal.h> + +#define VERBOSE 0 + +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) */ + + printf("Caught signal %d\n", sig); + signal(sig, SIG_IGN); +} +#endif int main (int argc, char **argv) { @@ -38,11 +54,78 @@ int main (int argc, char **argv) { struct timeval tv; #ifndef __APPLE__ struct timespec ts; + timer_t timerid1 = 0, timerid2; + struct sigevent sev; + struct itimerspec its; + sigset_t mask; + struct sigaction sa; #endif #ifdef FAKE_STAT struct stat buf; #endif +#ifndef __APPLE__ + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = handler; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGRTMIN, &sa, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + /* Block timer signal temporarily */ + + printf("Blocking signal %d\n", SIGRTMIN); + sigemptyset(&mask); + sigaddset(&mask, SIGRTMIN); + if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + + /* Create the timer */ + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = SIGRTMIN; + sev.sigev_value.sival_ptr = &timerid1; + if (timer_create(CLOCK_REALTIME, &sev, &timerid1) == -1) { + 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; + + if (timer_settime(timerid1, 0, &its, NULL) == -1) { + perror("timer_settime"); + exit(EXIT_FAILURE); + } + + sev.sigev_value.sival_ptr = &timerid2; + if (timer_create(CLOCK_REALTIME, &sev, &timerid2) == -1) { + 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; + + if (timer_settime(timerid2, TIMER_ABSTIME, &its, NULL) == -1) { + perror("timer_settime"); + exit(EXIT_FAILURE); + } +#endif + time(&now); printf("time() : Current date and time: %s", ctime(&now)); printf("time(NULL) : Seconds since Epoch : %u\n", (unsigned int)time(NULL)); @@ -59,8 +142,37 @@ int main (int argc, char **argv) { printf("gettimeofday() : Current date and time: %s", ctime(&tv.tv_sec)); #ifndef __APPLE__ + if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) { + perror("sigprocmask"); + exit(EXIT_FAILURE); + } + clock_gettime(CLOCK_REALTIME, &ts); printf("clock_gettime(): Current date and time: %s", ctime(&ts.tv_sec)); + + int timer_getoverrun_timerid1 = timer_getoverrun(timerid1); + if (timer_getoverrun_timerid1 != 3) { + printf("timer_getoverrun(timerid1) FAILED, must be 3 but got: %d\n", timer_getoverrun_timerid1); + } + + timer_gettime(timerid1, &its); + if (VERBOSE == 1) { + printf("timer_gettime(timerid1, &its); its = {{%ld, %ld}, {%ld, %ld}}}\n", + its.it_interval.tv_sec, its.it_interval.tv_nsec, + its.it_value.tv_sec, its.it_value.tv_nsec); + } + + int timer_getoverrun_timerid2 = timer_getoverrun(timerid2); + if (timer_getoverrun_timerid2 != 0) { + printf("timer_getoverrun(timerid2) FAILED, must be 0 but got: %d\n", timer_getoverrun_timerid2); + } + + timer_gettime(timerid2, &its); + if (VERBOSE == 1) { + printf("timer_gettime(timerid2, &its); its = {{%ld, %ld}, {%ld, %ld}}}\n", + its.it_interval.tv_sec, its.it_interval.tv_nsec, + its.it_value.tv_sec, its.it_value.tv_nsec); + } #endif #ifdef FAKE_STAT |