ioloop-poll.c revision d12888d64be4aa4cb8cf36ee69920a8cde58d276
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2003 Timo Sirainen */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger/* @UNSAFE: whole file */
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "lib.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "ioloop-internal.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#ifdef IOLOOP_POLL
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include <sys/poll.h>
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen#ifndef INITIAL_POLL_FDS
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen# define INITIAL_POLL_FDS 128
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#endif
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstruct ioloop_handler_data {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int fds_size, fds_pos;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen struct pollfd *fds;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int idx_size;
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen int *fd_index;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen};
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen
12d38e76ba7f70d6219c89ec7416fea0d5de7e02Timo Sirainenvoid io_loop_handler_init(struct ioloop *ioloop)
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct ioloop_handler_data *data;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ioloop->handler_data = data =
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen p_new(ioloop->pool, struct ioloop_handler_data, 1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data->fds_size = INITIAL_POLL_FDS;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data->fds = p_new(ioloop->pool, struct pollfd, data->fds_size);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data->idx_size = INITIAL_POLL_FDS;
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen data->fd_index = p_new(ioloop->pool, int, data->idx_size);
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen memset(data->fd_index, 0xff, sizeof(int) * data->idx_size);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen}
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainenvoid io_loop_handler_deinit(struct ioloop *ioloop)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen p_free(ioloop->pool, ioloop->handler_data->fds);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen p_free(ioloop->pool, ioloop->handler_data->fd_index);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen p_free(ioloop->pool, ioloop->handler_data);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen#define IO_POLL_INPUT (POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen#define IO_POLL_OUTPUT (POLLOUT|POLLERR|POLLHUP|POLLNVAL)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenvoid io_loop_handle_add(struct ioloop *ioloop, struct io *io)
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen{
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen struct ioloop_handler_data *data = ioloop->handler_data;
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen enum io_condition condition = io->condition;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen unsigned int old_size;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen int index, fd = io->fd;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if ((unsigned int) fd >= data->idx_size) {
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen /* grow the fd -> index array */
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen old_size = data->idx_size;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen data->idx_size = nearest_power((unsigned int) fd+1);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen i_assert(data->idx_size < (size_t)-1 / sizeof(int));
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen data->fd_index = p_realloc(ioloop->pool, data->fd_index,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen sizeof(int) * old_size,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen sizeof(int) * data->idx_size);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen memset(data->fd_index + old_size, 0xff,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen sizeof(int) * (data->idx_size-old_size));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (data->fds_pos >= data->fds_size) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* grow the fd array */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen old_size = data->fds_size;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data->fds_size = nearest_power(data->fds_size+1);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_assert(data->fds_size < (size_t)-1 / sizeof(struct pollfd));
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data->fds = p_realloc(ioloop->pool, data->fds,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen sizeof(struct pollfd) * old_size,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen sizeof(struct pollfd) * data->fds_size);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if (data->fd_index[fd] != -1) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* update existing pollfd */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen index = data->fd_index[fd];
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen } else {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* add new pollfd */
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen index = data->fds_pos++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data->fd_index[fd] = index;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data->fds[index].fd = fd;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data->fds[index].events = 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen data->fds[index].revents = 0;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen }
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainen if (condition & IO_READ)
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainen data->fds[index].events |= IO_POLL_INPUT;
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainen if (condition & IO_WRITE)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen data->fds[index].events |= IO_POLL_OUTPUT;
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen}
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvoid io_loop_handle_remove(struct ioloop *ioloop, struct io *io)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen struct ioloop_handler_data *data = ioloop->handler_data;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen enum io_condition condition = io->condition;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen int index, fd = io->fd;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen index = data->fd_index[fd];
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen i_assert(index >= 0 && (unsigned int) index < data->fds_size);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen if (condition & IO_READ) {
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen data->fds[index].events &= ~(POLLIN|POLLPRI);
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen data->fds[index].revents &= ~(POLLIN|POLLPRI);
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen }
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen if (condition & IO_WRITE) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen data->fds[index].events &= ~POLLOUT;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen data->fds[index].revents &= ~POLLOUT;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen }
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen if ((data->fds[index].events & (POLLIN|POLLOUT)) == 0) {
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen /* remove the whole pollfd */
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen data->fd_index[data->fds[index].fd] = -1;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen if (--data->fds_pos == (unsigned int) index)
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen return; /* removing last one */
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen /* move the last pollfd over the removed one */
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen data->fds[index] = data->fds[data->fds_pos];
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen data->fd_index[data->fds[index].fd] = index;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen }
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen}
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainenvoid io_loop_handler_run(struct ioloop *ioloop)
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen{
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen struct ioloop_handler_data *data = ioloop->handler_data;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen struct pollfd *pollfd;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen struct timeval tv;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen struct io *io;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen unsigned int t_id;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen int msecs, ret, call;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen /* get the time left for next timeout task */
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen msecs = io_loop_get_wait_time(ioloop->timeouts, &tv, NULL);
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret = poll(data->fds, data->fds_pos, msecs);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ret < 0 && errno != EINTR)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_fatal("poll(): %m");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* execute timeout handlers */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen io_loop_handle_timeouts(ioloop);
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen if (ret <= 0 || !ioloop->running) {
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen /* no I/O events */
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen return;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen for (io = ioloop->ios; io != NULL && ret > 0; io = ioloop->next_io) {
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi ioloop->next_io = io->next;
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi pollfd = &data->fds[data->fd_index[io->fd]];
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi if (pollfd->revents != 0) {
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen if (pollfd->revents & POLLNVAL) {
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen i_error("invalid I/O fd %d, callback %p",
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen io->fd, (void *) io->callback);
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen pollfd->events &= ~POLLNVAL;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen pollfd->revents = 0;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen call = TRUE;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen } else if ((io->condition &
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen (IO_READ|IO_WRITE)) == (IO_READ|IO_WRITE)) {
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen call = TRUE;
5d4855d7b4dcffb6975ed8e3c9c376dac74e5c8aTimo Sirainen pollfd->revents = 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen } else if (io->condition & IO_READ) {
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen call = (pollfd->revents & IO_POLL_INPUT) != 0;
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen pollfd->revents &= ~IO_POLL_INPUT;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen } else if (io->condition & IO_WRITE) {
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen call = (pollfd->revents & IO_POLL_OUTPUT) != 0;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen pollfd->revents &= ~IO_POLL_OUTPUT;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen } else {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen call = FALSE;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if (pollfd->revents == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret--;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (call) {
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen t_id = t_push();
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen io->callback(io->context);
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen if (t_pop() != t_id)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_panic("Leaked a t_pop() call!");
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen }
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen#endif
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen