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 <[email protected]>
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 <
> [email protected]> 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);
}