首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用setjmp longjmp时的Segfaulting

使用setjmp longjmp时的Segfaulting
EN

Stack Overflow用户
提问于 2011-03-31 01:45:01
回答 2查看 1.3K关注 0票数 1

我有一个学校项目,它是关于使用setjmp和longjmp来做不精确的计算。该程序启动一个定时器,该定时器将向信号处理器发出信号。

在计时器到期之前,会进行一些迭代计算(出于演示目的,只是一个没有任何用处的循环)。在这个循环的开始有一个setjmp调用,在信号处理程序中有一个longjmp调用。这基本上会迫使循环停止mid计算,并在调用longjmp的地方运行信号处理程序。

我遇到的问题是,每当计算部分非常短时,我似乎都相当一致地出现了分段故障,但是当计算部分很长时(内部循环有许多迭代),它运行得很好(还没有遇到分段故障)。显然,段错误肯定发生在计算部分周围的区域,但我不知道它是从哪里来的,因为调试会改变事情,就像使用print语句一样。

下面是我的代码:

代码语言:javascript
复制
#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;
}

我知道你们中的一些人可能不同意在信号处理程序中使用longjmp,但这是我的教授说的方法。另外,需要注意的是,在调用longjmp之后,我确实取消了对SIGALRM的阻塞(参见main的else语句)。

看看dmesg,我得到了:

代码语言:javascript
复制
 [121395.233842] cppapplication_[17397]: 
segfault at 2 ip b74656f6 sp bfbb5abc 
error 6 in libc-2.12.1.so[b743b000+157000

]

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-03-31 03:35:28

你不能使用“longjmp”来退出像计时器这样的异步事件。它只设计用来保存和恢复寄存器和堆栈指针,这些寄存器和堆栈指针是由正常调用约定保存的。

附注:请考虑在本地变量上使用volatile关键字,如7.13.2.1中所述:

在调用longjmp函数时,所有可访问的对象都有值,抽象机的所有其他组件都有状态,除了自动存储持续时间的对象的值是不确定的,这些对象是包含相应setjmp宏的调用的函数的本地对象,这些对象不具有setjmp类型,并且在setjmp调用和longjmp调用之间发生了更改。

票数 1
EN

Stack Overflow用户

发布于 2011-03-31 01:50:20

您的信号处理程序将调用longjmp,因此跳转目标最好是有效的。这意味着,首先调用setjmp,然后调用sigactionsetitimer

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5490038

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档