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);
}

Reply via email to