ctx->poller_app = 0;
LIBXL_LIST_INIT(&ctx->pollers_event);
LIBXL_LIST_INIT(&ctx->pollers_idle);
+ LIBXL_LIST_INIT(&ctx->pollers_fds_changed);
LIBXL_LIST_INIT(&ctx->efds);
LIBXL_TAILQ_INIT(&ctx->etimes);
libxl__poller_put(ctx, ctx->poller_app);
ctx->poller_app = NULL;
assert(LIBXL_LIST_EMPTY(&ctx->pollers_event));
+ assert(LIBXL_LIST_EMPTY(&ctx->pollers_fds_changed));
libxl__poller *poller, *poller_tmp;
LIBXL_LIST_FOREACH_SAFE(poller, &ctx->pollers_idle, entry, poller_tmp) {
libxl__poller_dispose(poller);
void libxl__ev_fd_deregister(libxl__gc *gc, libxl__ev_fd *ev)
{
CTX_LOCK;
+ libxl__poller *poller;
if (!libxl__ev_fd_isregistered(ev)) {
DBG("ev_fd=%p deregister unregistered",ev);
LIBXL_LIST_REMOVE(ev, entry);
ev->fd = -1;
+ LIBXL_LIST_FOREACH(poller, &CTX->pollers_fds_changed, fds_changed_entry)
+ poller->fds_changed = 1;
+
out:
CTX_UNLOCK;
}
*nfds_io = used;
+ poller->fds_changed = 0;
+
libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes);
if (etime) {
int our_timeout;
/* again, stale slot entry */
continue;
- assert(!(fds[slot].revents & POLLNVAL));
+ assert(poller->fds_changed || !(fds[slot].revents & POLLNVAL));
/* we mask in case requested events have changed */
int slot_revents = fds[slot].revents & events;
int rc;
p->fd_polls = 0;
p->fd_rindices = 0;
+ p->fds_changed = 0;
rc = libxl__pipe_nonblock(CTX, p->wakeup_pipe);
if (rc) goto out;
}
}
+ LIBXL_LIST_INSERT_HEAD(&CTX->pollers_fds_changed, p,
+ fds_changed_entry);
return p;
}
void libxl__poller_put(libxl_ctx *ctx, libxl__poller *p)
{
if (!p) return;
+ LIBXL_LIST_REMOVE(p, fds_changed_entry);
LIBXL_LIST_INSERT_HEAD(&ctx->pollers_idle, p, entry);
}
int (*fd_rindices)[3]; /* see libxl_event.c:beforepoll_internal */
int wakeup_pipe[2]; /* 0 means no fd allocated */
+
+ /*
+ * We also use the poller to record whether any fds have been
+ * deregistered since we entered poll. Each poller which is not
+ * idle is on the list pollers_fds_changed. fds_changed is
+ * cleared by beforepoll, and tested by afterpoll. Whenever an fd
+ * event is deregistered, we set the fds_changed of all non-idle
+ * pollers. So afterpoll can tell whether any POLLNVAL is
+ * plausibly due to an fd being closed and reopened.
+ */
+ LIBXL_LIST_ENTRY(libxl__poller) fds_changed_entry;
+ bool fds_changed;
};
struct libxl__gc {
libxl__poller *poller_app; /* libxl_osevent_beforepoll and _afterpoll */
LIBXL_LIST_HEAD(, libxl__poller) pollers_event, pollers_idle;
+ LIBXL_LIST_HEAD(, libxl__poller) pollers_fds_changed;
LIBXL_SLIST_HEAD(libxl__osevent_hook_nexi, libxl__osevent_hook_nexus)
hook_fd_nexi_idle, hook_timeout_nexi_idle;