Package: manpages
Version: 2.39-1

I think epoll(4)'s A9 has a problem.

       Q9     Do I need to continuously read/write an  fd  until  EAGAIN  when
              using the EPOLLET flag ( Edge Triggered behaviour ) ?

       A9     No  you don't. Receiving an event from epoll_wait(2) should sug-
              gest to you that such file descriptor is ready for the requested
              I/O  operation.  You  have simply to consider it ready until you
              will receive the next EAGAIN. When and how  you  will  use  such
              file  descriptor is entirely up to you. Also, the condition that
              the read/write I/O space is exhausted can be detected by  check-
              ing  the  amount  of  data  read/write  from/to  the target file
              descriptor. For example, if you call read(2) by asking to read a
              certain  amount  of  data  and read(2) returns a lower number of
              bytes, you can be sure to have exhausted the read I/O space  for
              such  file  descriptor.  Same  is  valid  when writing using the
              write(2) function.

The problem is the sentence about read(2):

  For example, if you call read(2) by asking to read a
  certain  amount  of  data  and read(2) returns a lower number of
  bytes, you can be sure to have exhausted the read I/O space  for
  such  file  descriptor.

When the waiting fd is a socket and other end sends some
data and half close it, epoll_wait notified EPOLLIN.
If client reads the data and the data is smaller than the
buffer length, the above condition met.  So epoll_wait
should be callable according to above description.  But
epoll_wait blocks indefinitely and doesn't notify EOF.

% cat tst.c 
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>

int main()
{
  int ret;
  int fds[2], r, w;
  int ep;
  struct epoll_event ev;
#define BUFLEN 4096
  char buf[BUFLEN];

  /* allocate socket pair */
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) { perror("socketpair"); 
exit(1); }
  r = fds[0];
  w = fds[1];

  /* write "abc" to writing side */
  ret = write(w, "abc", 3);
  if (ret == -1) { perror("write"); exit(1); }
  if (ret != 3) { fprintf(stderr, "unexpected write: %d\n", ret); exit(1); }

  /* half close on writing side */
  if (shutdown(w, SHUT_WR) == -1) { perror("shutdown"); exit(1); }

  /* allocate epoll queue */
  ep = epoll_create(1);
  if (ep == -1) { perror("epoll_create"); exit(1); }

  /* register the reading side socket in edge trigger style */
  ev.events = EPOLLIN|EPOLLET;
  ev.data.fd = r;
  ret = epoll_ctl(ep, EPOLL_CTL_ADD, r, &ev);

  /* first epoll_wait: it notifies some data ("abc") available. */
  ret = epoll_wait(ep, &ev, 1, -1);
  if (ret == -1) { perror("epoll_wait"); exit(1); }
  if (ret != 1) { fprintf(stderr, "unexpected epoll_wait: %d\n", ret); exit(1); 
}

  /* the notified event is just EPOLLIN.  (No EPOLLHUP) */
  if (ev.events != EPOLLIN) { fprintf(stderr, "unexpected events: %d\n", 
ev.events); exit(1); }

  /* consume "abc". */
  ret = read(r, buf, BUFLEN);
  if (ret == -1) { perror("read"); exit(1); }
  if (ret != 3) { fprintf(stderr, "unexpected read: %d\n", ret); exit(1); }

  /* According to A9 of epoll(4), ret < BUFLEN means the kernel I/O space of 
the r is exhausted.
   * So epoll_wait should be callable safely at this point.
   * But it blocks indefinitely. */
  ret = epoll_wait(ep, &ev, 1, -1);
  if (ret == -1) { perror("epoll_wait"); exit(1); }

  return 0;
}
% gcc tst.c      
% strace ./a.out 
...
socketpair(PF_FILE, SOCK_STREAM, 0, [3, 4]) = 0
write(4, "abc", 3)                      = 3
shutdown(4, 1 /* send */)               = 0
epoll_create(1)                         = 6
epoll_ctl(6, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLET, {u32=3, 
u64=12654713184490356739}}) = 0
epoll_wait(6, {{EPOLLIN, {u32=3, u64=12654713184490356739}}}, 1, -1) = 1
read(3, "abc", 4096)                    = 3
epoll_wait(6,      

The strace result shows that second epoll_wait blocks.

I think read(2) should be called until EAGAIN even if
read(2) doesn't fill up the buffer.

(The sample code doesn't use O_NONBLOCK, though.)
-- 
Tanaka Akira


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to