Materiale treno
[gapil.git] / sources / test_timerfdfork.c
1 /* test_timerfdfork.c
2  * 
3  * Copyright (C) 2011 Simone Piccardi
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or (at
8  * your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /****************************************************************
20  *
21  * Program test_timerfdfork.c: 
22  * Program to test timerfd behaviour across fork's
23  *
24  * Author: Simone Piccardi
25  * Apr. 2011
26  *
27  * Usage: testtimerfdfork -h give all info's
28  *
29  ****************************************************************/
30 /* 
31  * Include needed headers
32  */
33 #define _GNU_SOURCE
34 #include <errno.h>       /* error definitions and routines */ 
35 #include <stdlib.h>      /* C standard library */
36 #include <unistd.h>      /* unix standard library */
37 #include <stdio.h>       /* standard I/O library */
38 #include <string.h>      /* C strings library */
39 #include <sys/timerfd.h> /* timerfd */
40 #include <sys/epoll.h>   /* Linux epoll interface */
41 #include <time.h>
42
43 #include "macros.h"
44 #include "Gapil.h"
45
46 /* Help printing routine */
47 void usage(void);
48 void die(char *);
49
50 #define MAX_EPOLL_EV 10
51
52 int main(int argc, char *argv[])
53 {
54 /* 
55  * Variables definition  
56  */
57     int i, n, nread, fd, epfd;
58     int wait=5, interval=1, nswait=0, nsinter=0;   // timer default
59     pid_t pid;
60     struct epoll_event epev, events[MAX_EPOLL_EV];
61     struct itimerspec expiring;
62     uint64_t expired;
63     /*
64      * Input section: decode command line parameters 
65      * Use getopt function
66      */
67     opterr = 0;  /* don't want writing to stderr */
68     while ( (i = getopt(argc, argv, "ht:i:w:n:")) != -1) {
69         switch (i) {
70         /* 
71          * Handling options 
72          */ 
73         case 'h':   /* help option */
74             printf("Wrong -h option use\n");
75             usage();
76             return -1;
77             break;
78         case 'i':      /* timer interval */
79             interval = strtol(optarg, NULL, 10);    /* convert input */
80             break;
81         case 't':      /* timer expiring */
82             wait = strtol(optarg, NULL, 10);    /* convert input */
83             break;
84         case 'n':      /* timer interval in ns */
85             nsinter = strtol(optarg, NULL, 10);    /* convert input */
86             break;
87         case 'w':      /* timer expiring in ns */
88             nswait = strtol(optarg, NULL, 10);    /* convert input */
89             break;
90         case '?':   /* unrecognized options */
91             printf("Unrecognized options -%c\n",optopt);
92             usage();
93         default:    /* should not reached */
94             usage();
95         }
96     }
97     /* ***********************************************************
98      * 
99      *           Options processing completed
100      *
101      *                Main code beginning
102      * 
103      * ***********************************************************/
104     /* There must be 0 remaing arguments */
105     if ( (argc-optind) != 0 )  {
106         printf("From %d arguments, removed %d options\n", argc, optind);
107         usage();
108     }
109     /* timerfd setup */
110     fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
111     expiring.it_interval.tv_sec=interval;
112     expiring.it_interval.tv_nsec=nsinter;
113     expiring.it_value.tv_sec=wait;
114     expiring.it_value.tv_nsec=nswait;
115     if (timerfd_settime(fd, 0, &expiring, NULL)) {
116         die("Cannot set timer");
117     }
118     printf("Timer interval %i sec, timer time %i sec\n", wait, interval);
119     pid = fork();
120     /* epoll setup */
121     if ((epfd=epoll_create(5)) < 0)
122         die("Failing on epoll_create");
123     epev.data.fd = fd;
124     epev.events = EPOLLIN;
125     if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epev))
126         die("Failing in epoll_ctl"); 
127     /* main loop */
128     while (1) {
129         while (n=epoll_wait(epfd, events, MAX_EPOLL_EV, -1)) { 
130             if (n < 0) {
131                 if (errno != EAGAIN) 
132                     die("error on epoll_wait");
133                 else 
134                     continue;
135             } else {
136                 printf("Got %i events, pid %i, time %i\n", n, pid, time(NULL));
137                 /* loop on epoll events */
138                 for (i=0; i<n; i++) {
139                     if (events[i].data.fd == fd) {   // if timer expired
140                         printf("Timer expired in pid %i:\n", pid);
141                         while(nread=read(fd, &expired, sizeof(expired))) {
142                             if (nread < 0) {
143                                 if (errno != EAGAIN) 
144                                     die("signalfd read error");
145                                 else 
146                                     break;
147                             }
148                             if (nread != sizeof(expired)) {
149                                 printf("Error on timer data read, '\n");
150                                 continue;
151                             }
152                             printf("Expired %llu times in pid %i\n", 
153                                    expired, pid);
154                         }
155                     }
156                 }
157             }
158         }
159     }
160     return 0;
161 }
162 /*
163  * routine to print usage info and exit
164  */
165 void usage(void) {
166     printf("Program testtimerfdfork : test timerfd across fork  \n");
167     printf("Usage:\n");
168     printf("  testtimerfdfork [-h]  \n");
169     printf("  -i sec       interval for repetition\n");
170     printf("  -t sec       time to wait to expire\n");
171     printf("  -h           print this help\n");
172     
173     exit(1);
174 }
175 /*
176  * Print error message and exit routine
177  */
178 void die(char * mess) {
179     perror(mess);
180     exit(-1);
181 }
182