ioloop-select.c revision ccb7e5fbb0ab17e75f370bf08c0a7ff9613c6014
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/*
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop-select.c : I/O loop handler using select()
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Copyright (c) 2002 Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Permission is hereby granted, free of charge, to any person obtaining
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen a copy of this software and associated documentation files (the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Software"), to deal in the Software without restriction, including
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen without limitation the rights to use, copy, modify, merge, publish,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen distribute, sublicense, and/or sell copies of the Software, and to
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen permit persons to whom the Software is furnished to do so, subject to
bcf5af3335a814e4923ba1bf2e0d80eb6dabfb22Timo Sirainen the following conditions:
56561d472db25ebda35ae6afdc7f7deb75c323fcTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen The above copyright notice and this permission notice shall be
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen included in all copies or substantial portions of the Software.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
bcf5af3335a814e4923ba1bf2e0d80eb6dabfb22Timo Sirainen IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen*/
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop-internal.h"
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainen#ifdef IOLOOP_SELECT
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef HAVE_SYS_SELECT_H
659fe5d24825b160cae512538088020d97a60239Timo Sirainen# include <sys/select.h> /* According to POSIX 1003.1-2001 */
659fe5d24825b160cae512538088020d97a60239Timo Sirainen#endif
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen#include <sys/time.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct _IOLoopHandlerData {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fd_set read_fds, write_fds;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic fd_set tmp_read_fds, tmp_write_fds;
2a734f36105e33ab452d057df6bc7a2b7d9f96f0Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainenvoid io_loop_handler_init(IOLoop ioloop)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
659fe5d24825b160cae512538088020d97a60239Timo Sirainen ioloop->handler_data = p_new(ioloop->pool, IOLoopHandlerData, 1);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen FD_ZERO(&ioloop->handler_data->read_fds);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen FD_ZERO(&ioloop->handler_data->write_fds);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen}
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid io_loop_handler_deinit(IOLoop ioloop)
659fe5d24825b160cae512538088020d97a60239Timo Sirainen{
659fe5d24825b160cae512538088020d97a60239Timo Sirainen p_free(ioloop->pool, ioloop->handler_data);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen}
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainenvoid io_loop_handle_add(IOLoop ioloop, int fd, int condition)
659fe5d24825b160cae512538088020d97a60239Timo Sirainen{
659fe5d24825b160cae512538088020d97a60239Timo Sirainen i_assert(fd >= 0);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainen if (fd >= FD_SETSIZE)
659fe5d24825b160cae512538088020d97a60239Timo Sirainen i_fatal("fd %d too large for select()", fd);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainen if (condition & IO_READ)
659fe5d24825b160cae512538088020d97a60239Timo Sirainen FD_SET(fd, &ioloop->handler_data->read_fds);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen if (condition & IO_WRITE)
659fe5d24825b160cae512538088020d97a60239Timo Sirainen FD_SET(fd, &ioloop->handler_data->write_fds);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen}
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainenvoid io_loop_handle_remove(IOLoop ioloop, int fd, int condition)
659fe5d24825b160cae512538088020d97a60239Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(fd >= 0 && fd < FD_SETSIZE);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainen if (condition & IO_READ)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen FD_CLR(fd, &ioloop->handler_data->read_fds);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (condition & IO_WRITE)
d6f50f100ce17fa4b3a89e9567a5ff993b38b872Timo Sirainen FD_CLR(fd, &ioloop->handler_data->write_fds);
d6f50f100ce17fa4b3a89e9567a5ff993b38b872Timo Sirainen}
d6f50f100ce17fa4b3a89e9567a5ff993b38b872Timo Sirainen
d6f50f100ce17fa4b3a89e9567a5ff993b38b872Timo Sirainen#define io_check_condition(fd, condition) \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ((((condition) & IO_READ) && \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen FD_ISSET((fd), &tmp_read_fds)) || \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (((condition) & IO_WRITE) && \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen FD_ISSET((fd), &tmp_write_fds)))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid io_loop_handler_run(IOLoop ioloop)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen{
bcf5af3335a814e4923ba1bf2e0d80eb6dabfb22Timo Sirainen struct timeval tv;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen IO io, next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int t_id;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret, fd, condition;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* get the time left for next timeout task */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_get_wait_time(ioloop->timeouts, &tv, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen memcpy(&tmp_read_fds, &ioloop->handler_data->read_fds, sizeof(fd_set));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(&tmp_write_fds, &ioloop->handler_data->write_fds,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(fd_set));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = select(ioloop->highest_fd + 1, &tmp_read_fds, &tmp_write_fds,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen NULL, &tv);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret < 0 && errno != EINTR)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_warning("select() : %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* execute timeout handlers */
bcf5af3335a814e4923ba1bf2e0d80eb6dabfb22Timo Sirainen io_loop_handle_timeouts(ioloop);
bcf5af3335a814e4923ba1bf2e0d80eb6dabfb22Timo Sirainen
d6f50f100ce17fa4b3a89e9567a5ff993b38b872Timo Sirainen if (ret <= 0 || !ioloop->running) {
bcf5af3335a814e4923ba1bf2e0d80eb6dabfb22Timo Sirainen /* no I/O events */
bcf5af3335a814e4923ba1bf2e0d80eb6dabfb22Timo Sirainen return;
d6f50f100ce17fa4b3a89e9567a5ff993b38b872Timo Sirainen }
bcf5af3335a814e4923ba1bf2e0d80eb6dabfb22Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* execute the I/O handlers in prioritized order */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (io = ioloop->ios; io != NULL && ret > 0; io = next) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen next = io->next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2a734f36105e33ab452d057df6bc7a2b7d9f96f0Timo Sirainen if (io->destroyed) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we were destroyed, and io->fd points to -1 now. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_destroy(ioloop, io);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(io->fd >= 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
bcf5af3335a814e4923ba1bf2e0d80eb6dabfb22Timo Sirainen fd = io->fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen condition = io->condition;
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen if (!io_check_condition(fd, condition))
56561d472db25ebda35ae6afdc7f7deb75c323fcTimo Sirainen continue;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen t_id = t_push();
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen io->func(io->context, io->fd, io);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (t_pop() != t_id)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen i_panic("Leaked a t_pop() call!");
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (io->destroyed)
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen io_destroy(ioloop, io);
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen ret--;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen}
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen#endif
d7095f3a4466fbb78b2d5eb3d322bc15a5b0ab1fTimo Sirainen