diff options
author | Balint Reczey <balint@balintreczey.hu> | 2013-09-30 16:36:13 +0200 |
---|---|---|
committer | Wolfgang Hommel <wolfgang.hommel@lrz.de> | 2013-09-30 16:36:13 +0200 |
commit | 50c6ad4dc273e0cf0b11bdec225366e6a8ce1ae4 (patch) | |
tree | 4fa591143ce5be72c53db768dc1308048a9b1907 | |
parent | 27468e804db0c96b62bf0b1e8468bdc3b7c5f59b (diff) | |
download | libfaketime-50c6ad4dc273e0cf0b11bdec225366e6a8ce1ae4.tar.gz |
Provide timer related functions compatible with GLIBC 2.2 and >= 2.3.3 [pr32 @8615959]
-rw-r--r-- | src/Makefile | 4 | ||||
-rw-r--r-- | src/libfaketime.c | 254 | ||||
-rw-r--r-- | src/libfaketime.map | 10 | ||||
-rw-r--r-- | test/timetest.c | 99 |
4 files changed, 302 insertions, 65 deletions
diff --git a/src/Makefile b/src/Makefile index 6655888..b167dad 100644 --- a/src/Makefile +++ b/src/Makefile @@ -52,7 +52,7 @@ PREFIX ?= /usr/local 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,7 +69,7 @@ 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} clean: 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/timetest.c b/test/timetest.c index 139d171..48e02b7 100644 --- a/test/timetest.c +++ b/test/timetest.c @@ -30,6 +30,20 @@ #include <unistd.h> #endif +#ifndef __APPLE__ +#include <signal.h> + +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 +52,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 +140,26 @@ 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)); + + printf("timer_getoverrun(timerid1), must be 3: %d\n", + timer_getoverrun(timerid1)); + timer_gettime(timerid1, &its); + 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); + printf("timer_getoverrun(timerid2), must be 0: %d\n", + timer_getoverrun(timerid2)); + timer_gettime(timerid2, &its); + 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 |