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