blob: b1cd44ef3e8e18379b24433746d43d53a4833c9a [file] [log] [blame]
Willy Tarreau4f60f162007-04-08 16:39:58 +02001/*
2 * FD polling functions for generic select()
3 *
4 * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <unistd.h>
14#include <sys/time.h>
15#include <sys/types.h>
16
17#include <common/compat.h>
18#include <common/config.h>
19#include <common/time.h>
20
21#include <types/fd.h>
22#include <types/global.h>
23
24#include <proto/fd.h>
25#include <proto/polling.h>
26#include <proto/task.h>
27
28
29static fd_set *ReadEvent, *WriteEvent;
30static fd_set *StaticReadEvent, *StaticWriteEvent;
31
32
33/*
34 * Benchmarks performed on a Pentium-M notebook show that using functions
35 * instead of the usual macros improve the FD_* performance by about 80%,
36 * and that marking them regparm(2) adds another 20%.
37 */
38REGPRM2 static int __fd_isset(const int fd, const int dir)
39{
40 fd_set *ev;
41 if (dir == DIR_RD)
42 ev = StaticReadEvent;
43 else
44 ev = StaticWriteEvent;
45
46 return FD_ISSET(fd, ev);
47}
48
49REGPRM2 static void __fd_set(const int fd, const int dir)
50{
51 fd_set *ev;
52 if (dir == DIR_RD)
53 ev = StaticReadEvent;
54 else
55 ev = StaticWriteEvent;
56
57 FD_SET(fd, ev);
58}
59
60REGPRM2 static void __fd_clr(const int fd, const int dir)
61{
62 fd_set *ev;
63 if (dir == DIR_RD)
64 ev = StaticReadEvent;
65 else
66 ev = StaticWriteEvent;
67
68 FD_CLR(fd, ev);
69}
70
71REGPRM2 static int __fd_cond_s(const int fd, const int dir)
72{
73 int ret;
74 fd_set *ev;
75 if (dir == DIR_RD)
76 ev = StaticReadEvent;
77 else
78 ev = StaticWriteEvent;
79
80 ret = !FD_ISSET(fd, ev);
81 if (ret)
82 FD_SET(fd, ev);
83 return ret;
84}
85
86REGPRM2 static int __fd_cond_c(const int fd, const int dir)
87{
88 int ret;
89 fd_set *ev;
90 if (dir == DIR_RD)
91 ev = StaticReadEvent;
92 else
93 ev = StaticWriteEvent;
94
95 ret = FD_ISSET(fd, ev);
96 if (ret)
97 FD_CLR(fd, ev);
98 return ret;
99}
100
101REGPRM1 static void __fd_rem(const int fd)
102{
103 FD_CLR(fd, StaticReadEvent);
104 FD_CLR(fd, StaticWriteEvent);
105}
106
107
108/*
109 * Initialization of the select() poller.
110 * Returns 0 in case of failure, non-zero in case of success. If it fails, it
111 * disables the poller by setting its pref to 0.
112 */
113REGPRM1 static int select_init(struct poller *p)
114{
115 __label__ fail_swevt, fail_srevt, fail_wevt, fail_revt;
116 int fd_set_bytes;
117
118 p->private = NULL;
119 fd_set_bytes = sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE;
120
121 if ((ReadEvent = (fd_set *)calloc(1, fd_set_bytes)) == NULL)
122 goto fail_revt;
123
124 if ((WriteEvent = (fd_set *)calloc(1, fd_set_bytes)) == NULL)
125 goto fail_wevt;
126
127 if ((StaticReadEvent = (fd_set *)calloc(1, fd_set_bytes)) == NULL)
128 goto fail_srevt;
129
130 if ((StaticWriteEvent = (fd_set *)calloc(1, fd_set_bytes)) == NULL)
131 goto fail_swevt;
132
133 return 1;
134
135 fail_swevt:
136 free(StaticReadEvent);
137 fail_srevt:
138 free(WriteEvent);
139 fail_wevt:
140 free(ReadEvent);
141 fail_revt:
142 p->pref = 0;
143 return 0;
144}
145
146/*
147 * Termination of the select() poller.
148 * Memory is released and the poller is marked as unselectable.
149 */
150REGPRM1 static void select_term(struct poller *p)
151{
152 if (StaticWriteEvent)
153 free(StaticWriteEvent);
154 if (StaticReadEvent)
155 free(StaticReadEvent);
156 if (WriteEvent)
157 free(WriteEvent);
158 if (ReadEvent)
159 free(ReadEvent);
160 p->private = NULL;
161 p->pref = 0;
162}
163
164/*
165 * Select() poller
166 */
167REGPRM2 static void select_poll(struct poller *p, int wait_time)
168{
169 int status;
170 int fd, i;
171 struct timeval delta;
172 int readnotnull, writenotnull;
173 int fds;
174 char count;
175
176 /* allow select to return immediately when needed */
177 delta.tv_sec = delta.tv_usec = 0;
178 if (wait_time > 0) { /* FIXME */
179 /* Convert to timeval */
180 /* to avoid eventual select loops due to timer precision */
181 wait_time += SCHEDULER_RESOLUTION;
182 delta.tv_sec = wait_time / 1000;
183 delta.tv_usec = (wait_time % 1000) * 1000;
184 }
185
186 /* let's restore fdset state */
187
188 readnotnull = 0; writenotnull = 0;
189 for (i = 0; i < (maxfd + FD_SETSIZE - 1)/(8*sizeof(int)); i++) {
190 readnotnull |= (*(((int*)ReadEvent)+i) = *(((int*)StaticReadEvent)+i)) != 0;
191 writenotnull |= (*(((int*)WriteEvent)+i) = *(((int*)StaticWriteEvent)+i)) != 0;
192 }
193
194 // /* just a verification code, needs to be removed for performance */
195 // for (i=0; i<maxfd; i++) {
196 // if (FD_ISSET(i, ReadEvent) != FD_ISSET(i, StaticReadEvent))
197 // abort();
198 // if (FD_ISSET(i, WriteEvent) != FD_ISSET(i, StaticWriteEvent))
199 // abort();
200 //
201 // }
202
203 status = select(maxfd,
204 readnotnull ? ReadEvent : NULL,
205 writenotnull ? WriteEvent : NULL,
206 NULL,
207 (wait_time >= 0) ? &delta : NULL);
208
209 tv_now(&now);
210
211 if (status <= 0)
212 return;
213
214 for (fds = 0; (fds << INTBITS) < maxfd; fds++) {
215 if ((((int *)(ReadEvent))[fds] | ((int *)(WriteEvent))[fds]) == 0)
216 continue;
217
218 for (count = 1<<INTBITS, fd = fds << INTBITS; count && fd < maxfd; count--, fd++) {
219 /* if we specify read first, the accepts and zero reads will be
220 * seen first. Moreover, system buffers will be flushed faster.
221 */
222 if (FD_ISSET(fd, ReadEvent)) {
223 if (fdtab[fd].state == FD_STCLOSE)
224 continue;
225 fdtab[fd].cb[DIR_RD].f(fd);
226 }
227
228 if (FD_ISSET(fd, WriteEvent)) {
229 if (fdtab[fd].state == FD_STCLOSE)
230 continue;
231 fdtab[fd].cb[DIR_WR].f(fd);
232 }
233 }
234 }
235}
236
237/*
238 * The only exported function. Returns 1.
239 */
240int select_register(struct poller *p)
241{
242 p->name = "select";
243 p->pref = 150;
244 p->private = NULL;
245
246 p->init = select_init;
247 p->term = select_term;
248 p->poll = select_poll;
249 p->isset = __fd_isset;
250 p->set = __fd_set;
251 p->clr = __fd_clr;
252 p->clo = p->rem = __fd_rem;
253 p->cond_s = __fd_cond_s;
254 p->cond_c = __fd_cond_c;
255 return 1;
256}
257
258
259/*
260 * Local variables:
261 * c-indent-level: 8
262 * c-basic-offset: 8
263 * End:
264 */