Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple timers in C

I have an application which needs to do the following:

  • If an event happens (a disconnect from server), a long timer is started (say 5 minutes). The application then tries to reconnect to the server.
  • If the reconnect fails, a short timer is started (20 seconds) which should attempt to reconnect again.
  • If it succeeds, the long timer should keep going.
  • When the long timer expires, if there is no connection, the application should exit, otherwise it should continue as normal.

I am limited in that I cannot use threads, only processes. I also cannot afford to wait for the result of reconnect() to return.

So far I have a design like this:

int main(int argc, char **argv)
{
    /* do main loop work, if disconnected, call reconnect() & continue doing work */
}

void reconnect()
{
    pid = fork();

    if (pid >= 0) {
        /*Successful fork*/
        if (pid == 0) {

            rv = attempt_reconnect;               
            if (rv == 0) {
                /*Notify sig_child Success*/
                exit(0);
            } else {
                /*Notify sig_child Fail*/
                exit(1);
            }
        }
    } 
}

void sig_child(int signum)
{
    if(fork returned success) {
        set flag to continue network stuff
    }
    else {
        alarm(20);
    }
}

void sig_alarm(int signo)
{
    /*Received alarm, trying to reconnect...*/
    reconnect();
}

Any help would be greatly appreciated!

Edit

I think I have a solution working from an example here. It allows me to create timers with separate ID's, and then identify which one has has signalled the program

like image 965
TomSelleck Avatar asked Oct 24 '25 20:10

TomSelleck


2 Answers

Using the following code I found here, I have achieved (I think) what I was trying to do.

It allows the creation and handling of multiple timer_t objects using the functions "makeTtimer" and "timerHandler" respectively:

timer_t reconnect_timer_id;
timer_t timeout_timer_id;

int main(int argc, char **argv)
{
    /* do main loop work */
    if(disconnected()) {
        /*IF TIMEOUT SET, SKIP, IF OK, RESET*/
        if(timeout_set != 1) {
            "Schedule Alarm"
            makeTimer("Timeout Timer", &timeout_timer_id, 600,0);
            timeout_set = 1;
        } else {
              "Timeout alarm already set..";
        }
        reconnect();
    }
}

void reconnect()
{
    pid = fork();

    if (pid >= 0) {
        /*Successful fork*/
        if (pid == 0) {

            rv = attempt_reconnect;               
            if (rv == 0) {
                /*Notify sig_child Success*/
                exit(0);
            } else {
                /*Notify sig_child Fail*/
                exit(1);
            }
        }
    } 
}

void sig_child(int signum)
{
    if(fork returned success) {
        set flag to continue network stuff
    }
    else {
        "Reconnect fail, retrying in 20 seconds...";
        makeTimer("Reconnect Timer", &reconnect_timer_id, 20,0);
    }
}

static void
timerHandler( int sig, siginfo_t *si, void *uc )
{
    timer_t *tidp;
    tidp = si->si_value.sival_ptr;
    if ( *tidp == timeout_timer_id ) {

        if(state != STATE_CONNECTED) {
            "Timeout alarm received, not connected to server, exiting..."
            exit(0);
        } else {
            "Timeout alarm received, connected to server, continuing..."
            timeout_set = 0;
        }

    } else if ( *tidp == reconnect_timer_id ) {
        "Reconnect alarm received, retrying...";
        reconnect();
    }
}

static int
makeTimer( char *name, timer_t *timerID, int expireSeconds, int intervalSeconds )
{
    struct sigevent         te;
    struct itimerspec       its;
    struct sigaction        sa;
    int sigNo = SIGRTMIN;

    /* Set up signal handler. */
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = timerHandler;
    sigemptyset(&sa.sa_mask);

    if (sigaction(sigNo, &sa, NULL) == -1) {
          "Failed to setup signal handling for" *name;

        return(-1);
    }

    /* Set and enable alarm */
    te.sigev_notify = SIGEV_SIGNAL;
    te.sigev_signo = sigNo;
    te.sigev_value.sival_ptr = timerID;
    timer_create(CLOCK_REALTIME, &te, timerID);
    its.it_interval.tv_sec = intervalSeconds;
    its.it_interval.tv_nsec =0;

    its.it_value.tv_sec = expireSeconds;
    its.it_value.tv_nsec = 0;
    timer_settime(*timerID, 0, &its, NULL);
    return(0);
}
like image 136
TomSelleck Avatar answered Oct 27 '25 10:10

TomSelleck


One idea could be not to use alarm( ) but create timers as subprocesses that kill the main processes with two different signals after sleep():

void timer( int nsec, int signum )
{
    pid_t pid = getpid();
    if( fork() > 0 ) {
        sleep( nsec );
        kill( pid, signum );
        exit( 0 );
    }
}

By using two different signals, (e.g. SIGUSR1 for the short timer and SIGUSR2 for the long one) you can have a signal handler like that:

void sig_timer( int signum )
{
    if( signum == SIGUSR1 ) {
        // reconnect
    } else if( signumm == SIGUSR2 ) {
        if( !reconnected )
            exit( 11 );
    } 
}
like image 34
Ingo Leonhardt Avatar answered Oct 27 '25 11:10

Ingo Leonhardt