[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] [nicholas.marriott@xxxxxxxxx: libevent and invalid fds]



On Tue, Feb 7, 2012 at 1:47 PM, Nicholas Marriott
<nicholas.marriott@xxxxxxxxx> wrote:
> Forwarding this message to ML at Nick's request...
>
> Hi
>
> You may remember a few months ago you fixed a problem with kqueue and
> EPIPE on pipes - I backported this fix to 1.4 and recently applied it to
> OpenBSD.
>
> However, this is causing problems with Google Chrome. From what we can
> gather it appears the problem is with EBADF - when kqueue returns EBADF
> for an fd, libevent fires the read callback, same as for EPIPE. This
> makes Chrome segfault somewhere in a huge mess of C++ that I can't
> figure my way through.

Hm.  So IIRC, we first added that EBADF in, it was (supposedly)
because some kqueue implementations produced EBADF in response to one
side of a pipe being closed while we were watching the other with
kqueue.

Do we know what platform or platforms this might have been?  I'm not
convinced atm that it's a real thing.  I've attached a small test
program that tries closing the read and the write side of a pipe, both
before and after the point where it is added to the kqueue. Can we
find any platform where it says "bad file descriptor"?  If not, your
fix would indeed seem to be the easy way around the present issue.

yrs,
--
Nick
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

void
dump_events(int r, const struct kevent *results)
{
  int i;
  printf("%d events:\n", r);
  for (i=0;i<r;++i) {
    printf("  %d: filter=%x flags=%x", (int)results[i].ident, results[i].filter, results[i].flags);
    if (results[i].flags & EV_ERROR) {
      printf(" error=%d [%s]", (int)results[i].data, strerror(results[i].data));
    }
    puts("");
  }
}

int
main(int argc, char **argv)
{
  int kqfd, pipefd[4][2], r, i;
  struct kevent changes[4];
  struct kevent results[16];
  struct timespec ts = {1,0};

  kqfd = kqueue();
  if (kqfd < 0) {
    perror("kqueue");
    return 1;
  }

  for (i=0;i<4;++i) {
    if (pipe(pipefd[i])<0) {
      perror("pipe");
      return 1;
    }
    printf("pipefd[%d] = {%d,%d}\n", i, pipefd[i][0], pipefd[i][1]);
  }

  memset(changes, 0, sizeof(changes));
  changes[0].ident = pipefd[0][0];
  changes[0].filter = EVFILT_READ;
  changes[0].flags = EV_ADD;
  changes[1].ident = pipefd[1][0];
  changes[1].filter = EVFILT_READ;
  changes[1].flags = EV_ADD;
  changes[2].ident = pipefd[2][1];
  changes[2].filter = EVFILT_WRITE;
  changes[2].flags = EV_ADD;
  changes[3].ident = pipefd[3][1];
  changes[3].filter = EVFILT_WRITE;
  changes[3].flags = EV_ADD;

  close(pipefd[0][1]);
  close(pipefd[2][0]);

  r = kevent(kqfd, changes, 4, results, 16, &ts);
  if (r<0) {
    perror("kevent");
    return 1;
  }
  dump_events(r, results);

  close(pipefd[1][1]);
  close(pipefd[3][0]);

  r = kevent(kqfd, NULL, 0, results, 16, &ts);
  if (r<0) {
    perror("kevent");
    return -1;
  }
  dump_events(r,results);

  return 0;
}