通过sigsetjmp和longsetjmp恢复环境

时间:2013-03-07 04:32:36

标签: c++ context-switch

我正在使用sigsetjmp和singlongjmp与SIGALARM中断系统调用,如下面的代码所示

//data of Alarm_interrupter
void (TClass::*fpt)(const char*);   // pointer to member function
TClass* pt2Object;                  // pointer to object
===================================================
//for timeout processing
static sigjmp_buf jmpbuf;
static void recvfrom_alarm(int) {
    siglongjmp(jmpbuf, 1);
}
======================================================
void Alarm_interrupter::start_timeout() {
    signal(SIGALRM, recvfrom_alarm);
    alarm(timeout);
    (*pt2Object.*fpt)("timeouted before sigsetjmp"); //this call works OK
    if (sigsetjmp(jmpbuf,1) != 0) {
        //at this point, pt2Object is still OK,
        //but fpt seems to point to nothign.
        (*pt2Object.*fpt)("timeouted after sigsetjmp");
    }
    return;
}
==============================================================

在sigsetjmp returnn 1之前,使用object和方法指针调用:* pt2Object。* fpt(“sigsetjmp之前的时间”)是正常的,但是在sigsetjmp返回1之后,此调用失败。 检查变量状态后,我注意到对象指针“pt2Object”仍然是Ok,但方法指针“fpt”似乎不同。

我认为一个可能的原因是sigsetjmp无法恢复整个早期环境,其中包括方法指针“fpt”。

你可以帮我解决这个问题。非常感谢!

1 个答案:

答案 0 :(得分:1)

正如Potatoswatter指出的那样,使用闹钟推迟longjmp是太聪明了,无法依靠。你必须先调用'sigsetjmp'。它必须在之前发生你试图返回那里。

sigsetjmpsetjmp唯一可行的方法是遵循此伪代码。

if (sigsetjmp(...) != 0) {
    //  Error handling code
}
// code that might call siglongjmp to bail out to Error handling code

你知道,必须执行一次才能执行上下文的保存。这会初始化jmpbuf。如果您在执行前没有调用longjmp而调用setjmp,则无法预测该行为。

此外,longjmp将倾向于删除您可能尝试使用的任何局部变量。

int var = 3;
var = 2;
if (sigsetjmp(...) != 0) {
    //  Error handling code
    printf("%d", var); // could print 2, 3 or even "potato". Local vars get trashed.
}
// code that might call siglongjmp to bail out to Error handling code

所以你真的想在 *setjmp之后做一切有趣的事情。

int var = 3;
if (sigsetjmp(...) != 0) {
    //  Error handling code
    var = 2;
    printf("%d", var); // now you know it's 2
}
// code that might call siglongjmp to bail out to Error handling code

如果希望它在*longjmp中存活,则需要将其标记为volatile

volatile int var = 3;
var = 2;
if (sigsetjmp(...) != 0) {
    //  Error handling code
    printf("%d", var); // probably 2
}
// code that might call siglongjmp to bail out to Error handling code

即使这可能还不够。它可能需要被称为sigatomic_t或类似的东西。但尽量不要像那样疯狂。

int var = 3;
memcpy(var, (int *){2}); //memcpy is pretty reliable (C99ism: immediate pointer))
if (sigsetjmp(...) != 0) {
    //  Error handling code
    printf("%d", var); // probably 2
}
// code that might call siglongjmp to bail out to Error handling code