Восстановление среды с помощью sigsetjmp и longsetjmp

Я использую пару 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».

Не могли бы вы, ребята, помочь мне решить эту проблему. Спасибо!

2

Решение

Как указывает Potatoswatter, использование будильника для задержки longjmp слишком умный, чтобы на него можно было положиться. Сначала вы должны вызвать sigsetjmp. Это должно случиться до Вы пытаетесь вернуться туда.

Единственный способ sigsetjmp или же setjmp будет работать в соответствии с этим псевдокодом.

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
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]