ev->additional_data, struct poll_event_context);
int pollrtn;
int timeout = -1;
- unsigned first_fd;
- unsigned i, next_i;
int poll_errno;
+ struct tevent_fd *fde = NULL;
+ unsigned i;
if (ev->signal_events && tevent_common_check_signal(ev)) {
return 0;
return 0;
}
- first_fd = (poll_ev->signal_fd != -1) ? 1 : 0;
-
/* at least one file descriptor is ready - check
which ones and call the handler, being careful to allow
the handler to remove itself when called */
- for (i=first_fd; i<poll_ev->num_fds; i = next_i) {
+ for (fde = ev->fd_events; fde; fde = fde->next) {
+ unsigned idx = fde->additional_flags;
struct pollfd *pfd;
- struct tevent_fd *fde;
uint16_t flags = 0;
- next_i = i + 1;
+ if (idx == UINT64_MAX) {
+ continue;
+ }
+
+ pfd = &poll_ev->fds[idx];
- fde = poll_ev->fdes[i];
- if (fde == NULL) {
+ if (pfd->revents & POLLNVAL) {
/*
- * This fde was talloc_free()'ed. Delete it
- * from the arrays
+ * the socket is dead! this should never
+ * happen as the socket should have first been
+ * made readable and that should have removed
+ * the event, so this must be a bug.
+ *
+ * We ignore it here to match the epoll
+ * behavior.
*/
- poll_ev->num_fds -= 1;
- if (poll_ev->num_fds == i) {
- break;
- }
- poll_ev->fds[i] = poll_ev->fds[poll_ev->num_fds];
- poll_ev->fdes[i] = poll_ev->fdes[poll_ev->num_fds];
- if (poll_ev->fdes[i] != NULL) {
- poll_ev->fdes[i]->additional_flags = i;
- }
- /* we have to reprocess position 'i' */
- next_i = i;
+ tevent_debug(ev, TEVENT_DEBUG_ERROR,
+ "POLLNVAL on fde[%p] fd[%d] - disabling\n",
+ fde, pfd->fd);
+ poll_ev->fdes[idx] = NULL;
+ poll_ev->deleted = true;
+ DLIST_REMOVE(ev->fd_events, fde);
+ fde->event_ctx = NULL;
continue;
}
- pfd = &poll_ev->fds[i];
-
if (pfd->revents & (POLLHUP|POLLERR)) {
/* If we only wait for TEVENT_FD_WRITE, we
should not tell the event handler about it,
if (pfd->revents & POLLOUT) {
flags |= TEVENT_FD_WRITE;
}
+ /*
+ * Note that fde->flags could be changed when using
+ * the poll_mt backend together with threads,
+ * that why we need to check pfd->revents and fde->flags
+ */
+ flags &= fde->flags;
if (flags != 0) {
fde->handler(ev, fde, flags, fde->private_data);
- break;
+ return 0;
+ }
+ }
+
+ for (i = 0; i < poll_ev->num_fds; i++) {
+ if (poll_ev->fds[i].revents & POLLNVAL) {
+ /*
+ * the socket is dead! this should never
+ * happen as the socket should have first been
+ * made readable and that should have removed
+ * the event, so this must be a bug or
+ * a race in the poll_mt usage.
+ */
+ fde = poll_ev->fdes[i];
+ tevent_debug(ev, TEVENT_DEBUG_WARNING,
+ "POLLNVAL on dangling fd[%d] fde[%p] - disabling\n",
+ poll_ev->fds[i].fd, fde);
+ poll_ev->fdes[i] = NULL;
+ poll_ev->deleted = true;
+ if (fde != NULL) {
+ DLIST_REMOVE(ev->fd_events, fde);
+ fde->event_ctx = NULL;
+ }
}
}