summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBalint Reczey <balint@balintreczey.hu>2013-09-30 16:36:13 +0200
committerWolfgang Hommel <wolfgang.hommel@lrz.de>2013-09-30 16:36:13 +0200
commit50c6ad4dc273e0cf0b11bdec225366e6a8ce1ae4 (patch)
tree4fa591143ce5be72c53db768dc1308048a9b1907
parent27468e804db0c96b62bf0b1e8468bdc3b7c5f59b (diff)
downloadlibfaketime-50c6ad4dc273e0cf0b11bdec225366e6a8ce1ae4.tar.gz
Provide timer related functions compatible with GLIBC 2.2 and >= 2.3.3 [pr32 @8615959]
-rw-r--r--src/Makefile4
-rw-r--r--src/libfaketime.c254
-rw-r--r--src/libfaketime.map10
-rw-r--r--test/timetest.c99
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