title: Linux epoll syscall, waiting though data available
body: <p>Testing Linux syscall <strong>epoll</strong> using a simple parent-child program.</p>
  
  <p><strong>Expected behaviour</strong></p>
  
  <p>As the child writes a no every second, the parent should read it from the pipe and write a no every second to stdout.</p>
  
  <p><strong>Actual behaviour</strong></p>
  
  <p>The parent waits till the child writes all the nos, and then reads all data from pipe and writes to stdout. Verified by doing strace on parent. It blocks in epoll_wait.</p>
  
  <p><a href="https://github.com/tuxuday5/Samples" rel="nofollow noreferrer">please check README in github more information</a></p>
  
  <p><strong>Parent</strong></p>
  
  <pre><code>#define _GNU_SOURCE
  #include &lt;stdio.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;error.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;string.h&gt;
  #include &lt;sys/wait.h&gt;
  #include &lt;sys/epoll.h&gt;
  
  #include &lt;sys/types.h&gt;
  #include &lt;sys/stat.h&gt;
  #include &lt;fcntl.h&gt;
  
  #define NAMED_FIFO "aFifo"
  
  static void set_nonblocking(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
      perror("fcntl()");
      return;
    }
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
      perror("fcntl()");
    }
  }
  
  void errExit(char *msg) {
    perror(msg);
    exit(-1);
  }
  
  void printArgs(char **argv,char **env) {
    for(int i=0;argv[i];i++)
      printf("argv[%d]=%s\n",i,argv[i]);
  
    for(int i=0;env[i];i++)
      printf("env[%d]=%s\n",i,env[i]);
  }
  
  void PrintNos(short int max,char *name) {
    int fifo_fd,rVal;
    int bSize=2;
    char buffer[bSize];
  
    fifo_fd = open(NAMED_FIFO,O_RDONLY);
    if(fifo_fd&lt;0)
      errExit("open");
  
    for(short int i=0;i&lt;max;i++) {
      rVal = read(fifo_fd,buffer,bSize);
      if(rVal != bSize)
        errExit("read");
      printf("%03d\n",i);
    }
  }
  
  int main(int argc, char *argv[],char *env[]) {
    //int pipe_fds_child_stdin[2] ;
    int pipe_fds_child_stdout[2] ;
    pid_t child_id ;
  
    //if( pipe(pipe_fds_child_stdin) &lt; 0 )
    //  errExit("pipe");
  
    if( pipe(pipe_fds_child_stdout) &lt; 0 )
      errExit("pipe");
  
    child_id = fork();
  
    if( child_id &gt; 0 ) {
      const int MAX_POLL_FDS = 2;
      const int BUF_SIZE = 4;
  
      size_t readSize;
      char buf[BUF_SIZE];
      int status;
  
      int epoll_fd;
      int nfds ;
      struct epoll_event e_e, e_events[MAX_POLL_FDS];
  
      memset(e_events,'\0',sizeof(e_events));
      memset(&amp;e_e,'\0',sizeof(e_e));
      //close(pipe_fds_child_stdin[0]);
      close(pipe_fds_child_stdout[1]);
  
      epoll_fd = epoll_create1(0);
      if(epoll_fd &lt; 0)
        errExit("epoll_create1");
  
      e_e.data.fd = pipe_fds_child_stdout[0];
      e_e.events  = EPOLLIN;
  
      if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_fds_child_stdout[0], &amp;e_e) &lt; 0)
        errExit("epoll_ctl");
  
      while(1) {
        nfds = epoll_wait(epoll_fd, e_events,MAX_POLL_FDS,-1);
        if( nfds &lt; 0)
          errExit("epoll_wait");
  
        for(int i=0;i&lt;nfds;i++) {
          if( e_events[i].data.fd == pipe_fds_child_stdout[0]) {
            if( e_events[i].events &amp; EPOLLIN) {
              readSize = read(pipe_fds_child_stdout[0],buf,BUF_SIZE);
              if( readSize == BUF_SIZE ) {
                write(STDOUT_FILENO,buf,BUF_SIZE);
              } else if(readSize == 0) { // eof
                errExit("readSize=0");
              } else {
                errExit("read");
              }
            } else if( e_events[i].events &amp; EPOLLHUP) {
              printf("got EPOLLHUP on pipefd\n");
              wait(&amp;status);
              exit(0);
            } else {
              errExit("Unexpected event flag returned by epoll_wait on waited fd");
            }
          } else  {
            errExit("epoll_wait returned non-awaited fd");
          }
        }
      }
    } else if( child_id == 0 ) {
      close(0);
      close(1);
      //close(pipe_fds_child_stdin[1]);
      close(pipe_fds_child_stdout[0]);
  
      //dup2(pipe_fds_child_stdin[0],0);
      dup2(pipe_fds_child_stdout[1],1);
  
      execvpe(argv[1],&amp;(argv[1]),env);
      //PrintNos(100,"P");
      //errExit("execvp");
    } else {
      errExit("fork");
    }
  }
  </code></pre>
  
  <p><strong>Child</strong></p>
  
  <pre><code>import sys
  import time
  import os
  #f=open("aFifo",'r')
  for x in range(10):
      #try:
      #    val = f.read(2)
      #except Exception as e:
      #    raise 
      time.sleep(1)
      print(f'{x:03d}')
  </code></pre>