Communication with child process using pipes and epoll

独自空忆成欢 提交于 2019-12-11 11:50:35

问题


I'm writing an application which will start some processes (fork and exec) depending on users input and should inform user about every error in those processes (Print some internal ID + message written to stderr by the process). I'd also like to detect exiting processes. I'm facing the problem, that I cannot receive data after executing execl() command. Test data is received in epoll_wait loop, but process called by exec seems to not write anything to stderr nor even end (I don't know if I'm correct, but I expect pipe to be readable after it's writing end has been closed, when process exited). Some code reproducing my problem:

#include <unistd.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <thread>
#include <stdlib.h>
#include <sys/wait.h>

thread_local int epoll;

int do_fork()
{
    int pip[2];
    pipe(pip);
    int pid = fork();
    if (pid == 0)
    {
        dup2(pip[1], STDERR_FILENO);
        close(pip[0]);  
        close(pip[1]);  
        write(STDERR_FILENO, "test data", 10);
        sleep(3);
        //exit(1);
        execl("tr", "tr", NULL); //this process will end immediately and write error on stderr
    }
    else
    {
        printf("PID %d\n", pid);
        close(pip[1]);
        epoll_event ev;
        ev.data.fd = pip[0];
        ev.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
        printf("pipe %d\n", pip[0]);
        epoll_ctl(epoll, EPOLL_CTL_ADD, pip[0], &ev);
    }
}

int thread()
{
    epoll_event events[10];
    epoll = epoll_create1(0);

    epoll_event ev;
    ev.data.fd = STDIN_FILENO;
    ev.events = EPOLLIN;
    epoll_ctl(epoll, EPOLL_CTL_ADD, STDIN_FILENO, &ev);

    char buf[1000];
    while(true)
    {
        int r = epoll_wait(epoll, events, 10, -1);
        printf("r = %d\n", r);
        for (int i = 0; i < r; ++i)
        {
            if(events[i].data.fd == STDIN_FILENO)
            {
                int t = read(events[i].data.fd, buf, 1000);
                do_fork();
            }
            else
            {
                printf("event? %d\n", events[i].events);
                printf("pipe %d\n", events[i].data.fd);
                int t = read(events[i].data.fd, buf, 1000);
                printf("t == %d\n", t);
                if(t == -1)
                    printf("errno: %d\n", errno);
                if(events[i].events & EPOLLHUP || t == 0)
                {
                    epoll_ctl(epoll, EPOLL_CTL_DEL, events[i].data.fd, NULL);
                    if(close(events[i].data.fd) == -1)
                        printf("cannot close fd\n");
                }
            }
        }

    }
    return 0;
}

int main()
{
    std::thread t{thread};
    t.detach();
    while(true);
}

来源:https://stackoverflow.com/questions/37375047/communication-with-child-process-using-pipes-and-epoll

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!