# HG changeset patch # User Timo Sirainen # Date 1219293359 -10800 # Node ID 83aef3a6c0a37b2a144b8666c66bdaf7447020d1 # Parent 060165bdb0b0138251dd7acaa84a37fe78c53bbf Added io_remove_closed(). diff -r 060165bdb0b0 -r 83aef3a6c0a3 src/lib/ioloop-epoll.c --- a/src/lib/ioloop-epoll.c Thu Aug 21 07:14:50 2008 +0300 +++ b/src/lib/ioloop-epoll.c Thu Aug 21 07:35:59 2008 +0300 @@ -118,7 +118,8 @@ } } -void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io) +void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io, + bool closed) { struct ioloop_handler_context *ctx = ioloop->handler_context; struct io_list **list; @@ -129,17 +130,18 @@ list = array_idx_modifiable(&ctx->fd_index, io->fd); last = ioloop_iolist_del(*list, io); - memset(&event, 0, sizeof(event)); - event.data.ptr = *list; - event.events = epoll_event_mask(*list); - - op = last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD; + if (!closed) { + memset(&event, 0, sizeof(event)); + event.data.ptr = *list; + event.events = epoll_event_mask(*list); - if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) { - i_error("io_loop_handle_remove: epoll_ctl(%d, %d): %m", - op, io->fd); + op = last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD; + + if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) { + i_error("io_loop_handle_remove: epoll_ctl(%d, %d): %m", + op, io->fd); + } } - if (last) { /* since we're not freeing memory in any case, just increase deleted counter so next handle_add() can just decrease it diff -r 060165bdb0b0 -r 83aef3a6c0a3 src/lib/ioloop-internal.h --- a/src/lib/ioloop-internal.h Thu Aug 21 07:14:50 2008 +0300 +++ b/src/lib/ioloop-internal.h Thu Aug 21 07:35:59 2008 +0300 @@ -54,7 +54,8 @@ /* I/O handler calls */ void io_loop_handle_add(struct ioloop *ioloop, struct io_file *io); -void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io); +void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io, + bool closed); void io_loop_handler_init(struct ioloop *ioloop); void io_loop_handler_deinit(struct ioloop *ioloop); diff -r 060165bdb0b0 -r 83aef3a6c0a3 src/lib/ioloop-kqueue.c --- a/src/lib/ioloop-kqueue.c Thu Aug 21 07:14:50 2008 +0300 +++ b/src/lib/ioloop-kqueue.c Thu Aug 21 07:35:59 2008 +0300 @@ -80,17 +80,18 @@ (void)array_append_space(&ctx->events); } -void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io) +void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io, + bool closed) { struct ioloop_handler_context *ctx = ioloop->handler_context; struct kevent ev; - if ((io->io.condition & (IO_READ | IO_ERROR)) != 0) { + if ((io->io.condition & (IO_READ | IO_ERROR)) != 0 && !closed) { MY_EV_SET(&ev, io->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) i_error("kevent(EV_DELETE, %d) failed: %m", io->fd); } - if ((io->io.condition & IO_WRITE) != 0) { + if ((io->io.condition & IO_WRITE) != 0 && !closed) { MY_EV_SET(&ev, io->fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) i_error("kevent(EV_DELETE, %d) failed: %m", io->fd); diff -r 060165bdb0b0 -r 83aef3a6c0a3 src/lib/ioloop-poll.c --- a/src/lib/ioloop-poll.c Thu Aug 21 07:14:50 2008 +0300 +++ b/src/lib/ioloop-poll.c Thu Aug 21 07:35:59 2008 +0300 @@ -94,7 +94,8 @@ ctx->fds[index].events |= IO_POLL_ERROR; } -void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io) +void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io, + bool closed ATTR_UNUSED) { struct ioloop_handler_context *ctx = ioloop->handler_context; enum io_condition condition = io->io.condition; @@ -104,15 +105,18 @@ i_assert(index >= 0 && (unsigned int) index < ctx->fds_count); #ifdef DEBUG - /* io_remove() is required to be called before fd is closed. - This is required by kqueue, but since poll is more commonly used - while developing, this check here should catch the error early - enough not to cause problems for kqueue users. */ - if (fcntl(io->fd, F_GETFD, 0) < 0) { - if (errno == EBADF) - i_panic("io_remove(%d) called too late", io->fd); - else - i_error("fcntl(%d, F_GETFD) failed: %m", io->fd); + if (!closed) { + /* io_remove() is required to be called before fd is closed. + This is required by epoll/kqueue, but since poll is more + commonly used while developing, this check here should catch + the error early enough not to cause problems for kqueue + users. */ + if (fcntl(io->fd, F_GETFD, 0) < 0) { + if (errno == EBADF) + i_panic("io_remove(%d) called too late", io->fd); + else + i_error("fcntl(%d, F_GETFD) failed: %m", io->fd); + } } #endif i_free(io); diff -r 060165bdb0b0 -r 83aef3a6c0a3 src/lib/ioloop-select.c --- a/src/lib/ioloop-select.c Thu Aug 21 07:14:50 2008 +0300 +++ b/src/lib/ioloop-select.c Thu Aug 21 07:35:59 2008 +0300 @@ -74,7 +74,8 @@ ctx->highest_fd = io->fd; } -void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io) +void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io, + bool closed ATTR_UNUSED) { struct ioloop_handler_context *ctx = ioloop->handler_context; enum io_condition condition = io->io.condition; diff -r 060165bdb0b0 -r 83aef3a6c0a3 src/lib/ioloop.c --- a/src/lib/ioloop.c Thu Aug 21 07:14:50 2008 +0300 +++ b/src/lib/ioloop.c Thu Aug 21 07:35:59 2008 +0300 @@ -64,7 +64,7 @@ current_ioloop->next_io_file = io->next; } -void io_remove(struct io **_io) +static void io_remove_full(struct io **_io, bool closed) { struct io *io = *_io; @@ -82,10 +82,22 @@ struct io_file *io_file = (struct io_file *)io; io_file_unlink(io_file); - io_loop_handle_remove(current_ioloop, io_file); + io_loop_handle_remove(current_ioloop, io_file, closed); } } +void io_remove(struct io **io) +{ + io_remove_full(io, FALSE); +} + +void io_remove_closed(struct io **io) +{ + i_assert(((*io)->condition & IO_NOTIFY) == 0); + + io_remove_full(io, TRUE); +} + static void timeout_update_next(struct timeout *timeout, struct timeval *tv_now) { if (tv_now == NULL) { diff -r 060165bdb0b0 -r 83aef3a6c0a3 src/lib/ioloop.h --- a/src/lib/ioloop.h Thu Aug 21 07:14:50 2008 +0300 +++ b/src/lib/ioloop.h Thu Aug 21 07:35:59 2008 +0300 @@ -63,6 +63,9 @@ /* Remove I/O handler, and set io pointer to NULL. */ void io_remove(struct io **io); +/* Like io_remove(), but assume that the file descriptor is already closed. + With some backends this simply frees the memory. */ +void io_remove_closed(struct io **io); /* Timeout handlers */ struct timeout *timeout_add(unsigned int msecs, timeout_callback_t *callback,