Question

I have this school project and it is about using setjmp and longjmp to do imprecise calculations. The program starts a timer that will signal a signal handler.

Before the timer expires, there is some iterative calculation(for demo purposes, just a loop doing nothing useful). At the beginning of this loop there is a setjmp call, and in the signal handler there is a longjmp call. This basically forces the loop to stop mid calculation and run the signal handler where it calls longjmp.

The problem I am having is that whenever the calculation portion is very short, I seem to segfault fairly consistently, however when the calculation portion is long(inner loop has many iterations), it runs just fine(have not run into a segfault yet). Obviously the segfault must be occuring in the areas surrounding that calculation section, but I cannot figure out where it is coming from as debugging changes things as does using print statements.

Here is the code I have:

#include <iostream>
#include <signal.h>
#include <sys/time.h>
#include <setjmp.h>
#include <errno.h>
#include <stdlib.h>

jmp_buf env;


static void usr_timer_tick(int signal)
{
    if(signal == SIGALRM)
    {
        longjmp(env, 1);
    }
}


/*Program Description
 * This program first sets up the timer to signal usr_timer_tick
 * every 1 second on the SIGALRM signal. It then proceeds to do an iterated calculation three times.
 * An infinite loop calls setjmp and when 0 is returned, continues doing
 * a calculation on temp. After an iteration is complete, the result of
 * the iteration is saved into finalResult after blocking SIGALRM to
 * make the saving of the result atomic.
 *
 * Once the signal handler(usr_timer_tick) is triggered, it calls longjmp which forces
 * setjmp to return a non-zero value, which causes the main function to break out
 * of the infinite loop and start a new calculation...this is done a total of 3
 * times for demonstration purposes.
 */
int main(int argc, char **argv)
{

    //init timer using setitimer..real mode
    int which = ITIMER_REAL;
    struct itimerval value;
    struct sigaction sact;
    sigset_t newmask, oldmask;
    sigemptyset( &newmask );
    sigemptyset( &oldmask );
    sigaddset(&newmask, SIGALRM);

    sact.sa_flags = 0;
    sact.sa_handler = usr_timer_tick;
    sigaction( SIGALRM, &sact, NULL );
//    value.it_interval.tv_sec = 0;        /* One second */
//    value.it_interval.tv_usec = 0;
//    value.it_value.tv_sec = 1;           /* One second */
//    value.it_value.tv_usec = 0;
//
//    setitimer(which, &value, NULL);



    double finalResult = 0;
    int loopcount = 0;
    double tempResult = 0;
    for(int j = 0; j < 10; j++)
    {
        loopcount = 0;


            std::cout << "Run " << j << " begin loop "
            << loopcount << "\n";


            if(setjmp(env) == 0)
            {   //timer not hit yet

                //sigprocmask(SIG_BLOCK, &newmask, NULL);
                value.it_interval.tv_sec = 0;        /* One second */
                value.it_interval.tv_usec = 0;
                value.it_value.tv_sec = 1;           /* One second */
                value.it_value.tv_usec = 0;

                setitimer(which, &value, NULL);

                //sigprocmask(SIG_SETMASK, &oldmask, NULL);
                for(;;)
                {
                    //Do some random calculations
                    for(int i = 0; i < 1; i++)
                    {
                        tempResult = tempResult + .001;
                    }

                    //block signal from arriving and save to finalResult
                    if(sigprocmask(SIG_BLOCK, &newmask, NULL) < 0) exit(-1);
                    finalResult = tempResult;
                    std::cout << "Run " << j << " complete loop "
                        << loopcount << " result = " << finalResult<< "\n";
                    loopcount++;
                    if(sigprocmask(SIG_SETMASK, &oldmask, NULL)< 0) exit(errno);
                }
            }
            else
            {
                //timer signal arrived, print the final result and get out of loop
                std::cout << "***Run " << j << " killed on loop "
                        << loopcount << " result = "<< finalResult << "\n";
                sigprocmask(SIG_SETMASK, &oldmask, NULL);
                //break;
            }



    }
    return 0;
}

I understand some of you may not agree that longjmp should be used in a signal handler, but this is the way my professor said to do it. Also, it should be noted that I do unblock SIGALRM after the longjmp is called(see else statement of main).

Looking at dmesg I get:

 [121395.233842] cppapplication_[17397]: 
segfault at 2 ip b74656f6 sp bfbb5abc 
error 6 in libc-2.12.1.so[b743b000+157000

]

Was it helpful?

Solution

You can't use ´longjmp´ to exit from an asynchronous event like a timer. It is only designed to save and restore registers and the stack pointer that are saved by the normal calling-convention.

Side note: Consider using the volatile keyword on your local variables, as specified in 7.13.2.1:

All accessible objects have values, and all other components of the abstract machine have state, as of the time the longjmp function was called, except that the values of objects of automatic storage duration that are local to the function containing the invocation of the corresponding setjmp macro that do not have volatile-qualified type and have been changed between the setjmp invocation and longjmp call are indeterminate.

OTHER TIPS

Your signal handler is going to call longjmp, so the jump target had better be valid. That means, call setjmp first, then sigaction and setitimer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top