title: Communication with child process using pipes and epoll
body: <p>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:</p>
  
  <pre><code>#include &lt;unistd.h&gt;
  #include &lt;sys/epoll.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;thread&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;sys/wait.h&gt;
  
  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], &amp;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, &amp;ev);
  
      char buf[1000];
      while(true)
      {
          int r = epoll_wait(epoll, events, 10, -1);
          printf("r = %d\n", r);
          for (int i = 0; i &lt; 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 &amp; 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);
  }
  </code></pre>