Я использую пару 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».
Не могли бы вы, ребята, помочь мне решить эту проблему. Спасибо!
Как указывает 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
Других решений пока нет …