pid_t pid;
+ bool panic_force_replay;
+ bool *panic_state;
bool (*panic_fallback)(struct tevent_context *ev, bool replay);
};
const char *reason, bool replay)
{
struct tevent_context *ev = epoll_ev->ev;
+ bool (*panic_fallback)(struct tevent_context *ev, bool replay);
- if (epoll_ev->panic_fallback == NULL) {
+ panic_fallback = epoll_ev->panic_fallback;
+
+ if (epoll_ev->panic_state != NULL) {
+ *epoll_ev->panic_state = true;
+ }
+
+ if (epoll_ev->panic_force_replay) {
+ replay = true;
+ }
+
+ TALLOC_FREE(ev->additional_data);
+
+ if (panic_fallback == NULL) {
tevent_debug(ev, TEVENT_DEBUG_FATAL,
"%s (%s) replay[%u] - calling abort()\n",
reason, strerror(errno), (unsigned)replay);
"%s (%s) replay[%u] - calling panic_fallback\n",
reason, strerror(errno), (unsigned)replay);
- if (!epoll_ev->panic_fallback(ev, replay)) {
+ if (!panic_fallback(ev, replay)) {
/* Fallback failed. */
tevent_debug(ev, TEVENT_DEBUG_FATAL,
"%s (%s) replay[%u] - calling abort()\n",
static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
{
struct tevent_fd *fde;
+ bool *caller_panic_state = epoll_ev->panic_state;
+ bool panic_triggered = false;
if (epoll_ev->pid == getpid()) {
return;
close(epoll_ev->epoll_fd);
epoll_ev->epoll_fd = epoll_create(64);
if (epoll_ev->epoll_fd == -1) {
- tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
- "Failed to recreate epoll handle after fork\n");
+ epoll_panic(epoll_ev, "epoll_create() failed", false);
return;
}
}
epoll_ev->pid = getpid();
+ epoll_ev->panic_state = &panic_triggered;
for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
epoll_add_event(epoll_ev, fde);
+ if (panic_triggered) {
+ if (caller_panic_state != NULL) {
+ *caller_panic_state = true;
+ }
+ return;
+ }
}
+ epoll_ev->panic_state = NULL;
}
#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
{
struct tevent_context *ev = fde->event_ctx;
struct epoll_event_context *epoll_ev = NULL;
+ bool panic_triggered = false;
- if (ev) {
- epoll_ev = talloc_get_type(ev->additional_data,
- struct epoll_event_context);
+ if (ev == NULL) {
+ return tevent_common_fd_destructor(fde);
+ }
- epoll_check_reopen(epoll_ev);
+ epoll_ev = talloc_get_type_abort(ev->additional_data,
+ struct epoll_event_context);
- epoll_del_event(epoll_ev, fde);
+ /*
+ * we must remove the event from the list
+ * otherwise a panic fallback handler may
+ * reuse invalid memory
+ */
+ DLIST_REMOVE(ev->fd_events, fde);
+
+ epoll_ev->panic_state = &panic_triggered;
+ epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ return tevent_common_fd_destructor(fde);
+ }
+
+ epoll_del_event(epoll_ev, fde);
+ if (panic_triggered) {
+ return tevent_common_fd_destructor(fde);
}
+ epoll_ev->panic_state = NULL;
return tevent_common_fd_destructor(fde);
}
struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
struct epoll_event_context);
struct tevent_fd *fde;
-
- epoll_check_reopen(epoll_ev);
+ bool panic_triggered = false;
fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
handler, private_data,
talloc_set_destructor(fde, epoll_event_fd_destructor);
+ epoll_ev->panic_state = &panic_triggered;
+ epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ return fde;
+ }
+ epoll_ev->panic_state = NULL;
+
epoll_add_event(epoll_ev, fde);
return fde;
{
struct tevent_context *ev;
struct epoll_event_context *epoll_ev;
+ bool panic_triggered = false;
if (fde->flags == flags) return;
fde->flags = flags;
+ epoll_ev->panic_state = &panic_triggered;
epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ return;
+ }
+ epoll_ev->panic_state = NULL;
epoll_change_event(epoll_ev, fde);
}
struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
struct epoll_event_context);
struct timeval tval;
+ bool panic_triggered = false;
if (ev->signal_events &&
tevent_common_check_signal(ev)) {
return 0;
}
+ epoll_ev->panic_state = &panic_triggered;
+ epoll_ev->panic_force_replay = true;
epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ errno = EINVAL;
+ return -1;
+ }
+ epoll_ev->panic_force_replay = false;
+ epoll_ev->panic_state = NULL;
return epoll_event_loop(epoll_ev, &tval);
}