From: Timo Sirainen Date: Thu, 21 Aug 2008 04:35:59 +0000 (+0300) Subject: Added io_remove_closed(). X-Git-Tag: 1.2.alpha1~61 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=745f2c7424d88e368eff0a3a7650b352a9d1f0dd;p=thirdparty%2Fdovecot%2Fcore.git Added io_remove_closed(). --HG-- branch : HEAD --- diff --git a/src/lib/ioloop-epoll.c b/src/lib/ioloop-epoll.c index 114b6b2b4c..9f7377e026 100644 --- a/src/lib/ioloop-epoll.c +++ b/src/lib/ioloop-epoll.c @@ -118,7 +118,8 @@ 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) { struct ioloop_handler_context *ctx = ioloop->handler_context; struct io_list **list; @@ -129,17 +130,18 @@ void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io) 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); + if (!closed) { + memset(&event, 0, sizeof(event)); + event.data.ptr = *list; + event.events = epoll_event_mask(*list); - op = last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD; + 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 (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 --git a/src/lib/ioloop-internal.h b/src/lib/ioloop-internal.h index 80072c2167..c153b1c01d 100644 --- a/src/lib/ioloop-internal.h +++ b/src/lib/ioloop-internal.h @@ -54,7 +54,8 @@ void io_loop_handle_timeouts(struct ioloop *ioloop); /* 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 --git a/src/lib/ioloop-kqueue.c b/src/lib/ioloop-kqueue.c index 286fdd206e..c45e2870d5 100644 --- a/src/lib/ioloop-kqueue.c +++ b/src/lib/ioloop-kqueue.c @@ -80,17 +80,18 @@ void io_loop_handle_add(struct ioloop *ioloop, struct io_file *io) (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 --git a/src/lib/ioloop-poll.c b/src/lib/ioloop-poll.c index 3d636e9d64..ba8adfaf15 100644 --- a/src/lib/ioloop-poll.c +++ b/src/lib/ioloop-poll.c @@ -94,7 +94,8 @@ void io_loop_handle_add(struct ioloop *ioloop, struct io_file *io) 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 @@ void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io) 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 --git a/src/lib/ioloop-select.c b/src/lib/ioloop-select.c index 628b0f8b2c..1c63637088 100644 --- a/src/lib/ioloop-select.c +++ b/src/lib/ioloop-select.c @@ -74,7 +74,8 @@ void io_loop_handle_add(struct ioloop *ioloop, struct io_file *io) 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 --git a/src/lib/ioloop.c b/src/lib/ioloop.c index 406bebf1fa..0d194d9a1f 100644 --- a/src/lib/ioloop.c +++ b/src/lib/ioloop.c @@ -64,7 +64,7 @@ static void io_file_unlink(struct io_file *io) 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 @@ void io_remove(struct io **_io) 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 --git a/src/lib/ioloop.h b/src/lib/ioloop.h index 67242c87f2..f86b00dbd6 100644 --- a/src/lib/ioloop.h +++ b/src/lib/ioloop.h @@ -63,6 +63,9 @@ enum io_notify_result io_add_notify(const char *path, io_callback_t *callback, /* 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,