Как правильно обрабатывать SIGBUS, чтобы я мог продолжить поиск адреса?

В настоящее время я работаю над проектом, использующим сильно модифицированную версию linux, чтобы он мог работать с использованием действительно старой шины, которая нужна нашей компании. Большая часть обработки шины выполнена, у меня есть класс VMEAccess, который использует mmap для записи в определенную область / dev / mem, чтобы драйвер мог получить эти данные и перенести их на шину.

Моя проблема в том, что когда программа запускается, она не будет знать, где будет подчиненная плата, единственная информация, которую я могу иметь: если по данному адресу ничего нет, чтение там даст SIGBUS (ошибка шины), поэтому я решил использовать это, чтобы найти раба (в основном пробовал все адреса, пока у меня больше нет SIGBUS)

Я пробовал несколько вещей, в основном используя обработку сигналов, но после некоторых попыток я использую некоторые прыжки. Первый longjmp () работает, но при втором чтении у меня возникает ошибка шины, хотя мой обработчик должен предотвращать сбой программы.

Мой main.cpp:

#include <iostream>
#include <string>
#include <sstream>
#include <csignal>
#include <cstdlib>
#include <csignal>
#include <csetjmp>

#include "types.h"#include "VME_access.h"
VMEAccess *busVME;

int main(int argc, char const *argv[]);
void catch_sigbus (int sig);
void exit_function(int sig);

volatile BOOL bus_error;
volatile UDWORD offset;
jmp_buf env;

int main(int argc, char const *argv[])
{
sigemptyset(&sigBusHandler.sa_mask);

struct sigaction sigIntHandler;

sigIntHandler.sa_handler = exit_function;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;

sigaction(SIGINT, &sigIntHandler, NULL);

/*   */
struct sigaction sigBusHandler;

sigBusHandler.sa_handler = catch_sigbus;
sigemptyset(&sigBusHandler.sa_mask);
sigBusHandler.sa_flags = 0;

sigaction(SIGBUS, &sigBusHandler, NULL);

busVME = new VMEAccess(VME_SHORT);

offset = 0x01FE;

setjmp(env);
printf("%d\n", sigismember(&sigBusHandler.sa_mask, SIGBUS));

busVME->readWord(offset);
sleep(1);

printf("%#08x\n", offset+0xC1000000);

return 0;
}

void catch_sigbus (int sig)
{
offset++;
printf("%#08x\n", offset);
longjmp(env, 1);
}

void exit_function(int sig)
{
delete busVME;
exit(0);
}

1

Решение

Как уже упоминалось в комментариях, используя longjmp в обработчике сигналов это плохая идея. После выполнения прыжка из обработчика сигнала ваша программа по-прежнему остается в обработчике сигнала. Таким образом, вызов не асинхронно-безопасных функций приводит, например, к неопределенному поведению. С помощью siglongjmp не очень поможет здесь, цитируя man signal-safety:

Если обработчик сигнала прерывает выполнение небезопасной функции, а обработчик завершается с помощью вызова longjmp (3) или siglongjmp (3), и программа впоследствии вызывает небезопасную функцию, то поведение программы не определено.

И только для примера, это (siglongjmp) в прошлом вызывал некоторые проблемы в коде libcurl, смотрите здесь: ошибка: longjmp вызывает неинициализированный кадр стека

Я бы предложил использовать обычный цикл и изменить условие выхода в обработчике сигнала (вы в любом случае изменяете смещение там). Что-то вроде следующего (псевдокод):

int had_sigbus = 0;

int main(int argc, char const *argv[])
{
...
for (offset = 0x01FE; offset is sane; ++offset) {
had_sigbus = 0;
probe(offset);
if (!had_sigbus) {
// found
break;
}
}
...
}

void catch_sigbus(int)
{
had_sigbus = 1;
}

Таким образом, сразу становится очевидным, что цикл существует, и за всей логикой гораздо проще следовать. И там нет прыжков, поэтому он должен работать для более чем одного зонда 🙂 Но, очевидно, probe() должен обработать неудачный вызов (прерванный с SIGBUS) внутренне тоже — и, возможно, вернет ошибку. Если он возвращает ошибку, используя had_sigbus функция может быть не нужна вообще.

0

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

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

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