Thanks Bryan. I take back what I said. epoll_* does not ignore epoll_event.data passed in.
I managed to reproduce the issue with a program rewritten from yours: # gcc myepoll.c # ./a.out EPOLL_CTL_ADD: fd = 4, ptr = fffffd7fffdffba0 writing to pipe fd 5 written 6 bytes to fd 5 Got an event on fd 4, events = 1, ptr = fffffd7fffdffba0 got 6 bytes from fd 5 EPOLL_CTL_DEL: fd = 4, ptr = fffffd7fffdffba0 EPOLL_CTL_ADD: fd = 4, ptr = fffffd7fffdffb80 writing to pipe fd 5 written 6 bytes to fd 5 Got an event on fd 4, events = 1, ptr = fffffd7fffdffba0 got 6 bytes from fd 5 As it indicates, the issue here is that after EPOLL_CTL_DEL, and then EPOLL_CTL_ADD of the same file descriptor with a new data.ptr, epoll_wait still returns an old pointer. C code is attached for your reference. Thanks very much, -Youzhong On Wed, Jul 30, 2014 at 5:38 PM, Bryan Cantrill <bryancantr...@gmail.com> wrote: > > Seems like a bug, but not sure I entirely understand: there may be some > edge conditions where data specified in the "data" field of the epoll_event > structure via epoll_ctl() is not properly returned, but it's not true that > SmartOS simply ignores it. Take, for example, the following program: > > https://us-east.manta.joyent.com/bcantrill/public/epoll_add.c > > (It's essentially the most basic possible use of epoll(5).) Compiling > that program and running it yields (for me, anyway) the same result on > SmartOS as it does on Linux: > > $ ./epoll_add > writing to pipe > adding event... > parent: got an event on fd 4 > > I certainly don't doubt that there's a bug here -- I just don't think it's > quite as broad as you're implying; could you point me to the core file for > Samba and/or instructions as to how to reproduce the issue? > > - Bryan > > > > On Wed, Jul 30, 2014 at 2:08 PM, Youzhong Yang via smartos-discuss < > smartos-discuss@lists.smartos.org> wrote: > >> Hi All, >> >> The man page of epoll_ctl says: >> >> The data field specifies the datum to be associated with the >> event and will be returned via epoll_wait(3C). The events field >> denotes both the desired events (when specified via epoll_ctl()) >> and the events that have occurred (when returned via >> epoll_wait(3C)). >> >> This does not seem to be the case and is not compatible with Linux's >> implementation. Recently I tried to compile Samba 4.1.10 on smartos and >> 'net ads join' just crashes. Samba uses epoll_event.data.ptr to keep track >> of its tevent_fd data but epoll_ctl() on smartos simply ignores it and does >> not keep a copy of the 'data' structure and returns it when epoll_wait is >> called. >> >> Can I assume this is an implementation specific bug? >> >> Thanks, >> >> -Youzhong >> *smartos-discuss* | Archives >> <https://www.listbox.com/member/archive/184463/=now> >> <https://www.listbox.com/member/archive/rss/184463/21493597-819305a5> | >> Modify >> <https://www.listbox.com/member/?&> >> Your Subscription <http://www.listbox.com> >> > > ------------------------------------------- smartos-discuss Archives: https://www.listbox.com/member/archive/184463/=now RSS Feed: https://www.listbox.com/member/archive/rss/184463/25769125-55cfbc00 Modify Your Subscription: https://www.listbox.com/member/?member_id=25769125&id_secret=25769125-7688e9fb Powered by Listbox: http://www.listbox.com
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <signal.h> #include <limits.h> #include <pthread.h> #include <strings.h> #include <sys/epoll.h> struct tevent_fd { int fd; void *private_data; void *additional_data; }; void add_or_del(int epoll_fd, int fd, int op, int events, void *ptr) { struct epoll_event evt; if(op != EPOLL_CTL_ADD && op != EPOLL_CTL_DEL){ printf("only handle EPOLL_CTL_ADD or EPOLL_CTL_DEL\n"); return; } bzero(&evt, sizeof (evt)); evt.events = events; evt.data.ptr = ptr; if (epoll_ctl(epoll_fd, op, fd, &evt) < 0) perror("epoll_ctl"); else printf("%s: fd = %d, ptr = %p\n", (op == EPOLL_CTL_ADD) ? "EPOLL_CTL_ADD" : "EPOLL_CTL_DEL", fd, ptr); return; } void wait_event(int epoll_fd, int timeout) { struct epoll_event evt; int ret; bzero(&evt, sizeof(evt)); ret = epoll_wait(epoll_fd, &evt, 1, timeout); if(ret == 1) { printf("Got an event on fd %d, events = %d, ptr = %p\n", ((struct tevent_fd*)evt.data.ptr)->fd, evt.events, evt.data.ptr); } else if(ret == -1) { perror("epoll_wait"); } else { printf("No event!\n"); } } int main(int argc, char **argv) { int pipefds[2]; int epoll_fd; struct tevent_fd fde1, fde2; char buf[64]; int nbytes; if ((epoll_fd = epoll_create1(EPOLL_CLOEXEC)) == -1) { perror("epoll_create1"); return (1); } if (pipe(pipefds) < 0) { perror("pipe()"); return (1); } bzero(&fde1, sizeof(fde1)); fde1.fd = pipefds[0]; add_or_del(epoll_fd, pipefds[0], EPOLL_CTL_ADD, EPOLLIN, &fde1); printf("writing to pipe fd %d\n", pipefds[1]); nbytes = write(pipefds[1], "foo!\n", 6); printf("written %d bytes to fd %d\n", nbytes, pipefds[1]); wait_event(epoll_fd, 5000); nbytes = read(pipefds[0], buf, 64); printf("got %d bytes from fd %d\n", nbytes, pipefds[1]); add_or_del(epoll_fd, pipefds[0], EPOLL_CTL_DEL, EPOLLIN, &fde1); bzero(&fde2, sizeof(fde2)); fde2.fd = pipefds[0]; add_or_del(epoll_fd, pipefds[0], EPOLL_CTL_ADD, EPOLLIN, &fde2); printf("writing to pipe fd %d\n", pipefds[1]); nbytes = write(pipefds[1], "foo!\n", 6); printf("written %d bytes to fd %d\n", nbytes, pipefds[1]); wait_event(epoll_fd, 5000); nbytes = read(pipefds[0], buf, 64); printf("got %d bytes from fd %d\n", nbytes, pipefds[1]); return(0); }