Reputation: 317
I'm using the couple sigsetjmp and singlongjmp with SIGALARM for interrupting a system call, which is illustrated in the following code
//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;
}
==============================================================
Before sigsetjmp returnn 1, the call using object and the method pointer: *pt2Object.*fpt("timeouted before sigsetjmp") is OK, but after sigsetjmp return 1, this call failed. After examining the state of variables, I noticed that the object pointer "pt2Object" is still Ok, but the method pointer "fpt" seems to different.
I think that one possible reasons for this is that sigsetjmp cannot restore the whole earlier environment, which includes the method pointer "fpt".
Could you guys help me fix this problem. Thanks so much!
Upvotes: 2
Views: 1053
Reputation: 19504
As Potatoswatter points out, using the alarm to delay the longjmp
is too clever to rely upon. You have to call 'sigsetjmp' first. It has to happen before you try to return there.
The only way sigsetjmp
or setjmp
will work is following this pseudocode.
if (sigsetjmp(...) != 0) {
// Error handling code
}
// code that might call siglongjmp to bail out to Error handling code
You see, it has to be executed once to perform the save of the context. This initializes the jmpbuf
. If you call longjmp
without having called setjmp
earlier in the execution, the behavior cannot be predicted.
Also, longjmp
will tend to obliterate any local variables you might try to use.
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
So you really want to do everything interesting after the *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
For any hope of it surviving across the *longjmp
, it needs to be marked 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
And even this may not be enough. It may need to be something called a sigatomic_t or something similar. But try not to need crazy stuff like that.
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
Upvotes: 1