clinuxunixsignalssetitimer

Understanding struct itimerval field tv_usec


Hi I'm studying this code:

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>


volatile sig_atomic_t print_flag = true;
static int count = 0;

void timer_handler (int signum)
{

 printf ("timer expired %d times\n", ++count);
 if(count>20) {
    print_flag = false;
 } 
}

int main ()
{
 struct sigaction sa;
 struct itimerval timer;

 /* Install timer_handler as the signal handler for SIGVTALRM. */
 memset (&sa, 0, sizeof (sa));
 sa.sa_handler = &timer_handler;
 sigaction (SIGALRM, &sa, NULL);

 /* Configure the timer to expire after 250 msec... */
 timer.it_value.tv_sec = 0;
 timer.it_value.tv_usec = 250000;
 /* ... and every 250 msec after that. */
 timer.it_interval.tv_sec = 0;
 timer.it_interval.tv_usec = 250000;
 /* Start a virtual timer. It counts down whenever this process is
   executing. */
 setitimer (ITIMER_REAL, &timer, NULL);

 /* Do busy work. */
 while (print_flag) {
    sleep(1);
 }

printf("job done bye bye\n");
    exit(0);

}

With this settings everything goes fine and i get this output

...
timer expired 17 times
timer expired 18 times
timer expired 19 times
timer expired 20 times
timer expired 21 times
job done bye bye

If i try to alter the code commenting timer.it_interval.tv_usec and timer.it_interval.tv_usecand setting both timer.it_value.tv_sec and timer.it_value.tv_sec equal to, for instance, 3 it doesn't do his job.

However if I maintain an explicit declaration of tv_usec like this it works:

 timer.it_value.tv_sec = 3;
 timer.it_value.tv_usec = 0;
 timer.it_interval.tv_sec = 3;
 timer.it_interval.tv_usec = 0;

Why I'm bonded on the explicit declaration of tv_usec for both fields?


Solution

  • As far as you don't initialize *.tv_usec fields, theirs values are undefined. If it'd contain a value greater that 999999 or less than 0, the setitimer () will just fail with EINVAL as described on the man page.

    You ought to initialize all the data yourself. If you are willing to save a line of code, you may memset the timer struct to 0 the same way you have done it for sa.