Потеря сигнала при открытии именованного канала в режиме блокировки - PullRequest
0 голосов
/ 05 апреля 2019

Справочная информация: Я сделал программу, в которой «родитель» создает 2 дочерних процесса (отправитель и получатель). Я реализовал дочерние элементы таким образом, что при сбое одного дочернего элемента он отправляет сигнал (SIGUSR2) родительскому элементу. Когда родитель получает сигнал, находит другой процесс (например, если «получатель» отправил сигнал, тогда родитель находит соответствующий процесс «отправителя») и отправляет ему сигнал SIGINT. После этого родитель создает 2 новых детей. Внутри дочернего обработчика сигнала для SIGINT я выполняю некоторую очистку (закрываю именованный канал, освобождаю память кучи и выхожу нормально). Я сделал дочерний «получатель», чтобы он всегда отправлял SIGUSR2 родителю, а затем выходил, так что родитель должен будет найти дочернего «отправителя», отправить ему сигнал и снова и снова создавать новых детей.

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

Итак, я открываю именованный канал в режиме блокировки, и "отправитель" застревает там. Согласно руководству open , когда сигнал получен в ожидании завершения открытия, функция возвращает -1, а errno устанавливается в EINTR. Но похоже, что открытый системный вызов никогда не дает сбой и сигнал никогда не принимается .

Таким образом, в обработчике сигнала родительского SIGUSR2 я посылаю следующий сигнал процессу «отправителя», который соответствует «получателю», который отправил сигнал:

int stat;
cout << "Going to kill " << pidINFO2->myPID << endl;
int ret = kill(pidINFO2->myPID,SIGINT);
if (ret==0) cout << "SIGNAL WAS SENT SUCCESSFULLY" <<endl;

waitpid(pidINFO2->myPID,&stat,0);
cout << "AFTER WAIT" << endl;

И это весь код отправителя ребенка код:

#include <iostream>
#include <cstring>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

using namespace std;

#include "interface.h"

char* input_dirName, *common_dirName, *myID, *syncID, *buflen;

void SIGINT_handler(int signo)
{
    cout << "INTO SENDER " << getpid() << " SIGNAL HANDLER" << endl;
    /* Remove the pipe we created */
        /* Make the name+path of the named pipe */
        char fifoNamePath[4096];
        strcpy(fifoNamePath,common_dirName);
        strcat(fifoNamePath,"/");
        strcat(fifoNamePath,myID);
        strcat(fifoNamePath,"_to_");
        strcat(fifoNamePath,syncID);
        strcat(fifoNamePath,".fifo");
        /* ------------------------------------ */
        unlink(fifoNamePath);
    /* -------------------------- */
    delete[] input_dirName;
    delete[] myID;
    delete[] syncID;
    delete[] common_dirName;
    delete[] buflen;

    exit(0);
}

int main(int argc, char* argv[])
{
     cout << "INTO SENDER CHILD -> " << getpid() << endl;

     struct sigaction term;
     term.sa_handler = SIGINT_handler;
     term.sa_flags = SA_RESTART;
     sigfillset(&term.sa_mask);
     if (sigaction(SIGINT, &term, NULL) == -1) {
             perror("sigaction");
             return EXIT_FAILURE;
     }

    common_dirName = new char[strlen(argv[1])+1];
    strcpy(common_dirName,argv[1]);
    input_dirName = new char[strlen(argv[2])+1];
    strcpy(input_dirName,argv[2]);
    myID = new char[strlen(argv[3])+1];
    strcpy(myID,argv[3]);
    syncID = new char[strlen(argv[4])+1];
    strcpy(syncID,argv[4]);
    buflen = new char[strlen(argv[5])+1];
    strcpy(buflen,argv[5]);


    /* Create and/or open the named pipes (FIFO) */
        /* Make the name+path of the named pipe */
        char fifoNamePath[4096];
        strcpy(fifoNamePath,common_dirName);
        strcat(fifoNamePath,"/");
        strcat(fifoNamePath,myID);
        strcat(fifoNamePath,"_to_");
        strcat(fifoNamePath,syncID);
        strcat(fifoNamePath,".fifo");
        /* ------------------------------------ */
        if (mkfifo(fifoNamePath,0777)!=0) //try to make the FIFO
        {
            if (errno != EEXIST) //if we get an error and that error is different than EEXIST, then we send a signal to the parent to try again with a new child
            {
                perror("Error: ");
                delete[] input_dirName;
                delete[] myID;
                delete[] syncID;
                delete[] common_dirName;
                delete[] buflen;
                kill(getppid(),SIGUSR2);
                exit(0);
            }
        }
        //if we don't get an error or if the error is EEXIST (which means that the fifo is already made by the other process) we open it

        cout << "before open in " << getpid() << endl;
        int fd;
        if ( (fd = open(fifoNamePath, O_WRONLY)) == -1) //we try to open the fifo "read-only" in BLOCKING mode
        {
            perror("Error: ");
            delete[] input_dirName;
            delete[] myID;
            delete[] syncID;
            delete[] common_dirName;
            kill(getppid(),SIGUSR2);
            unlink(fifoNamePath);
            exit(0);
        }
        cout << "Sender opened -> " << fifoNamePath << " on " << fd << endl;
        char buffer[50] = "SOMETHING";
        int rsize;
        if ( ( rsize = write(fd,&buffer,strlen(buffer)+1) )==-1)
        {
            perror("Error: ");
            exit(5);
        }
        close(fd);
    /* --------------------------- */

    cout << "send completed for " << syncID << endl;
    delete[] input_dirName;
    delete[] myID;
    delete[] syncID;
    delete[] common_dirName;
    delete[] buflen;
    kill(getppid(),SIGUSR1);
    exit(0);
}

Таким образом, я ожидал, что все дочерние «отправители» получат сигнал SIGINT от родителя, но похоже, что только первый созданный «отправитель» получает сигнал, а другие нет, хотя родитель показывает, что сигнал был успешно отправлен

Фактический вывод, который я получаю: (Они используют один и тот же терминал. Где бы он ни говорил INTO *** CHILD, это означает, что родитель создал 2 новых процесса)

[child]INTO SENDER CHILD -> 23410
[child]INTO RECEIVER CHILD -> 23409
[child]before open in 23410
[parent]The process -> 23409 terminated with an error!
[parent]Going to kill 23410
[parent]SIGNAL WAS SENT SUCCESSFULLY
[child]INTO SENDER 23410 SIGNAL HANDLER
[parent]AFTER WAIT
[child]INTO RECEIVER CHILD -> 23413
[child]INTO SENDER CHILD -> 23414
[child]before open in 23414
[parent]The process -> 23413 terminated with an error!
[parent]Going to kill 23414
[parent]SIGNAL WAS SENT SUCCESSFULLY

И терминал застрял там. Родитель заблокирован на waitpid , а дочерний элемент заблокирован на open (я полагаю, поскольку он напечатал «до открытия в 23414», но не сообщение после системного вызова open). Так почему же второй созданный «отправитель» не получил сигнал SIGINT от родителя, поскольку родитель сказал, что он был отправлен (SIGNAL WAS SENT SUCCESSFULLY).

Что я делаю не так?

...