2 * IRC - Internet Relay Chat, ircd/engine_epoll.c
3 * Copyright (C) 2003 Michael Poole <mdpoole@troilus.org>
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)
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.
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.
24 #include "ircd_events.h"
25 #include "ircd_alloc.h"
26 #include "ircd_features.h"
32 #include <sys/types.h>
33 #ifdef HAVE_INTTYPES_H
34 #include <inttypes.h> /* bah */
37 #include <sys/epoll.h>
38 #include <sys/socket.h>
40 #include <linux/unistd.h>
42 /* The GNU C library may have a valid header but stub implementations
43 * of the epoll system calls. If so, provide our own. */
44 #if defined(__stub_epoll_create) || defined(__stub___epoll_create) || defined(EPOLL_NEED_BODY)
46 /* Oh, did we mention that some glibc releases do not even define the
48 #if !defined(__NR_epoll_create)
50 #define __NR_epoll_create 254
51 #define __NR_epoll_ctl 255
52 #define __NR_epoll_wait 256
53 #elif 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
62 #error No system call numbers defined for epoll family.
63 #endif /* cpu types */
64 #endif /* !defined(__NR_epoll_create) */
66 _syscall1(int, epoll_create, int, size)
67 _syscall4(int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, event)
68 _syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents, int, maxevents, int, timeout)
70 #endif /* epoll_create defined as stub */
72 #define EPOLL_ERROR_THRESHOLD 20 /* after 20 epoll errors, restart */
73 #define ERROR_EXPIRE_TIME 3600 /* expire errors after an hour */
77 static struct Timer clear_error;
79 /* decrements the error count once per hour */
81 error_clear(struct Event *ev)
84 timer_del(ev_timer(ev));
87 /* initialize the epoll engine */
89 engine_init(int max_sockets)
91 if ((epoll_fd = epoll_create(max_sockets)) < 0) {
92 log_write(LS_SYSTEM, L_WARNING, 0,
93 "epoll() engine cannot initialize: %m");
100 set_events(struct Socket *sock, enum SocketState state, unsigned int events, struct epoll_event *evt)
103 assert(0 <= s_fd(sock));
104 memset(evt, 0, sizeof(*evt));
106 evt->data.ptr = sock;
110 evt->events = EPOLLOUT;
115 evt->events = EPOLLIN;
121 switch (events & SOCK_EVENT_MASK) {
125 case SOCK_EVENT_READABLE:
126 evt->events = EPOLLIN;
128 case SOCK_EVENT_WRITABLE:
129 evt->events = EPOLLOUT;
131 case SOCK_EVENT_READABLE|SOCK_EVENT_WRITABLE:
132 evt->events = EPOLLIN|EPOLLOUT;
140 engine_add(struct Socket *sock)
142 struct epoll_event evt;
145 Debug((DEBUG_ENGINE, "epoll: Adding socket %d [%p], state %s, to engine",
146 s_fd(sock), sock, state_to_name(s_state(sock))));
147 set_events(sock, s_state(sock), s_events(sock), &evt);
148 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, s_fd(sock), &evt) < 0) {
149 event_generate(ET_ERROR, sock, errno);
156 engine_set_state(struct Socket *sock, enum SocketState new_state)
158 struct epoll_event evt;
161 Debug((DEBUG_ENGINE, "epoll: Changing state for socket %p to %s",
162 sock, state_to_name(new_state)));
163 set_events(sock, new_state, s_events(sock), &evt);
164 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, s_fd(sock), &evt) < 0)
165 event_generate(ET_ERROR, sock, errno);
169 engine_set_events(struct Socket *sock, unsigned new_events)
171 struct epoll_event evt;
174 Debug((DEBUG_ENGINE, "epoll: Changing event mask for socket %p to [%s]",
175 sock, sock_flags(new_events)));
176 set_events(sock, s_state(sock), new_events, &evt);
177 if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, s_fd(sock), &evt) < 0)
178 event_generate(ET_ERROR, sock, errno);
182 engine_delete(struct Socket *sock)
184 struct epoll_event evt;
187 memset(&evt, 0, sizeof(evt));
188 Debug((DEBUG_ENGINE, "epoll: Deleting socket %d [%p], state %s",
189 s_fd(sock), sock, state_to_name(s_state(sock))));
190 if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, s_fd(sock), &evt) < 0)
191 log_write(LS_SOCKET, L_WARNING, 0,
192 "Unable to delete epoll item for socket %d", s_fd(sock));
196 engine_loop(struct Generators *gen)
198 struct epoll_event *events;
201 int events_count, i, wait, nevs, errcode;
203 if ((events_count = feature_int(FEAT_POLLS_PER_LOOP)) < 20)
205 events = MyMalloc(sizeof(events[0]) * events_count);
207 if ((i = feature_int(FEAT_POLLS_PER_LOOP)) >= 20 && i != events_count) {
208 events = MyRealloc(events, sizeof(events[0]) * i);
212 wait = timer_next(gen) ? (timer_next(gen) - CurrentTime) * 1000 : -1;
213 Debug((DEBUG_INFO, "epoll: delay: %d (%d) %d", timer_next(gen),
215 nevs = epoll_wait(epoll_fd, events, events_count, wait);
216 CurrentTime = time(0);
219 if (errno != EINTR) {
220 log_write(LS_SOCKET, L_ERROR, 0, "epoll() error: %m");
222 timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
224 else if (errors > EPOLL_ERROR_THRESHOLD)
225 server_restart("too many epoll errors");
230 for (i = 0; i < nevs; i++) {
231 if (!(sock = events[i].data.ptr))
235 "epoll: Checking socket %p (fd %d) state %s, events %s",
236 sock, s_fd(sock), state_to_name(s_state(sock)),
237 sock_flags(s_events(sock))));
239 if (events[i].events & EPOLLERR) {
241 codesize = sizeof(errcode);
242 if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
246 event_generate(ET_ERROR, sock, errcode);
252 switch (s_state(sock)) {
254 if (events[i].events & EPOLLOUT) /* connection completed */
255 event_generate(ET_CONNECT, sock, 0);
259 if (events[i].events & EPOLLIN) /* incoming connection */
260 event_generate(ET_ACCEPT, sock, 0);
265 if (events[i].events & EPOLLIN)
266 event_generate((events[i].events & EPOLLHUP) ? ET_EOF : ET_READ, sock, 0);
267 if (events[i].events & EPOLLOUT)
268 event_generate(ET_WRITE, sock, 0);
273 if (events[i].events & EPOLLIN)
274 event_generate(ET_READ, sock, 0);
275 if (events[i].events & EPOLLOUT)
276 event_generate(ET_WRITE, sock, 0);
285 struct Engine engine_epoll = {