From: Bart Van Assche Date: Sun, 27 Apr 2008 12:52:33 +0000 (+0000) Subject: Added regression test for timerfd_create(), timerfd_gettime() and timerfd_settime... X-Git-Tag: svn/VALGRIND_3_4_0~682 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3ed6a4e595e52158f55b81fc4375961bb8f7c919;p=thirdparty%2Fvalgrind.git Added regression test for timerfd_create(), timerfd_gettime() and timerfd_settime() system calls. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7941 --- diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am index c73e3cba30..b3bd006d3a 100644 --- a/memcheck/tests/Makefile.am +++ b/memcheck/tests/Makefile.am @@ -67,6 +67,7 @@ EXTRA_DIST = $(noinst_SCRIPTS) \ leakotron.vgtest leakotron.stdout.exp leakotron.stderr.exp \ linux-syslog-syscall linux-syslog-syscall.stderr.exp \ linux-syscalls-2007 linux-syscalls-2007.stderr.exp \ + linux-timerfd-syscall linux-timerfd-syscall.stderr.exp \ long_namespace_xml.vgtest long_namespace_xml.stdout.exp \ long_namespace_xml.stderr.exp \ lsframe1.vgtest lsframe1.stdout.exp lsframe1.stderr.exp \ @@ -174,6 +175,7 @@ check_PROGRAMS = \ leak-0 leak-cycle leak-pool leak-tree leak-regroot leakotron \ linux-syslog-syscall \ linux-syscalls-2007 \ + linux-timerfd-syscall \ long_namespace_xml \ lsframe1 lsframe2 \ mallinfo \ @@ -214,6 +216,7 @@ memcmptest_CFLAGS = $(AM_FLAG_M3264_PRI) $(AM_CFLAGS) -fno-builtin-memcmp oset_test_CFLAGS = $(AM_FLAG_M3264_PRI) \ -DVGA_$(VG_ARCH)=1 -DVGO_$(VG_OS)=1 \ -DVGP_$(VG_ARCH)_$(VG_OS)=1 +linux_timerfd_syscall_CFLAGS = -lrt vcpu_bz2_CFLAGS = $(AM_FLAG_M3264_PRI) $(AM_CFLAGS) -O2 -g vcpu_fbench_CFLAGS = $(AM_FLAG_M3264_PRI) $(AM_CFLAGS) -O2 -g vcpu_fnfns_CFLAGS = $(AM_FLAG_M3264_PRI) $(AM_CFLAGS) -O2 -g diff --git a/memcheck/tests/linux-timerfd-syscall.c b/memcheck/tests/linux-timerfd-syscall.c new file mode 100644 index 0000000000..4425bc42e6 --- /dev/null +++ b/memcheck/tests/linux-timerfd-syscall.c @@ -0,0 +1,298 @@ +/** Test Valgrind's interception of the Linux syscalls timerfd_create(), + * timerfd_gettime() and timerfd_settime(). + * + * This is a modified version of + * timerfd-test2 by Davide Libenzi (test app for timerfd) + * Copyright (C) 2007 Davide Libenzi + * Modified for inclusion in Valgrind. + * Copyright (C) 2008 Bart Van Assche + * + * This program 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 License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * See also http://www.xmailserver.org/timerfd-test2.c + */ + +#if defined(__linux__) + +#define _GNU_SOURCE + +#include "../../config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(HAVE_SYS_SIGNAL_H) +#include +#endif +#if defined(HAVE_SYS_SYSCALL_H) +#include +#endif +#if defined(HAVE_SYS_TIME_H) +#include +#endif +#if defined(HAVE_SYS_TYPES_H) +#include +#endif + + +/* + * timerfd_* system call numbers introduced in 2.6.23. These constants are + * not yet in the glibc 2.7 headers, that is why they are defined here. + */ +#ifndef __NR_timerfd_create +#if defined(__x86_64__) +#define __NR_timerfd_create 283 +#define __NR_timerfd_settime 286 +#define __NR_timerfd_gettime 287 +#elif defined(__i386__) +#define __NR_timerfd_create 322 +#define __NR_timerfd_settime 325 +#define __NR_timerfd_gettime 326 +#elif defined(__powerpc__) +#define __NR_timerfd_create 306 +#define __NR_timerfd_settime 311 +#define __NR_timerfd_gettime 312 +#else +#error Cannot detect your architecture! +#endif +#endif + + + +/* Definitions from include/linux/timerfd.h */ +#define TFD_TIMER_ABSTIME (1 << 0) + + + +struct tmr_type +{ + int id; + char const *name; +}; + + +#if defined(HAVE_CLOCK_GETTIME) +unsigned long long getustime(int clockid) +{ + struct timespec tp; + + if (clock_gettime((clockid_t) clockid, &tp)) + { + perror("clock_gettime"); + return 0; + } + + return 1000000ULL * tp.tv_sec + tp.tv_nsec / 1000; +} +#else +unsigned long long getustime(int clockid) +{ + fprintf(stderr, "error: clock_gettime\n"); + return 0; +} +#endif + +void set_timespec(struct timespec *tmr, unsigned long long ustime) +{ + tmr->tv_sec = (time_t) (ustime / 1000000ULL); + tmr->tv_nsec = (long) (1000ULL * (ustime % 1000000ULL)); +} + +int timerfd_create(int clockid, int flags) +{ + return syscall(__NR_timerfd_create, clockid, flags); +} + +int timerfd_settime(int ufc, int flags, const struct itimerspec *utmr, + struct itimerspec *otmr) +{ + return syscall(__NR_timerfd_settime, ufc, flags, utmr, otmr); +} + +int timerfd_gettime(int ufc, struct itimerspec *otmr) +{ + return syscall(__NR_timerfd_gettime, ufc, otmr); +} + +long waittmr(int tfd, int timeo) +{ + u_int64_t ticks; + struct pollfd pfd; + + pfd.fd = tfd; + pfd.events = POLLIN; + pfd.revents = 0; + if (poll(&pfd, 1, timeo) < 0) + { + perror("poll"); + return -1; + } + if ((pfd.revents & POLLIN) == 0) + { + fprintf(stdout, "no ticks happened\n"); + return -1; + } + if (read(tfd, &ticks, sizeof(ticks)) != sizeof(ticks)) + { + perror("timerfd read"); + return -1; + } + + return ticks; +} + +int main(int ac, char **av) +{ + int i, tfd; + long ticks; + unsigned long long tnow, ttmr; + u_int64_t uticks; + struct itimerspec tmr; + struct tmr_type clks[] = + { + { CLOCK_MONOTONIC, "CLOCK MONOTONIC" }, + { CLOCK_REALTIME, "CLOCK REALTIME" }, + }; + + for (i = 0; i < sizeof(clks) / sizeof(clks[0]); i++) + { + fprintf(stdout, "\n\n---------------------------------------\n"); + fprintf(stdout, "| testing %s\n", clks[i].name); + fprintf(stdout, "---------------------------------------\n\n"); + + fprintf(stdout, "relative timer test (at 500 ms) ...\n"); + set_timespec(&tmr.it_value, 500 * 1000); + set_timespec(&tmr.it_interval, 0); + tnow = getustime(clks[i].id); + if ((tfd = timerfd_create(clks[i].id, 0)) == -1) + { + perror("timerfd"); + return 1; + } + fprintf(stdout, "timerfd = %d\n", tfd); + + if (timerfd_settime(tfd, 0, &tmr, NULL)) + { + perror("timerfd_settime"); + return 1; + } + + fprintf(stdout, "wating timer ...\n"); + ticks = waittmr(tfd, -1); + ttmr = getustime(clks[i].id); + if (ticks <= 0) + fprintf(stdout, "whooops! no timer showed up!\n"); + else + fprintf(stdout, "got timer ticks (%ld) after %.1f s\n", + ticks, (ttmr - tnow) * 1e-6); + + + fprintf(stdout, "absolute timer test (at 500 ms) ...\n"); + tnow = getustime(clks[i].id); + set_timespec(&tmr.it_value, tnow + 500 * 1000); + set_timespec(&tmr.it_interval, 0); + if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tmr, NULL)) + { + perror("timerfd_settime"); + return 1; + } + + fprintf(stdout, "wating timer ...\n"); + ticks = waittmr(tfd, -1); + ttmr = getustime(clks[i].id); + if (ticks <= 0) + fprintf(stdout, "whooops! no timer showed up!\n"); + else + fprintf(stdout, "got timer ticks (%ld) after %.1f s\n", + ticks, (ttmr - tnow) * 1e-6); + + fprintf(stdout, "sequential timer test (100 ms clock) ...\n"); + tnow = getustime(clks[i].id); + set_timespec(&tmr.it_value, tnow + 100 * 1000); + set_timespec(&tmr.it_interval, 100 * 1000); + if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tmr, NULL)) + { + perror("timerfd_settime"); + return 1; + } + + fprintf(stdout, "sleeping one second ...\n"); + sleep(1); + if (timerfd_gettime(tfd, &tmr)) + { + perror("timerfd_gettime"); + return 1; + } + fprintf(stdout, "timerfd_gettime returned:\n" + "\tit_value = %.1f it_interval = %.1f\n", + tmr.it_value.tv_sec + 1e-9 * tmr.it_value.tv_nsec, + tmr.it_interval.tv_sec + 1e-9 * tmr.it_interval.tv_nsec); + fprintf(stdout, "sleeping 1 second ...\n"); + sleep(1); + + fprintf(stdout, "wating timer ...\n"); + ticks = waittmr(tfd, -1); + ttmr = getustime(clks[i].id); + if (ticks <= 0) + fprintf(stdout, "whooops! no timer showed up!\n"); + else + fprintf(stdout, "got timer ticks (%ld) after %.1f s\n", + ticks, (ttmr - tnow) * 1e-6); + + + fprintf(stdout, "O_NONBLOCK test ...\n"); + tnow = getustime(clks[i].id); + set_timespec(&tmr.it_value, 100 * 1000); + set_timespec(&tmr.it_interval, 0); + if (timerfd_settime(tfd, 0, &tmr, NULL)) + { + perror("timerfd_settime"); + return 1; + } + fprintf(stdout, "timerfd = %d\n", tfd); + + fprintf(stdout, "wating timer (flush the single tick) ...\n"); + ticks = waittmr(tfd, -1); + ttmr = getustime(clks[i].id); + if (ticks <= 0) + fprintf(stdout, "whooops! no timer showed up!\n"); + else + fprintf(stdout, "got timer ticks (%ld) after %.1f s\n", + ticks, (ttmr - tnow) * 1e-6); + + fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) | O_NONBLOCK); + + if (read(tfd, &uticks, sizeof(uticks)) > 0) + fprintf(stdout, "whooops! timer ticks not zero when should have been\n"); + else if (errno != EAGAIN) + fprintf(stdout, "whooops! bad errno value (%d = '%s')!\n", + errno, strerror(errno)); + else + fprintf(stdout, "success\n"); + + fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) & ~O_NONBLOCK); + + close(tfd); + } + + return 0; +} + +#endif /* __linux__ */ diff --git a/memcheck/tests/linux-timerfd-syscall.stderr.exp b/memcheck/tests/linux-timerfd-syscall.stderr.exp new file mode 100644 index 0000000000..c4aa6f04fe --- /dev/null +++ b/memcheck/tests/linux-timerfd-syscall.stderr.exp @@ -0,0 +1,7 @@ + + +ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +malloc/free: in use at exit: 0 bytes in 0 blocks. +malloc/free: 0 allocs, 0 frees, 0 bytes allocated. +For a detailed leak analysis, rerun with: --leak-check=yes +For counts of detected errors, rerun with: -v diff --git a/memcheck/tests/linux-timerfd-syscall.stdout.exp b/memcheck/tests/linux-timerfd-syscall.stdout.exp new file mode 100644 index 0000000000..446f0863fa --- /dev/null +++ b/memcheck/tests/linux-timerfd-syscall.stdout.exp @@ -0,0 +1,50 @@ + + +--------------------------------------- +| testing CLOCK MONOTONIC +--------------------------------------- + +relative timer test (at 500 ms) ... +timerfd = 3 +wating timer ... +got timer ticks (1) after 0.5 s +absolute timer test (at 500 ms) ... +wating timer ... +got timer ticks (1) after 0.5 s +sequential timer test (100 ms clock) ... +sleeping one second ... +timerfd_gettime returned: + it_value = 0.1 it_interval = 0.1 +sleeping 1 second ... +wating timer ... +got timer ticks (20) after 2.0 s +O_NONBLOCK test ... +timerfd = 3 +wating timer (flush the single tick) ... +got timer ticks (1) after 0.1 s +success + + +--------------------------------------- +| testing CLOCK REALTIME +--------------------------------------- + +relative timer test (at 500 ms) ... +timerfd = 3 +wating timer ... +got timer ticks (1) after 0.5 s +absolute timer test (at 500 ms) ... +wating timer ... +got timer ticks (1) after 0.5 s +sequential timer test (100 ms clock) ... +sleeping one second ... +timerfd_gettime returned: + it_value = 0.1 it_interval = 0.1 +sleeping 1 second ... +wating timer ... +got timer ticks (20) after 2.0 s +O_NONBLOCK test ... +timerfd = 3 +wating timer (flush the single tick) ... +got timer ticks (1) after 0.1 s +success diff --git a/memcheck/tests/linux-timerfd-syscall.vgtest b/memcheck/tests/linux-timerfd-syscall.vgtest new file mode 100644 index 0000000000..ecd0d3e14c --- /dev/null +++ b/memcheck/tests/linux-timerfd-syscall.vgtest @@ -0,0 +1,2 @@ +prereq: [ "$(uname)" = "Linux" ] && awk 'END{exit("'$(uname -r)'" >= "2.6.23" ? 0 : 1)}'