]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/engine_epoll.c
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.
20 * @brief Linux epoll_*() event engine.
21 * @version $Id: engine_epoll.c,v 1.12 2005/08/25 01:26:46 entrope Exp $
26 #include "ircd_events.h"
27 #include "ircd_alloc.h"
28 #include "ircd_features.h"
32 /* #include <assert.h> -- Now using assert in ircd_log.h */
34 #include <sys/types.h>
36 #include <stdint.h> /* bah */
39 #include <sys/epoll.h>
40 #include <sys/socket.h>
42 #include <linux/unistd.h>
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)
48 /* Oh, did we mention that some glibc releases do not even define the
50 #if !defined(__NR_epoll_create)
52 #define __NR_epoll_create 1243
53 #define __NR_epoll_ctl 1244
54 #define __NR_epoll_wait 1245
55 #elif defined(__x86_64__)
56 #define __NR_epoll_create 214
57 #define __NR_epoll_ctl 233
58 #define __NR_epoll_wait 232
59 #elif defined(__sparc64__) || defined(__sparc__)
60 #define __NR_epoll_create 193
61 #define __NR_epoll_ctl 194
62 #define __NR_epoll_wait 195
63 #elif defined(__s390__) || defined(__m68k__)
64 #define __NR_epoll_create 249
65 #define __NR_epoll_ctl 250
66 #define __NR_epoll_wait 251
67 #elif defined(__ppc64__) || defined(__ppc__)
68 #define __NR_epoll_create 236
69 #define __NR_epoll_ctl 237
70 #define __NR_epoll_wait 238
71 #elif defined(__parisc__) || defined(__arm26__) || defined(__arm__)
72 #define __NR_epoll_create 224
73 #define __NR_epoll_ctl 225
74 #define __NR_epoll_wait 226
75 #elif defined(__alpha__)
76 #define __NR_epoll_create 407
77 #define __NR_epoll_ctl 408
78 #define __NR_epoll_wait 409
79 #elif defined(__sh64__)
80 #define __NR_epoll_create 282
81 #define __NR_epoll_ctl 283
82 #define __NR_epoll_wait 284
83 #elif defined(__i386__) || defined(__sh__) || defined(__m32r__) || defined(__h8300__) || defined(__frv__)
84 #define __NR_epoll_create 254
85 #define __NR_epoll_ctl 255
86 #define __NR_epoll_wait 256
88 #error No system call numbers defined for epoll family.
89 #endif /* cpu types */
90 #endif /* !defined(__NR_epoll_create) */
92 _syscall1(int, epoll_create
, int, size
)
93 _syscall4(int, epoll_ctl
, int, epfd
, int, op
, int, fd
, struct epoll_event
*, event
)
94 _syscall4(int, epoll_wait
, int, epfd
, struct epoll_event
*, pevents
, int, maxevents
, int, timeout
)
96 #endif /* epoll_create defined as stub */
98 #define EPOLL_ERROR_THRESHOLD 20 /**< after 20 epoll errors, restart */
99 #define ERROR_EXPIRE_TIME 3600 /**< expire errors after an hour */
101 /** File descriptor for epoll pseudo-file. */
103 /** Number of recent epoll errors. */
105 /** Periodic timer to forget errors. */
106 static struct Timer clear_error
;
108 /** Decrement the error count (once per hour).
109 * @param[in] ev Expired timer event (ignored).
112 error_clear(struct Event
*ev
)
115 timer_del(ev_timer(ev
));
118 /** Initialize the epoll engine.
119 * @param[in] max_sockets Maximum number of file descriptors to support.
120 * @return Non-zero on success, or zero on failure.
123 engine_init(int max_sockets
)
125 if ((epoll_fd
= epoll_create(max_sockets
)) < 0) {
126 log_write(LS_SYSTEM
, L_WARNING
, 0,
127 "epoll() engine cannot initialize: %m");
133 /** Set events for a particular socket.
134 * @param[in] sock Socket to calculate events for.
135 * @param[in] state Current socket state.
136 * @param[in] events User-specified event interest list.
137 * @param[out] evt epoll event structure for socket.
140 set_events(struct Socket
*sock
, enum SocketState state
, unsigned int events
, struct epoll_event
*evt
)
143 assert(0 <= s_fd(sock
));
144 memset(evt
, 0, sizeof(*evt
));
146 evt
->data
.ptr
= sock
;
150 evt
->events
= EPOLLOUT
;
155 evt
->events
= EPOLLIN
;
161 switch (events
& SOCK_EVENT_MASK
) {
165 case SOCK_EVENT_READABLE
:
166 evt
->events
= EPOLLIN
;
168 case SOCK_EVENT_WRITABLE
:
169 evt
->events
= EPOLLOUT
;
171 case SOCK_EVENT_READABLE
|SOCK_EVENT_WRITABLE
:
172 evt
->events
= EPOLLIN
|EPOLLOUT
;
179 /** Add a socket to the event engine.
180 * @param[in] sock Socket to add to engine.
181 * @return Non-zero on success, or zero on error.
184 engine_add(struct Socket
*sock
)
186 struct epoll_event evt
;
189 Debug((DEBUG_ENGINE
, "epoll: Adding socket %d [%p], state %s, to engine",
190 s_fd(sock
), sock
, state_to_name(s_state(sock
))));
191 set_events(sock
, s_state(sock
), s_events(sock
), &evt
);
192 if (epoll_ctl(epoll_fd
, EPOLL_CTL_ADD
, s_fd(sock
), &evt
) < 0) {
193 event_generate(ET_ERROR
, sock
, errno
);
199 /** Handle state transition for a socket.
200 * @param[in] sock Socket changing state.
201 * @param[in] new_state New state for socket.
204 engine_set_state(struct Socket
*sock
, enum SocketState new_state
)
206 struct epoll_event evt
;
209 Debug((DEBUG_ENGINE
, "epoll: Changing state for socket %p to %s",
210 sock
, state_to_name(new_state
)));
211 set_events(sock
, new_state
, s_events(sock
), &evt
);
212 if (epoll_ctl(epoll_fd
, EPOLL_CTL_MOD
, s_fd(sock
), &evt
) < 0)
213 event_generate(ET_ERROR
, sock
, errno
);
216 /** Handle change to preferred socket events.
217 * @param[in] sock Socket getting new interest list.
218 * @param[in] new_events New set of interesting events for socket.
221 engine_set_events(struct Socket
*sock
, unsigned new_events
)
223 struct epoll_event evt
;
226 Debug((DEBUG_ENGINE
, "epoll: Changing event mask for socket %p to [%s]",
227 sock
, sock_flags(new_events
)));
228 set_events(sock
, s_state(sock
), new_events
, &evt
);
229 if (epoll_ctl(epoll_fd
, EPOLL_CTL_MOD
, s_fd(sock
), &evt
) < 0)
230 event_generate(ET_ERROR
, sock
, errno
);
233 /** Remove a socket from the event engine.
234 * @param[in] sock Socket being destroyed.
237 engine_delete(struct Socket
*sock
)
240 Debug((DEBUG_ENGINE
, "epoll: Deleting socket %d [%p], state %s",
241 s_fd(sock
), sock
, state_to_name(s_state(sock
))));
242 /* No action necessary; epoll removes the socket on close(). */
245 /** Run engine event loop.
246 * @param[in] gen Lists of generators of various types.
249 engine_loop(struct Generators
*gen
)
251 struct epoll_event
*events
;
254 int events_count
, i
, wait
, nevs
, errcode
;
256 if ((events_count
= feature_int(FEAT_POLLS_PER_LOOP
)) < 20)
258 events
= MyMalloc(sizeof(events
[0]) * events_count
);
260 if ((i
= feature_int(FEAT_POLLS_PER_LOOP
)) >= 20 && i
!= events_count
) {
261 events
= MyRealloc(events
, sizeof(events
[0]) * i
);
265 wait
= timer_next(gen
) ? (timer_next(gen
) - CurrentTime
) * 1000 : -1;
266 Debug((DEBUG_ENGINE
, "epoll: delay: %d (%d) %d", timer_next(gen
),
268 nevs
= epoll_wait(epoll_fd
, events
, events_count
, wait
);
269 CurrentTime
= time(0);
272 if (errno
!= EINTR
) {
273 log_write(LS_SOCKET
, L_ERROR
, 0, "epoll() error: %m");
275 timer_add(timer_init(&clear_error
), error_clear
, 0, TT_PERIODIC
,
277 else if (errors
> EPOLL_ERROR_THRESHOLD
)
278 server_restart("too many epoll errors");
283 for (i
= 0; i
< nevs
; i
++) {
284 if (!(sock
= events
[i
].data
.ptr
))
288 "epoll: Checking socket %p (fd %d) state %s, events %s",
289 sock
, s_fd(sock
), state_to_name(s_state(sock
)),
290 sock_flags(s_events(sock
))));
292 if (events
[i
].events
& EPOLLERR
) {
294 codesize
= sizeof(errcode
);
295 if (getsockopt(s_fd(sock
), SOL_SOCKET
, SO_ERROR
, &errcode
,
299 event_generate(ET_ERROR
, sock
, errcode
);
303 } else if (events
[i
].events
& EPOLLHUP
) {
304 event_generate(ET_EOF
, sock
, 0);
305 } else switch (s_state(sock
)) {
307 if (events
[i
].events
& EPOLLOUT
) /* connection completed */
308 event_generate(ET_CONNECT
, sock
, 0);
312 if (events
[i
].events
& EPOLLIN
) /* incoming connection */
313 event_generate(ET_ACCEPT
, sock
, 0);
320 if (events
[i
].events
& EPOLLIN
)
321 event_generate(ET_READ
, sock
, 0);
322 if (events
[i
].events
& EPOLLOUT
)
323 event_generate(ET_WRITE
, sock
, 0);
333 /** Descriptor for epoll event engine. */
334 struct Engine engine_epoll
= {