В настоящее время я работаю над проектом, использующим сильно модифицированную версию 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);
}
Как уже упоминалось в комментариях, используя 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
функция может быть не нужна вообще.
Других решений пока нет …