/[svn]/branches/newio/src/ioengine_epoll.c
ViewVC logotype

Contents of /branches/newio/src/ioengine_epoll.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2415 - (show annotations)
Sun Jul 21 14:33:22 2013 UTC (6 years, 11 months ago) by michael
File MIME type: text/x-chdr
File size: 10155 byte(s)
- ioengine changes as of 21JUL13

1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 *
4 * Copyright (C) 2003 Michael Poole <mdpoole@troilus.org>
5 * Copyright (C) 2013 by the Hybrid Development Team.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 */
22
23 /*! \file ioengine_epoll.c
24 * \brief Linux epoll_*() event engine.
25 * \version $Id$
26 */
27
28 #include "stdinc.h"
29 #include "ioengine.h"
30 #include "ircd.h"
31 #include "memory.h"
32 #include "log.h"
33 #include "restart.h"
34
35 #include <errno.h>
36 #include <sys/types.h>
37 #ifdef HAVE_STDINT_H
38 #include <stdint.h>
39 #endif
40 #include <string.h>
41 #include <sys/epoll.h>
42 #include <sys/socket.h>
43 #include <time.h>
44 #include <linux/unistd.h>
45
46 /* The GNU C library may have a valid header but stub implementations
47 * of the epoll system calls. If so, provide our own. */
48 #if defined(__stub_epoll_create) || defined(__stub___epoll_create) || defined(EPOLL_NEED_BODY)
49
50 /* Oh, did we mention that some glibc releases do not even define the
51 * syscall numbers? */
52 #if !defined(__NR_epoll_create)
53 #if defined(__ia64__)
54 #define __NR_epoll_create 1243
55 #define __NR_epoll_ctl 1244
56 #define __NR_epoll_wait 1245
57 #elif defined(__x86_64__)
58 #define __NR_epoll_create 214
59 #define __NR_epoll_ctl 233
60 #define __NR_epoll_wait 232
61 #elif defined(__sparc64__) || defined(__sparc__)
62 #define __NR_epoll_create 193
63 #define __NR_epoll_ctl 194
64 #define __NR_epoll_wait 195
65 #elif defined(__s390__) || defined(__m68k__)
66 #define __NR_epoll_create 249
67 #define __NR_epoll_ctl 250
68 #define __NR_epoll_wait 251
69 #elif defined(__ppc64__) || defined(__ppc__)
70 #define __NR_epoll_create 236
71 #define __NR_epoll_ctl 237
72 #define __NR_epoll_wait 238
73 #elif defined(__parisc__) || defined(__arm26__) || defined(__arm__)
74 #define __NR_epoll_create 224
75 #define __NR_epoll_ctl 225
76 #define __NR_epoll_wait 226
77 #elif defined(__alpha__)
78 #define __NR_epoll_create 407
79 #define __NR_epoll_ctl 408
80 #define __NR_epoll_wait 409
81 #elif defined(__sh64__)
82 #define __NR_epoll_create 282
83 #define __NR_epoll_ctl 283
84 #define __NR_epoll_wait 284
85 #elif defined(__i386__) || defined(__sh__) || defined(__m32r__) || defined(__h8300__) || defined(__frv__)
86 #define __NR_epoll_create 254
87 #define __NR_epoll_ctl 255
88 #define __NR_epoll_wait 256
89 #else /* cpu types */
90 #error No system call numbers defined for epoll family.
91 #endif /* cpu types */
92 #endif /* !defined(__NR_epoll_create) */
93
94 _syscall1(int, epoll_create, int, size)
95 _syscall4(int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, event)
96 _syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents, int, maxevents, int, timeout)
97
98 #endif /* epoll_create defined as stub */
99
100 #define EPOLL_ERROR_THRESHOLD 20 /**< after 20 epoll errors, restart */
101 #define ERROR_EXPIRE_TIME 3600 /**< expire errors after an hour */
102
103 /** File descriptor for epoll pseudo-file. */
104 static int epoll_fd;
105 /** Number of recent epoll errors. */
106 static int errors;
107 /** Periodic timer to forget errors. */
108 static struct Timer clear_error;
109
110 /** Decrement the error count (once per hour).
111 * @param[in] ev Expired timer event (ignored).
112 */
113 static void
114 error_clear(struct Event *ev)
115 {
116 if (!--errors)
117 timer_del(ev_timer(ev));
118 }
119
120 /** Initialize the epoll engine.
121 * @param[in] max_sockets Maximum number of file descriptors to support.
122 * @return Non-zero on success, or zero on failure.
123 */
124 static int
125 engine_init(int max_sockets)
126 {
127 if ((epoll_fd = epoll_create(max_sockets)) < 0)
128 {
129 ilog(LOG_TYPE_DEBUG,
130 "epoll() engine cannot initialize: %m");
131 return 0;
132 }
133
134 return 1;
135 }
136
137 /** Set events for a particular socket.
138 * @param[in] sock Socket to calculate events for.
139 * @param[in] state Current socket state.
140 * @param[in] events User-specified event interest list.
141 * @param[out] evt epoll event structure for socket.
142 */
143 static void
144 set_events(struct Socket *sock, enum SocketState state, unsigned int events, struct epoll_event *evt)
145 {
146 assert(0 != sock);
147 assert(0 <= s_fd(sock));
148
149 memset(evt, 0, sizeof(*evt));
150
151 evt->data.ptr = sock;
152
153 switch (state)
154 {
155 case SS_CONNECTING:
156 evt->events = EPOLLOUT;
157 break;
158
159 case SS_LISTENING:
160 case SS_NOTSOCK:
161 evt->events = EPOLLIN;
162 break;
163
164 case SS_CONNECTED:
165 case SS_DATAGRAM:
166 case SS_CONNECTDG:
167 switch (events & SOCK_EVENT_MASK)
168 {
169 case 0:
170 evt->events = 0;
171 break;
172 case SOCK_EVENT_READABLE:
173 evt->events = EPOLLIN;
174 break;
175 case SOCK_EVENT_WRITABLE:
176 evt->events = EPOLLOUT;
177 break;
178 case SOCK_EVENT_READABLE|SOCK_EVENT_WRITABLE:
179 evt->events = EPOLLIN|EPOLLOUT;
180 break;
181 }
182
183 break;
184 }
185 }
186
187 /** Add a socket to the event engine.
188 * @param[in] sock Socket to add to engine.
189 * @return Non-zero on success, or zero on error.
190 */
191 static int
192 engine_add(struct Socket *sock)
193 {
194 struct epoll_event evt;
195
196 assert(0 != sock);
197 ilog(LOG_TYPE_DEBUG, "epoll: Adding socket %d [%p], state %s, to engine",
198 s_fd(sock), sock, state_to_name(s_state(sock)));
199 set_events(sock, s_state(sock), s_events(sock), &evt);
200 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, s_fd(sock), &evt) < 0) {
201 event_generate(ET_ERROR, sock, errno);
202 return 0;
203 }
204 return 1;
205 }
206
207 /** Handle state transition for a socket.
208 * @param[in] sock Socket changing state.
209 * @param[in] new_state New state for socket.
210 */
211 static void
212 engine_set_state(struct Socket *sock, enum SocketState new_state)
213 {
214 struct epoll_event evt;
215
216 assert(0 != sock);
217 ilog(LOG_TYPE_DEBUG, "epoll: Changing state for socket %p to %s",
218 sock, state_to_name(new_state));
219 set_events(sock, new_state, s_events(sock), &evt);
220 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, s_fd(sock), &evt) < 0)
221 event_generate(ET_ERROR, sock, errno);
222 }
223
224 /** Handle change to preferred socket events.
225 * @param[in] sock Socket getting new interest list.
226 * @param[in] new_events New set of interesting events for socket.
227 */
228 static void
229 engine_set_events(struct Socket *sock, unsigned new_events)
230 {
231 struct epoll_event evt;
232
233 assert(0 != sock);
234 ilog(LOG_TYPE_DEBUG, "epoll: Changing event mask for socket %p to [%s]",
235 sock, sock_flags(new_events));
236 set_events(sock, s_state(sock), new_events, &evt);
237 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, s_fd(sock), &evt) < 0)
238 event_generate(ET_ERROR, sock, errno);
239 }
240
241 /** Remove a socket from the event engine.
242 * @param[in] sock Socket being destroyed.
243 */
244 static void
245 engine_delete(struct Socket *sock)
246 {
247 assert(0 != sock);
248 ilog(LOG_TYPE_DEBUG, "epoll: Deleting socket %d [%p], state %s",
249 s_fd(sock), sock, state_to_name(s_state(sock)));
250 /* No action necessary; epoll removes the socket on close(). */
251 }
252
253 /** Run engine event loop.
254 * @param[in] gen Lists of generators of various types.
255 */
256 static void
257 engine_loop(struct Generators *gen)
258 {
259 struct epoll_event *events;
260 struct Socket *sock;
261 socklen_t codesize;
262 int events_count, i, iwait, nevs, errcode;
263
264 if ((events_count = 64 /* XXX */) < 20)
265 events_count = 20;
266 events = MyMalloc(sizeof(events[0]) * events_count);
267 while (running)
268 {
269 if ((i = 64 /* XXX */) >= 20 && i != events_count) {
270 events = MyRealloc(events, sizeof(events[0]) * i);
271 events_count = i;
272 }
273
274 iwait = timer_next(gen) ? (timer_next(gen) - CurrentTime) * 1000 : -1;
275 ilog(LOG_TYPE_DEBUG, "epoll: delay: %d (%d) %d", timer_next(gen),
276 CurrentTime, iwait);
277 nevs = epoll_wait(epoll_fd, events, events_count, iwait);
278 set_time();
279
280 if (nevs < 0) {
281 if (errno != EINTR) {
282 ilog(LOG_TYPE_DEBUG, "epoll() error: %m");
283 if (!errors++)
284 timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
285 ERROR_EXPIRE_TIME);
286 else if (errors > EPOLL_ERROR_THRESHOLD)
287 restart("too many epoll errors");
288 }
289 continue;
290 }
291
292 for (i = 0; i < nevs; i++) {
293 if (!(sock = events[i].data.ptr))
294 continue;
295 gen_ref_inc(sock);
296 ilog(LOG_TYPE_DEBUG,
297 "epoll: Checking socket %p (fd %d) state %s, events %s",
298 sock, s_fd(sock), state_to_name(s_state(sock)),
299 sock_flags(s_events(sock)));
300
301 if (events[i].events & EPOLLERR) {
302 errcode = 0;
303 codesize = sizeof(errcode);
304 if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
305 &codesize) < 0)
306 errcode = errno;
307 if (errcode) {
308 event_generate(ET_ERROR, sock, errcode);
309 gen_ref_dec(sock);
310 continue;
311 }
312 } else if (events[i].events & EPOLLHUP) {
313 event_generate(ET_EOF, sock, 0);
314 } else switch (s_state(sock)) {
315 case SS_CONNECTING:
316 if (events[i].events & EPOLLOUT) /* connection completed */
317 event_generate(ET_CONNECT, sock, 0);
318 break;
319
320 case SS_LISTENING:
321 if (events[i].events & EPOLLIN) /* incoming connection */
322 event_generate(ET_ACCEPT, sock, 0);
323 break;
324
325 case SS_NOTSOCK:
326 case SS_CONNECTED:
327 case SS_DATAGRAM:
328 case SS_CONNECTDG:
329 if (events[i].events & EPOLLIN)
330 event_generate(ET_READ, sock, 0);
331 if (events[i].events & EPOLLOUT)
332 event_generate(ET_WRITE, sock, 0);
333 break;
334 }
335 gen_ref_dec(sock);
336 }
337 timer_run();
338 }
339 MyFree(events);
340 }
341
342 /** Descriptor for epoll event engine. */
343 struct Engine engine_epoll =
344 {
345 "epoll()",
346 engine_init,
347 0,
348 engine_add,
349 engine_set_state,
350 engine_set_events,
351 engine_delete,
352 engine_loop
353 };

Properties

Name Value
svn:keywords Id Revision

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28