/* delete the epoll event for given fd_event */ static void epoll_del_event(struct std_event_context *std_ev, struct tevent_fd *fde) { struct epoll_event event; if (std_ev->epoll_fd == -1) return; fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; /* if there's no epoll_event, we don't need to delete it */ if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return; ZERO_STRUCT(event); event.events = epoll_map_flags(fde->flags); event.data.ptr = fde; epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event); fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; }
/* change the epoll event to the given fd_event */ static void epoll_mod_event(struct std_event_context *std_ev, struct tevent_fd *fde) { struct epoll_event event; if (std_ev->epoll_fd == -1) return; fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; ZERO_STRUCT(event); event.events = epoll_map_flags(fde->flags); event.data.ptr = fde; if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) { epoll_fallback_to_select(std_ev, "EPOLL_CTL_MOD failed"); } /* only if we want to read we want to tell the event handler about errors */ if (fde->flags & TEVENT_FD_READ) { fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; } }
/* delete the epoll event for given fd_event */ static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde) { struct epoll_event event; if (epoll_ev->epoll_fd == -1) return; fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; /* if there's no epoll_event, we don't need to delete it */ if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return; ZERO_STRUCT(event); event.events = epoll_map_flags(fde->flags); event.data.ptr = fde; if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) { tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL, "epoll_del_event failed! probable early close bug (%s)\n", strerror(errno)); } fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; }
/* add the epoll event to the given fd_event */ static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde) { struct epoll_event event; if (epoll_ev->epoll_fd == -1) return; fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; /* if we don't want events yet, don't add an epoll_event */ if (fde->flags == 0) return; ZERO_STRUCT(event); event.events = epoll_map_flags(fde->flags); event.data.ptr = fde; if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) { epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed"); } fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; /* only if we want to read we want to tell the event handler about errors */ if (fde->flags & TEVENT_FD_READ) { fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; } }
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; }
fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) { /* * This is a multiplexed fde, we need to include both * flags in the modified event. */ mpx_fde = talloc_get_type_abort(fde->additional_data, struct tevent_fd); mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; } ZERO_STRUCT(event); event.events = epoll_map_flags(fde->flags); if (mpx_fde != NULL) { event.events |= epoll_map_flags(mpx_fde->flags); } event.data.ptr = fde; ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event); if (ret != 0 && errno == EBADF) { tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR, "EPOLL_CTL_ADD EBADF for " "fde[%p] mpx_fde[%p] fd[%d] - disabling\n", fde, mpx_fde, fde->fd); DLIST_REMOVE(epoll_ev->ev->fd_events, fde); fde->event_ctx = NULL; if (mpx_fde != NULL) { DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde); mpx_fde->event_ctx = NULL;