]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/engine_poll.c
133daf8a66b5bc444178b586aa7834addb69faed
2 * IRC - Internet Relay Chat, ircd/engine_poll.c
3 * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
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 POSIX poll() event engine.
21 * @version $Id: engine_poll.c,v 1.10 2004/12/11 05:13:44 klmitch Exp $
25 #include "ircd_events.h"
28 #include "ircd_alloc.h"
32 /* #include <assert.h> -- Now using assert in ircd_log.h */
35 #include <sys/socket.h>
36 #include <sys/types.h>
40 #define POLL_ERROR_THRESHOLD 20 /**< after 20 poll errors, restart */
41 #define ERROR_EXPIRE_TIME 3600 /**< expire errors after an hour */
43 /* Figure out what bits to set for read */
44 #if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM)
45 # define POLLREADFLAGS (POLLMSG|POLLIN|POLLRDNORM)
46 #elif defined(POLLIN) && defined(POLLRDNORM)
47 # define POLLREADFLAGS (POLLIN|POLLRDNORM)
49 # define POLLREADFLAGS POLLIN
50 #elif defined(POLLRDNORM)
51 # define POLLREADFLAGS POLLRDNORM
54 /* Figure out what bits to set for write */
55 #if defined(POLLOUT) && defined(POLLWRNORM)
56 # define POLLWRITEFLAGS (POLLOUT|POLLWRNORM)
57 #elif defined(POLLOUT)
58 # define POLLWRITEFLAGS POLLOUT
59 #elif defined(POLLWRNORM)
60 # define POLLWRITEFLAGS POLLWRNORM
63 /** Array of active Socket structures, indexed by file descriptor. */
64 static struct Socket
** sockList
;
65 /** Array of poll() active elements. */
66 static struct pollfd
* pollfdList
;
67 /** Number of pollfd elements currently used. */
68 static unsigned int poll_count
;
69 /** Maximum file descriptor supported, plus one. */
70 static unsigned int poll_max
;
72 /** Number of recent errors from poll(). */
73 static int errors
= 0;
74 /** Periodic timer to forget errors. */
75 static struct Timer clear_error
;
77 /** Decrement the error count (once per hour).
78 * @param[in] ev Expired timer event (ignored).
81 error_clear(struct Event
* ev
)
83 if (!--errors
) /* remove timer when error count reaches 0 */
84 timer_del(ev_timer(ev
));
87 /** Initialize the poll() engine.
88 * @param[in] max_sockets Maximum number of file descriptors to support.
89 * @return Non-zero on success, or zero on failure.
92 engine_init(int max_sockets
)
96 /* allocate necessary memory */
97 sockList
= (struct Socket
**) MyMalloc(sizeof(struct Socket
*) * max_sockets
);
98 pollfdList
= (struct pollfd
*) MyMalloc(sizeof(struct pollfd
) * max_sockets
);
100 /* initialize the data */
101 for (i
= 0; i
< max_sockets
; i
++) {
103 pollfdList
[i
].fd
= -1;
104 pollfdList
[i
].events
= 0;
105 pollfdList
[i
].revents
= 0;
108 poll_count
= 0; /* nothing in set */
109 poll_max
= max_sockets
; /* number of sockets allocated */
114 /** Figure out what events go with a given state.
115 * @param[in] state %Socket state to consider.
116 * @param[in] events User-specified preferred event set.
117 * @return Actual set of preferred events.
120 state_to_events(enum SocketState state
, unsigned int events
)
123 case SS_CONNECTING
: /* connecting socket */
124 return SOCK_EVENT_WRITABLE
;
127 case SS_LISTENING
: /* listening socket */
128 case SS_NOTSOCK
: /* our signal socket */
129 return SOCK_EVENT_READABLE
;
132 case SS_CONNECTED
: case SS_DATAGRAM
: case SS_CONNECTDG
:
133 return events
; /* ordinary socket */
141 /** Set interest events in a pollfd as appropriate.
142 * @param[in] idx Index of pollfd to operate on.
143 * @param[in] clear Set of interest events to clear from socket.
144 * @param[in] set Set of interest events to set on socket.
147 set_or_clear(int idx
, unsigned int clear
, unsigned int set
)
149 if ((clear
^ set
) & SOCK_EVENT_READABLE
) { /* readable has changed */
150 if (set
& SOCK_EVENT_READABLE
) /* it's set */
151 pollfdList
[idx
].events
|= POLLREADFLAGS
;
153 pollfdList
[idx
].events
&= ~POLLREADFLAGS
;
156 if ((clear
^ set
) & SOCK_EVENT_WRITABLE
) { /* writable has changed */
157 if (set
& SOCK_EVENT_WRITABLE
) /* it's set */
158 pollfdList
[idx
].events
|= POLLWRITEFLAGS
;
160 pollfdList
[idx
].events
&= ~POLLWRITEFLAGS
;
164 /** Add a socket to the event engine.
165 * @param[in] sock Socket to add to engine.
166 * @return Non-zero on success, or zero on error.
169 engine_add(struct Socket
* sock
)
175 for (i
= 0; sockList
[i
] && i
< poll_count
; i
++) /* Find an empty slot */
178 Debug((DEBUG_ENGINE
, "poll: Looking at slot %d, contents %p", i
,
181 if (i
>= poll_count
) { /* ok, need to allocate another off the list */
182 if (poll_count
>= poll_max
) { /* bounds-check... */
183 log_write(LS_SYSTEM
, L_ERROR
, 0,
184 "Attempt to add socket %d (> %d) to event engine", sock
->s_fd
,
190 Debug((DEBUG_ENGINE
, "poll: Allocating a new slot: %d", i
));
193 s_ed_int(sock
) = i
; /* set engine data */
194 sockList
[i
] = sock
; /* enter socket into data structures */
195 pollfdList
[i
].fd
= s_fd(sock
);
197 Debug((DEBUG_ENGINE
, "poll: Adding socket %d to engine on %d [%p], state %s",
198 s_fd(sock
), s_ed_int(sock
), sock
, state_to_name(s_state(sock
))));
200 /* set the appropriate bits */
201 set_or_clear(i
, 0, state_to_events(s_state(sock
), s_events(sock
)));
203 return 1; /* success */
206 /** Handle state transition for a socket.
207 * @param[in] sock Socket changing state.
208 * @param[in] new_state New state for socket.
211 engine_state(struct Socket
* sock
, enum SocketState new_state
)
214 assert(sock
== sockList
[s_ed_int(sock
)]);
215 assert(s_fd(sock
) == pollfdList
[s_ed_int(sock
)].fd
);
217 Debug((DEBUG_ENGINE
, "poll: Changing state for socket %p to %s", sock
,
218 state_to_name(new_state
)));
220 /* set the correct events */
221 set_or_clear(s_ed_int(sock
),
222 state_to_events(s_state(sock
), s_events(sock
)), /* old state */
223 state_to_events(new_state
, s_events(sock
))); /* new state */
226 /** Handle change to preferred socket events.
227 * @param[in] sock Socket getting new interest list.
228 * @param[in] new_events New set of interesting events for socket.
231 engine_events(struct Socket
* sock
, unsigned int new_events
)
234 assert(sock
== sockList
[s_ed_int(sock
)]);
235 assert(s_fd(sock
) == pollfdList
[s_ed_int(sock
)].fd
);
237 Debug((DEBUG_ENGINE
, "poll: Changing event mask for socket %p to [%s]", sock
,
238 sock_flags(new_events
)));
240 /* set the correct events */
241 set_or_clear(s_ed_int(sock
),
242 state_to_events(s_state(sock
), s_events(sock
)), /* old events */
243 state_to_events(s_state(sock
), new_events
)); /* new events */
246 /** Remove a socket from the event engine.
247 * @param[in] sock Socket being destroyed.
250 engine_delete(struct Socket
* sock
)
253 assert(sock
== sockList
[s_ed_int(sock
)]);
254 assert(s_fd(sock
) == pollfdList
[s_ed_int(sock
)].fd
);
256 Debug((DEBUG_ENGINE
, "poll: Deleting socket %d (%d) [%p], state %s",
257 s_fd(sock
), s_ed_int(sock
), sock
, state_to_name(s_state(sock
))));
259 /* clear the events */
260 pollfdList
[s_ed_int(sock
)].fd
= -1;
261 pollfdList
[s_ed_int(sock
)].events
= 0;
263 /* zero the socket list entry */
264 sockList
[s_ed_int(sock
)] = 0;
266 /* update poll_count */
267 while (poll_count
> 0 && sockList
[poll_count
- 1] == 0)
271 /** Run engine event loop.
272 * @param[in] gen Lists of generators of various types.
275 engine_loop(struct Generators
* gen
)
285 wait
= timer_next(gen
) ? (timer_next(gen
) - CurrentTime
) * 1000 : -1;
287 Debug((DEBUG_INFO
, "poll: delay: %Tu (%Tu) %d", timer_next(gen
),
290 /* check for active files */
291 nfds
= poll(pollfdList
, poll_count
, wait
);
293 CurrentTime
= time(0); /* set current time... */
296 if (errno
!= EINTR
) { /* ignore poll interrupts */
297 /* Log the poll error */
298 log_write(LS_SOCKET
, L_ERROR
, 0, "poll() error: %m");
300 timer_add(timer_init(&clear_error
), error_clear
, 0, TT_PERIODIC
,
302 else if (errors
> POLL_ERROR_THRESHOLD
) /* too many errors... */
303 server_restart("too many poll errors");
305 /* old code did a sleep(1) here; with usage these days,
306 * that may be too expensive
311 for (i
= 0; nfds
&& i
< poll_count
; i
++) {
312 if (!(sock
= sockList
[i
])) /* skip empty socket elements */
315 assert(s_fd(sock
) == pollfdList
[i
].fd
);
317 gen_ref_inc(sock
); /* can't have it going away on us */
319 Debug((DEBUG_ENGINE
, "poll: Checking socket %p (fd %d, index %d, "
320 "state %s, events %s", sock
, s_fd(sock
), i
,
321 state_to_name(s_state(sock
)), sock_flags(s_events(sock
))));
323 if (s_state(sock
) != SS_NOTSOCK
) {
324 errcode
= 0; /* check for errors on socket */
325 codesize
= sizeof(errcode
);
326 if (getsockopt(s_fd(sock
), SOL_SOCKET
, SO_ERROR
, &errcode
,
328 errcode
= errno
; /* work around Solaris implementation */
330 if (errcode
) { /* an error occurred; generate an event */
331 Debug((DEBUG_ENGINE
, "poll: Error %d on fd %d (index %d), socket %p",
332 errcode
, s_fd(sock
), i
, sock
));
333 event_generate(ET_ERROR
, sock
, errcode
);
334 gen_ref_dec(sock
); /* careful not to leak ref counts */
341 if (pollfdList
[i
].revents
& POLLHUP
) { /* hang-up on socket */
342 Debug((DEBUG_ENGINE
, "poll: EOF from client (POLLHUP)"));
343 event_generate(ET_EOF
, sock
, 0);
349 switch (s_state(sock
)) {
351 if (pollfdList
[i
].revents
& POLLWRITEFLAGS
) { /* connect completed */
352 Debug((DEBUG_ENGINE
, "poll: Connection completed"));
353 event_generate(ET_CONNECT
, sock
, 0);
359 if (pollfdList
[i
].revents
& POLLREADFLAGS
) { /* ready for accept */
360 Debug((DEBUG_ENGINE
, "poll: Ready for accept"));
361 event_generate(ET_ACCEPT
, sock
, 0);
367 if (pollfdList
[i
].revents
& POLLREADFLAGS
) { /* data on socket */
368 /* can't peek; it's not a socket */
369 Debug((DEBUG_ENGINE
, "poll: non-socket readable"));
370 event_generate(ET_READ
, sock
, 0);
376 if (pollfdList
[i
].revents
& POLLREADFLAGS
) { /* data on socket */
379 switch (recv(s_fd(sock
), &c
, 1, MSG_PEEK
)) { /* check EOF */
380 case -1: /* error occurred?!? */
381 if (errno
== EAGAIN
) {
382 Debug((DEBUG_ENGINE
, "poll: Resource temporarily unavailable?"));
385 Debug((DEBUG_ENGINE
, "poll: Uncaught error!"));
386 event_generate(ET_ERROR
, sock
, errno
);
389 case 0: /* EOF from client */
390 Debug((DEBUG_ENGINE
, "poll: EOF from client"));
391 event_generate(ET_EOF
, sock
, 0);
394 default: /* some data can be read */
395 Debug((DEBUG_ENGINE
, "poll: Data to be read"));
396 event_generate(ET_READ
, sock
, 0);
400 if (pollfdList
[i
].revents
& POLLWRITEFLAGS
) { /* socket writable */
401 Debug((DEBUG_ENGINE
, "poll: Data can be written"));
402 event_generate(ET_WRITE
, sock
, 0);
404 if (pollfdList
[i
].revents
& (POLLREADFLAGS
| POLLWRITEFLAGS
))
408 case SS_DATAGRAM
: case SS_CONNECTDG
:
409 if (pollfdList
[i
].revents
& POLLREADFLAGS
) { /* socket readable */
410 Debug((DEBUG_ENGINE
, "poll: Datagram to be read"));
411 event_generate(ET_READ
, sock
, 0);
413 if (pollfdList
[i
].revents
& POLLWRITEFLAGS
) { /* socket writable */
414 Debug((DEBUG_ENGINE
, "poll: Datagram can be written"));
415 event_generate(ET_WRITE
, sock
, 0);
417 if (pollfdList
[i
].revents
& (POLLREADFLAGS
| POLLWRITEFLAGS
))
422 gen_ref_dec(sock
); /* we're done with it */
425 timer_run(); /* execute any pending timers */
429 /** Descriptor for poll() event engine. */
430 struct Engine engine_poll
= {
431 "poll()", /* Engine name */
432 engine_init
, /* Engine initialization function */
433 0, /* Engine signal registration function */
434 engine_add
, /* Engine socket registration function */
435 engine_state
, /* Engine socket state change function */
436 engine_events
, /* Engine socket events mask function */
437 engine_delete
, /* Engine socket deletion function */
438 engine_loop
/* Core engine event loop */