leiva
leiva

Reputation: 65

RT timer strange behavior

I am learning how to use RT timers to create a periodic event. I have trying with this example that is based of the timer_create documentation example.

The behavior expected is produce a periodic event each 5 seconds meanwhile main execution is sleeping for 30 seconds, but I get the follow behavior.

The timer is created and is initialized the main execution sleeps. 5 seconds later the timer event is produced, the respectively handler is call and when the handler function finishes the main execution wakes up and the elapsed time is 5 second but must be 30 seconds.

/* gcc main.c -Wall -Wextra -lrt -o timer */ 
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>

/* Macros *********************************************************************/
#define CLOCKID CLOCK_REALTIME
/* Real-time signals number */
#define RT_SIGNAL_NUM SIGRTMIN

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE);} while (0)

#define MAIN_SLEEP 30
#define TIMER_TIME 5


/* Global data ****************************************************************/
struct itimerspec gIts;

timer_t gTimerId;

/* Functions ******************************************************************/

static void handler(int sig, siginfo_t *si, void *uc)
{
    int or;
    timer_t *tidp;
    /* 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);

}

void main(int argc, char *argv[])
{
    struct sigevent sev;
    long long freq_nanosecs;
    sigset_t mask;
    struct sigaction sa;
    time_t begin, end;
    double time_spent;

    (void) argc;
    (void) argv;

    /* Establish handler for  Real-time signal */
    printf("Establishing handler for signal %d\n", RT_SIGNAL_NUM);
    /* If SA_SIGINFO is specified in sa_flags, then sa_sigaction (instead of
     * sa_handler) specifies the signal-handling function for signum.
     */
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = handler;
    /* the Signal no would be masked. */
    sigemptyset(&sa.sa_mask);
    /* Change the action taken by a process on receipt of a specific signal. */
    if (-1 == sigaction(RT_SIGNAL_NUM, &sa, NULL))
    {
        errExit("sigaction");
    }

    /* Configure timer:
     * SIGEV_SIGNAL: Upon timer expiration, generate the signal sigev_signo for
     * the process.
     */
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = RT_SIGNAL_NUM;
    sev.sigev_value.sival_ptr = &gTimerId;
    /* Create and init the timer */
    if (-1 == timer_create(CLOCKID, &sev, &gTimerId))
    {
        errExit("timer_create");
    }

    printf("timer ID is 0x%lx\n", (long) gTimerId);
    /* Start the timer */
    gIts.it_value.tv_sec = TIMER_TIME ;
    gIts.it_value.tv_nsec = 0;
    gIts.it_interval.tv_sec = TIMER_TIME;
    gIts.it_interval.tv_nsec = 0;
    if (-1 == timer_settime(gTimerId, 0, &gIts, NULL))
    {
         errExit("timer_settime");
    }

    /* Sleep for a while; meanwhile, the timer may expire multiple times */
    struct itimerspec currTime;
    printf("Main Sleep for %d seconds\n", MAIN_SLEEP);
    begin = time(NULL);
    sleep(MAIN_SLEEP);
    end = time(NULL);
    printf("Main Wake up\n");
    time_spent = (double)(end - begin);
    timer_gettime(gTimerId, &currTime);
    printf("Main sleep elapsed time = %f s %d %d\n",time_spent);
    printf("Timer time = %ld s\n",currTime.it_value.tv_sec);

    exit(EXIT_SUCCESS);
}

This is the execution output:

Establishing handler for signal 34
timer ID is 0x9522008
Main Sleep for 30 seconds
Caught signal 34
Main Wake up
Main sleep elapsed time = 5.000000 s
Timer time = 4 s

Can someone help me to figure out what happen here?

Thanks in advance.

Upvotes: 2

Views: 167

Answers (1)

user3386109
user3386109

Reputation: 34829

When the signal is generated, the sleep function is interrupted and returns immediately. To quote the man page for sleep

The sleep() function suspends execution of the calling thread until either [the time has] elapsed or a signal is delivered to the thread and its action is to invoke a signal-catching function or to terminate the thread or process.

Fortunately, the return value from the sleep function is the amount of time left to sleep, so you can simply call sleep in a loop like this

int t = 30;
while ( t > 0 )
    t = sleep( t );

Upvotes: 2

Related Questions