Usually on linux when we wish to use epoll, we first create a epfd, and then register fd and events to it.
int fd=open(...) int epfd=epoll_create(1); epoll_event ev,events[1]; ev.data.fd=fd;//already registered ev.events=EPOLLIN|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev);//still need to specify fd?
Above is a common example I found from internet. It works, but problem is:
ev.data.fd=fd here I already have my “fd” assigned to ev structure.
epoll_ctl still requires the 3rd parameter of this fd.
While the 4th parameter of epoll_ctl already contain information about this fd. This is why I think it’s redundant.
Any explanations?
Advertisement
Answer
Your ev.data
is a union. You can use the fd
member, but you don’t have to. You can also stick other data in there.
The point of ev.data
is of course that that‘s the data you get back when the event fires, so you need some way of relating that to the original file descriptor. Writing that very file descriptor into the fd
variant is one simple way to achieve that, but other solutions exist.
One popular example is to define an abstract class Fd
, derive concrete classes from it for particular purposes, and then write the upcast base pointer, converted to void*
, into ev.data.ptr
. On receipt of the event, you cast ev.data.ptr
back to Fd*
and invoke a suitable virtual member function to handle the event.