1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop-private.h"
#ifdef IOLOOP_SELECT
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h> /* According to POSIX 1003.1-2001 */
#endif
#include <sys/time.h>
#include <unistd.h>
struct ioloop_handler_context {
int highest_fd;
fd_set read_fds, write_fds, except_fds;
fd_set tmp_read_fds, tmp_write_fds, tmp_except_fds;
};
static void update_highest_fd(struct ioloop *ioloop)
{
struct ioloop_handler_context *ctx = ioloop->handler_context;
struct io_file *io;
int max_highest_fd;
max_highest_fd = ctx->highest_fd-1;
ctx->highest_fd = -1;
for (io = ioloop->io_files; io != NULL; io = io->next) {
if (io->fd <= ctx->highest_fd)
continue;
ctx->highest_fd = io->fd;
if (ctx->highest_fd == max_highest_fd)
break;
}
}
void io_loop_handler_init(struct ioloop *ioloop,
unsigned int initial_fd_count ATTR_UNUSED)
{
struct ioloop_handler_context *ctx;
ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
ctx->highest_fd = -1;
FD_ZERO(&ctx->read_fds);
FD_ZERO(&ctx->write_fds);
FD_ZERO(&ctx->except_fds);
}
void io_loop_handler_deinit(struct ioloop *ioloop)
{
i_free(ioloop->handler_context);
}
void io_loop_handle_add(struct io_file *io)
{
struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
enum io_condition condition = io->io.condition;
int fd = io->fd;
i_assert(fd >= 0);
if (fd >= FD_SETSIZE)
i_fatal("fd %d too large for select()", fd);
if ((condition & (IO_READ | IO_ERROR)) != 0)
FD_SET(fd, &ctx->read_fds);
if ((condition & IO_WRITE) != 0)
FD_SET(fd, &ctx->write_fds);
FD_SET(fd, &ctx->except_fds);
if (io->fd > ctx->highest_fd)
ctx->highest_fd = io->fd;
}
void io_loop_handle_remove(struct io_file *io, bool closed ATTR_UNUSED)
{
struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
enum io_condition condition = io->io.condition;
int fd = io->fd;
i_assert(fd >= 0 && fd < FD_SETSIZE);
if ((condition & (IO_READ | IO_ERROR)) != 0)
FD_CLR(fd, &ctx->read_fds);
if ((condition & IO_WRITE) != 0)
FD_CLR(fd, &ctx->write_fds);
if (!FD_ISSET(fd, &ctx->read_fds) && !FD_ISSET(fd, &ctx->write_fds)) {
FD_CLR(fd, &ctx->except_fds);
/* check if we removed the highest fd */
if (io->fd == ctx->highest_fd)
update_highest_fd(io->io.ioloop);
}
i_free(io);
}
#define io_check_condition(ctx, fd, cond) \
((FD_ISSET((fd), &(ctx)->tmp_read_fds) && ((cond) & (IO_READ|IO_ERROR)) != 0) || \
(FD_ISSET((fd), &(ctx)->tmp_write_fds) && ((cond) & IO_WRITE) != 0) || \
(FD_ISSET((fd), &(ctx)->tmp_except_fds)))
void io_loop_handler_run_internal(struct ioloop *ioloop)
{
struct ioloop_handler_context *ctx = ioloop->handler_context;
struct timeval tv;
struct io_file *io;
int ret;
/* get the time left for next timeout task */
io_loop_run_get_wait_time(ioloop, &tv);
memcpy(&ctx->tmp_read_fds, &ctx->read_fds, sizeof(fd_set));
memcpy(&ctx->tmp_write_fds, &ctx->write_fds, sizeof(fd_set));
memcpy(&ctx->tmp_except_fds, &ctx->except_fds, sizeof(fd_set));
ret = select(ctx->highest_fd + 1, &ctx->tmp_read_fds,
&ctx->tmp_write_fds, &ctx->tmp_except_fds, &tv);
if (ret < 0 && errno != EINTR)
i_warning("select() : %m");
/* execute timeout handlers */
io_loop_handle_timeouts(ioloop);
if (ret <= 0 || !ioloop->running) {
/* no I/O events */
return;
}
io = ioloop->io_files;
for (; io != NULL && ret > 0; io = ioloop->next_io_file) {
ioloop->next_io_file = io->next;
if (io->fd == -1) {
/* io_add_istream() without fd */
} else if (io_check_condition(ctx, io->fd, io->io.condition)) {
ret--;
io_loop_call_io(&io->io);
if (!ioloop->running)
break;
}
}
}
#endif
|