blob: 53535e1a7af4b834dc0f733f4676b348a87a56b6 [file] [log] [blame]
/*
* timerfd() test by Davide Libenzi (test app for timerfd)
* Copyright (C) 2007 Davide Libenzi
*
* 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
*
* Davide Libenzi <davidel@xmailserver.org>
*
*
* $ gcc -o timerfd-test2 timerfd-test2.c -lrt
*
* NAME
* timerfd01.c
* HISTORY
* 28/05/2008 Initial contribution by Davide Libenzi <davidel@xmailserver.org>
* 28/05/2008 Integrated to LTP by Subrata Modak <subrata@linux.vnet.ibm.com>
* 2016-04-08 Deintegrated from LTP by Barret Rhoden <brho@cs.berkeley.edu>
* Ported to Akaros. Added a few more tests.
*/
#define _GNU_SOURCE
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <poll.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <sys/timerfd.h>
#include <sys/select.h>
#include <parlib/alarm.h>
#include <parlib/uthread.h>
struct tmr_type {
int id;
char const *name;
};
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;
}
void set_timespec(struct timespec *tmr, unsigned long long ustime)
{
tmr->tv_sec = (time_t) (ustime / 1000000ULL);
tmr->tv_nsec = (long)(1000ULL * (ustime % 1000000ULL));
}
long waittmr(int tfd, int timeo)
{
u_int64_t ticks;
fd_set rfds;
struct timeval tv, *timeout = 0;
int ret;
FD_ZERO(&rfds);
FD_SET(tfd, &rfds);
if (timeo != -1) {
tv.tv_sec = timeo / 1000;
tv.tv_usec = (timeo % 1000) * 1000;
timeout = &tv;
}
ret = select(tfd + 1, &rfds, 0, 0, timeout);
if (ret < 0) {
perror("select");
return -1;
}
if (ret == 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, "waiting 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 %llu ms\n",
ticks, (ttmr - tnow) / 1000);
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, "waiting 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 %llu ms\n",
ticks, (ttmr - tnow) / 1000);
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 1 second ...\n");
sleep(1);
if (timerfd_gettime(tfd, &tmr)) {
perror("timerfd_gettime");
return 1;
}
fprintf(stdout, "timerfd_gettime returned:\n"
"\tit_value = { %ld, %ld } it_interval = { %ld, %ld }\n",
(long)tmr.it_value.tv_sec, (long)tmr.it_value.tv_nsec,
(long)tmr.it_interval.tv_sec,
(long)tmr.it_interval.tv_nsec);
fprintf(stdout, "sleeping 1 second ...\n");
sleep(1);
fprintf(stdout, "waiting 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 %llu ms\n",
ticks, (ttmr - tnow) / 1000);
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, "waiting 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 %llu ms\n",
ticks, (ttmr - tnow) / 1000);
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");
/* try a select loop with O_NONBLOCK */
fd_set rfds;
bool has_selected = FALSE;
int ret;
FD_ZERO(&rfds);
FD_SET(tfd, &rfds);
set_timespec(&tmr.it_value, 1000000);
set_timespec(&tmr.it_interval, 0);
if (timerfd_settime(tfd, 0, &tmr, NULL)) {
perror("timerfd_settime");
exit(-1);
}
while (1) {
ret = read(tfd, &uticks, sizeof(uticks));
if (ret < 0) {
if (errno != EAGAIN) {
perror("select read");
exit(-1);
}
} else {
if (ret != sizeof(uticks)) {
fprintf(stdout, "short read! (bad)\n");
exit(-1);
}
if (uticks)
break;
}
if (select(tfd + 1, &rfds, 0, 0, 0) < 0) {
perror("select");
return -1;
}
has_selected = TRUE;
}
if (!has_selected) {
fprintf(stdout, "Failed to try to select!\n");
exit(-1);
}
fprintf(stdout, "more success\n");
fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) & ~O_NONBLOCK);
/* let's make sure it actually blocks too. */
struct alarm_waiter waiter;
init_awaiter(&waiter, alarm_abort_sysc);
waiter.data = current_uthread;
set_awaiter_rel(&waiter, 1000000);
set_timespec(&tmr.it_value, 10000000);
set_timespec(&tmr.it_interval, 0);
if (timerfd_settime(tfd, 0, &tmr, NULL)) {
perror("timerfd_settime");
exit(-1);
}
set_alarm(&waiter);
ret = read(tfd, &uticks, sizeof(uticks));
unset_alarm(&waiter);
if (ret > 0) {
fprintf(stdout,
"Failed to block when we should have!\n");
exit(-1);
}
fprintf(stdout, "done (still success)\n");
close(tfd);
}
}