Я пытаюсь создать программу, которая делает следующее:
В качестве аргументов командной строки он получает пути к файлам FIFO. Предполагается, что мониторинг этих FIFO осуществляется с помощью epoll
API. Через FIFO гарантируется, что будут отправлены только числа с плавающей точкой. Выходные данные программы должны быть суммой чисел, отправленных через каждый FIFO (программа останавливается, когда сторона записи закрывает все файлы).
Прежде чем я начну с реального кода, вот макрос и функция, которые вы увидите во всей программе:
#define iAssert(cond, msg) crash(cond, msg, __LINE__)
void crash(bool cond, char * msg, int line){
if(!cond){
perror(msg);
fprintf(stderr, "at line %d\n", line);
exit(EXIT_FAILURE);
}
}
Это просто простой механизм утверждения, не имеющий отношения к самой проблеме.
В любом случае, сначала я выбираю количество FIFO, переданных через аргументы командной строки, и создаю дескриптор файла epoll
:
int numFifos = argc - 1;
int epollFileDesc = epoll_create(1);
iAssert(-1 != epollFileDesc, "epoll_create");
Затем я создаю массив дескрипторов файлов fifo и массив сумм, которые в следующем цикле я инициализирую нулем.
int * fifoFileDescriptors = malloc(numFifos * sizeof(int));
iAssert(NULL != fifoFileDescriptors, "malloc1");
float * localSums = malloc(numFifos * sizeof(float));
iAssert(NULL != localSums, "malloc 2");
Пока все хорошо, я думаю. Следующий цикл, кроме инициализации массива сумм, открывает FIFO, заполняет предыдущий массив файловых дескрипторов и регистрирует события.
for(int i = 0; i<numFifos; i++){
localSums[i] = 0.f;
int thisFd = open(argv[i+1], O_RDONLY | O_NONBLOCK);
iAssert(-1 != thisFd, "open");
fifoFileDescriptors[i] = thisFd;
FILE * thisFs = fdopen(thisFd, "r");
iAssert(NULL != thisFs, "fdopen");
DataPass registerThis;
registerThis.fifoIndex = i;
registerThis.file = thisFs;
struct epoll_event thisEvent;
thisEvent.events = 0;
thisEvent.events |= EPOLLIN;
thisEvent.data.ptr = (void *)®isterThis;
iAssert(-1 != epoll_ctl(epollFileDesc, EPOLL_CTL_ADD, thisFd, &thisEvent), "epoll_ctl");
}
Структура DataPass выглядит следующим образом:
typedef struct{
int fifoIndex;
FILE * file;
}DataPass;
Как вы можете видеть, я хочу получать потоки файлов вместо файловых дескрипторов, потому что их легче читать. Кроме того, я держу индекс FIFO, поэтому я знаю, какой это.
После этого я отслеживаю изменения:
int nOpen = numFifos;
struct epoll_event events[MAX_EVENTS];
while(nOpen){
int active = epoll_wait(epollFileDesc, events, MAX_EVENTS, -1);
iAssert(-1 != active, "epoll_wait");
for(int i = 0; i<active; i++){
struct epoll_event thisEvent = events[i];
if(thisEvent.events & EPOLLIN){
DataPass * thisData = (DataPass *)thisEvent.data.ptr;
//fifo with index thisData->fifoIndex has sent a message
float x;
while(1 == fscanf(thisData->file, "%f", &x)){
localSums[thisData->fifoIndex] += x;
}
}else if (thisEvent.events & (EPOLLERR | EPOLLHUP)){
//need to close this connection
DataPass * thisData = (DataPass *)thisEvent.data.ptr;
iAssert(-1 != epoll_ctl(epollFileDesc, EPOLL_CTL_DEL, fifoFileDescriptors[thisData->fifoIndex], NULL), "epoll_ctl del");
fclose(thisData->file);
close(fifoFileDescriptors[thisData->fifoIndex]);
nOpen--;
}
}
}
Макрос MAX_EVENTS
определен как 4.
После запуска этого (и использования сторонней программы для создания fifo и отправки значений через них) я получаю ошибку сегментации, которую мне удалось отследить до части fscanf
. Несмотря на то, что я выследил это, я все еще не понимаю, почему это вызывает.
Есть идеи?
Спасибо.