2

我使用 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 返回 1 之前,使用对象和方法指针的调用:*pt2Object.*fpt("timeouted before sigsetjmp") 是可以的,但是在 sigsetjmp 返回 1 之后,此调用失败。检查变量的状态后,我注意到对象指针“pt2Object”仍然可以,但方法指针“fpt”似乎有所不同。

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

你们能帮我解决这个问题吗?非常感谢!

4

1 回答 1

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
于 2013-03-07T04:37:08.573 回答