[Dovecot] Fix for the kevent "Unrecognized event" problem.
The attached patch should fix the problem with dying imap on "Unrecognized event". The problem is that when we register a handle for IO_ERROR only, we still can get readable/writable event without EV_EOF being set. This case was not handled.
-- Vaclav Haisman
*** ioloop-kqueue.c.~1.4.~ Tue May 2 14:36:56 2006 --- ioloop-kqueue.c Tue May 9 21:29:33 2006
*** 74,80 **** { struct ioloop_handler_context *ctx = ioloop->handler_context; const int fd = io->fd; ! struct kevent ev = { fd, 0, EV_ADD | EV_EOF, 0, 0, NULL }; enum io_condition condition = io->condition & MASK;
i_assert(io->callback != NULL);
--- 74,80 ---- { struct ioloop_handler_context *ctx = ioloop->handler_context; const int fd = io->fd; ! struct kevent ev = { fd, 0, EV_ADD, 0, 0, NULL }; enum io_condition condition = io->condition & MASK;
i_assert(io->callback != NULL);
*** 184,190 ****
i_assert(ctx->evbuf[i].ident < ctx->fds_size);
if ((ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) &&
! (ctx->evbuf[i].flags & EV_EOF)) { struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
t_id = t_push();
--- 184,190 ----
i_assert(ctx->evbuf[i].ident < ctx->fds_size);
if ((ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) &&
! (ctx->evbuf[i].flags & (EV_EOF | EV_ERROR))) { struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
t_id = t_push();
*** 203,216 **** " in I/O handler %p", (void *)io->callback); } } else i_panic("Unrecognized event: kevent {.ident = %u," " .filter = 0x%04x," " .flags = 0x%04x," " .fflags = 0x%08x," ! " .data = 0x%08x}", ctx->evbuf[i].ident, ctx->evbuf[i].filter, ctx->evbuf[i].flags, ! ctx->evbuf[i].fflags, ctx->evbuf[i].data); } }
--- 203,224 ---- " in I/O handler %p", (void *)io->callback); }
} else if (ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) {
! " .data = 0x%08x}\n" ! "mode: 0x%x04x", ctx->evbuf[i].ident, ctx->evbuf[i].filter, ctx->evbuf[i].flags, ! ctx->evbuf[i].fflags, ctx->evbuf[i].data, ! ctx->fds[ctx->evbuf[i].ident].mode); } }} else i_panic("Unrecognized event: kevent {.ident = %u," " .filter = 0x%04x," " .flags = 0x%04x," " .fflags = 0x%08x,"
Václav Haisman wrote:
The attached patch should fix the problem with dying imap on "Unrecognized event". The problem is that when we register a handle for IO_ERROR only, we still can get readable/writable event without EV_EOF being set. This case was not handled.
-- Vaclav Haisman The fix uncovered another related glitch. If we are waiting just on IO_ERROR then we get readable/writable event all the time, because kqueue is level triggered by default and the codition is always present, and the result is busy loop. Adding EV_CLEAR bit in this case should fix it.
-- Vaclav Haisman
*** ioloop-kqueue.c.~1.4.~ Tue May 2 14:36:56 2006 --- ioloop-kqueue.c Wed May 10 11:23:02 2006
*** 74,80 **** { struct ioloop_handler_context *ctx = ioloop->handler_context; const int fd = io->fd; ! struct kevent ev = { fd, 0, EV_ADD | EV_EOF, 0, 0, NULL }; enum io_condition condition = io->condition & MASK;
i_assert(io->callback != NULL);
--- 74,80 ---- { struct ioloop_handler_context *ctx = ioloop->handler_context; const int fd = io->fd; ! struct kevent ev = { fd, 0, EV_ADD, 0, 0, NULL }; enum io_condition condition = io->condition & MASK;
i_assert(io->callback != NULL);
*** 101,106 **** --- 101,108 ---- if (condition & (IO_READ | IO_ERROR)) { ctx->fds[fd].mode |= condition; ev.filter = EVFILT_READ;
if ((condition & IO_ERROR) == IO_ERROR)
if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) { i_error("kevent(%d) in io_loop_handle_add() failed: %m", fd);
*** 109,114 **** --- 111,118 ---- if (condition & (IO_WRITE | IO_ERROR)) { ctx->fds[fd].mode |= condition; ev.filter = EVFILT_WRITE;
if ((condition & IO_ERROR) == IO_ERROR)
if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) { i_error("kevent(%d) in io_loop_handle_add() failed: %m", fd);
*** 184,190 ****
i_assert(ctx->evbuf[i].ident < ctx->fds_size);
if ((ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) &&
! (ctx->evbuf[i].flags & EV_EOF)) { struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
t_id = t_push();
--- 188,194 ----
i_assert(ctx->evbuf[i].ident < ctx->fds_size);
if ((ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) &&
! (ctx->evbuf[i].flags & (EV_EOF | EV_ERROR))) { struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
t_id = t_push();
*** 203,216 **** " in I/O handler %p", (void *)io->callback); } } else i_panic("Unrecognized event: kevent {.ident = %u," " .filter = 0x%04x," " .flags = 0x%04x," " .fflags = 0x%08x," ! " .data = 0x%08x}", ctx->evbuf[i].ident, ctx->evbuf[i].filter, ctx->evbuf[i].flags, ! ctx->evbuf[i].fflags, ctx->evbuf[i].data); } }
--- 207,228 ---- " in I/O handler %p", (void *)io->callback); }
} else if (ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) {
! " .data = 0x%08x}\n" ! "mode: 0x%x04x", ctx->evbuf[i].ident, ctx->evbuf[i].filter, ctx->evbuf[i].flags, ! ctx->evbuf[i].fflags, ctx->evbuf[i].data, ! ctx->fds[ctx->evbuf[i].ident].mode); } }} else i_panic("Unrecognized event: kevent {.ident = %u," " .filter = 0x%04x," " .flags = 0x%04x," " .fflags = 0x%08x,"
Václav Haisman wrote:
Václav Haisman wrote:
The attached patch should fix the problem with dying imap on "Unrecognized event". The problem is that when we register a handle for IO_ERROR only, we still can get readable/writable event without EV_EOF being set. This case was not handled.
-- Vaclav Haisman The fix uncovered another related glitch. If we are waiting just on IO_ERROR then we get readable/writable event all the time, because kqueue is level triggered by default and the codition is always present, and the result is busy loop. Adding EV_CLEAR bit in this case should fix it.
-- Vaclav Haisman
Bah, I was too fast to post. Attached is a corrected patch. The condition I have added in the previous should be different.
-- Vaclav Haisman
*** ioloop-kqueue.c.~1.4.~ Tue May 2 14:36:56 2006 --- ioloop-kqueue.c Wed May 10 12:02:31 2006
*** 74,80 **** { struct ioloop_handler_context *ctx = ioloop->handler_context; const int fd = io->fd; ! struct kevent ev = { fd, 0, EV_ADD | EV_EOF, 0, 0, NULL }; enum io_condition condition = io->condition & MASK;
i_assert(io->callback != NULL);
--- 74,80 ---- { struct ioloop_handler_context *ctx = ioloop->handler_context; const int fd = io->fd; ! struct kevent ev = { fd, 0, EV_ADD, 0, 0, NULL }; enum io_condition condition = io->condition & MASK;
i_assert(io->callback != NULL);
*** 101,106 **** --- 101,108 ---- if (condition & (IO_READ | IO_ERROR)) { ctx->fds[fd].mode |= condition; ev.filter = EVFILT_READ;
if (!(condition & ~IO_ERROR))
if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) { i_error("kevent(%d) in io_loop_handle_add() failed: %m", fd);
*** 109,114 **** --- 111,118 ---- if (condition & (IO_WRITE | IO_ERROR)) { ctx->fds[fd].mode |= condition; ev.filter = EVFILT_WRITE;
if (!(condition & ~IO_ERROR))
if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) { i_error("kevent(%d) in io_loop_handle_add() failed: %m", fd);
*** 184,190 ****
i_assert(ctx->evbuf[i].ident < ctx->fds_size);
if ((ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) &&
! (ctx->evbuf[i].flags & EV_EOF)) { struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
t_id = t_push();
--- 188,194 ----
i_assert(ctx->evbuf[i].ident < ctx->fds_size);
if ((ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) &&
! (ctx->evbuf[i].flags & (EV_EOF | EV_ERROR))) { struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
t_id = t_push();
*** 203,216 **** " in I/O handler %p", (void *)io->callback); } } else i_panic("Unrecognized event: kevent {.ident = %u," " .filter = 0x%04x," " .flags = 0x%04x," " .fflags = 0x%08x," ! " .data = 0x%08x}", ctx->evbuf[i].ident, ctx->evbuf[i].filter, ctx->evbuf[i].flags, ! ctx->evbuf[i].fflags, ctx->evbuf[i].data); } }
--- 207,228 ---- " in I/O handler %p", (void *)io->callback); }
} else if (ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) {
! " .data = 0x%08x}\n" ! "mode: 0x%x04x", ctx->evbuf[i].ident, ctx->evbuf[i].filter, ctx->evbuf[i].flags, ! ctx->evbuf[i].fflags, ctx->evbuf[i].data, ! ctx->fds[ctx->evbuf[i].ident].mode); } }} else i_panic("Unrecognized event: kevent {.ident = %u," " .filter = 0x%04x," " .flags = 0x%04x," " .fflags = 0x%08x,"
Václav Haisman wrote:
The fix uncovered another related glitch. If we are waiting just on IO_ERROR then we get readable/writable event all the time, because kqueue is level triggered by default and the codition is always present, and the result is busy loop. Adding EV_CLEAR bit in this case should fix it.
I guess that explains why while the first patch seemed to work imap was eating up all my cpu :-)
Bah, I was too fast to post. Attached is a corrected patch. The condition I have added in the previous should be different.
-- Vaclav Haisman
So far so good, I just applied it on my FreeBSD/amd64 box and everything is behaving. Thanks for the fix, you rock.
Cheers, Dillon
i use openbsd/i386 + dovecot-cvs(10-may) + this patch, my maillog still have kqueue error message like this:
Unrecognized event: kevent {.ident = 0, .filter = 0xffffffff, .flags = 0x8001, .fflags = 0x00000000, .data = 0x00000000}
thank you
Václav Haisman wrote:
The attached patch should fix the problem with dying imap on "Unrecognized event". The problem is that when we register a handle for IO_ERROR only, we still can get readable/writable event without EV_EOF being set. This case was not handled.
-- Vaclav Haisman
*** ioloop-kqueue.c.~1.4.~ Tue May 2 14:36:56 2006 --- ioloop-kqueue.c Tue May 9 21:29:33 2006
*** 74,80 **** { struct ioloop_handler_context *ctx = ioloop->handler_context; const int fd = io->fd; ! struct kevent ev = { fd, 0, EV_ADD | EV_EOF, 0, 0, NULL }; enum io_condition condition = io->condition & MASK;
i_assert(io->callback != NULL); --- 74,80 ---- { struct ioloop_handler_context *ctx = ioloop->handler_context; const int fd = io->fd; ! struct kevent ev = { fd, 0, EV_ADD, 0, 0, NULL }; enum io_condition condition = io->condition & MASK;
i_assert(io->callback != NULL);
*** 184,190 ****
i_assert(ctx->evbuf[i].ident < ctx->fds_size); if ((ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) &&
! (ctx->evbuf[i].flags & EV_EOF)) { struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
t_id = t_push();
--- 184,190 ----
i_assert(ctx->evbuf[i].ident < ctx->fds_size); if ((ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) &&
! (ctx->evbuf[i].flags & (EV_EOF | EV_ERROR))) { struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
t_id = t_push();
*** 203,216 **** " in I/O handler %p", (void *)io->callback); } } else i_panic("Unrecognized event: kevent {.ident = %u," " .filter = 0x%04x," " .flags = 0x%04x," " .fflags = 0x%08x," ! " .data = 0x%08x}", ctx->evbuf[i].ident, ctx->evbuf[i].filter, ctx->evbuf[i].flags, ! ctx->evbuf[i].fflags, ctx->evbuf[i].data); } }
--- 203,224 ---- " in I/O handler %p", (void *)io->callback); }
} else if (ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) {
! " .data = 0x%08x}\n" ! "mode: 0x%x04x", ctx->evbuf[i].ident, ctx->evbuf[i].filter, ctx->evbuf[i].flags, ! ctx->evbuf[i].fflags, ctx->evbuf[i].data, ! ctx->fds[ctx->evbuf[i].ident].mode); } }} else i_panic("Unrecognized event: kevent {.ident = %u," " .filter = 0x%04x," " .flags = 0x%04x," " .fflags = 0x%08x,"
i use openbsd/i386 + dovecot-cvs(10-may) + this patch, my maillog still have kqueue error message like this:
Unrecognized event: kevent {.ident = 0, .filter = 0xffffffff, .flags = 0x8001, .fflags = 0x00000000, .data = 0x00000000} There should be one more line of the log following this one. Could you
John Wong wrote: please post it too?
thank you
-- Vaclav Haisman
yes, the maillog should be like this:
Unrecognized event: kevent {.ident = 0, .filter = 0xffffffff, .flags = 0x8001, .fflags = 0x00000000, .data = 0x00000000} mode: 0x004x killed with signal 6
thank you
在 2006/5/11 的來信中,"Václav Haisman" V.Haisman@sh.cvut.cz 提及:
i use openbsd/i386 + dovecot-cvs(10-may) + this patch, my maillog still have kqueue error message like this:
Unrecognized event: kevent {.ident = 0, .filter = 0xffffffff, .flags = 0x8001, .fflags = 0x00000000, .data = 0x00000000} There should be one more line of the log following this one. Could you
John Wong wrote: please post it too?
thank you
-- Vaclav Haisman
participants (3)
-
Dillon
-
John Wong
-
Václav Haisman