1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

tevent: Start to fix the epoll backend to support 2 fd events on the same fd correctly.

Add a utility function epoll_add_multiplex_fd() and
a new flag EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX.

This will be called by epoll_add_event() to merge two
fde events with the same file descriptor.

Signed-off-by: Jeremy Allison <jra@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:
Jeremy Allison 2013-02-14 13:50:56 -08:00
parent 7ef688c1dd
commit e4b496cc09

View File

@ -4,7 +4,8 @@
main select loop and event handling - epoll implementation
Copyright (C) Andrew Tridgell 2003-2005
Copyright (C) Stefan Metzmacher 2005-2009
Copyright (C) Stefan Metzmacher 2005-2013
Copyright (C) Jeremy Allison 2013
** NOTE! The following LGPL license applies to the tevent
** library. This does NOT imply that all of Samba is released
@ -48,6 +49,7 @@ struct epoll_event_context {
#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1)
#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2)
#define EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX (1<<3)
#ifdef TEST_PANIC_FALLBACK
@ -263,6 +265,99 @@ static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
epoll_ev->panic_state = NULL;
}
/*
epoll cannot add the same file descriptor twice, once
with read, once with write which is allowed by the
tevent backend. Multiplex the existing fde, flag it
as such so we can search for the correct fde on
event triggering.
*/
static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev,
struct tevent_fd *add_fde)
{
struct epoll_event event;
struct tevent_fd *mpx_fde;
int ret;
/* Find the existing fde that caused the EEXIST error. */
for (mpx_fde = epoll_ev->ev->fd_events; mpx_fde; mpx_fde = mpx_fde->next) {
if (mpx_fde->fd != add_fde->fd) {
continue;
}
if (mpx_fde == add_fde) {
continue;
}
break;
}
if (mpx_fde == NULL) {
tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
"can't find multiplex fde for fd[%d]",
add_fde->fd);
return -1;
}
if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
/* Logic error. Can't have more than 2 multiplexed fde's. */
tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
"multiplex fde for fd[%d] is already multiplexed\n",
mpx_fde->fd);
return -1;
}
/*
* The multiplex fde must have the same fd, and also
* already have an epoll event attached.
*/
if (!(mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) {
/* Logic error. Can't have more than 2 multiplexed fde's. */
tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
"multiplex fde for fd[%d] has no event\n",
mpx_fde->fd);
return -1;
}
/* Modify the mpx_fde to add in the new flags. */
ZERO_STRUCT(event);
event.events = epoll_map_flags(mpx_fde->flags);
event.events |= epoll_map_flags(add_fde->flags);
event.data.ptr = mpx_fde;
ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, mpx_fde->fd, &event);
if (ret != 0 && errno == EBADF) {
tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
"EPOLL_CTL_MOD EBADF for "
"add_fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
add_fde, mpx_fde, add_fde->fd);
DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
mpx_fde->event_ctx = NULL;
DLIST_REMOVE(epoll_ev->ev->fd_events, add_fde);
add_fde->event_ctx = NULL;
return 0;
} else if (ret != 0) {
return ret;
}
/*
* Make each fde->additional_data pointers point at each other
* so we can look them up from each other. They are now paired.
*/
mpx_fde->additional_data = (struct tevent_fd *)add_fde;
add_fde->additional_data = (struct tevent_fd *)mpx_fde;
/* Now flag both fde's as being multiplexed. */
mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
/* we need to keep the GOT_ERROR flag */
if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR) {
add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
}
return 0;
}
/*
add the epoll event to the given fd_event
*/