X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fengine_devpoll.c;h=e4fd20042120a216556f95cef53bb6b860170a4a;hb=f50e98744ac3e53605d59a2f313d610c9abc8f26;hp=8bd9c75511708b0c454d96e0846d22b35b6ace4d;hpb=fda30451cac5936729c683d38a700f4928812c6f;p=ircu2.10.12-pk.git diff --git a/ircd/engine_devpoll.c b/ircd/engine_devpoll.c index 8bd9c75..e4fd200 100644 --- a/ircd/engine_devpoll.c +++ b/ircd/engine_devpoll.c @@ -15,8 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id$ + */ +/** @file + * @brief Solaris /dev/poll event engine. + * @version $Id$ */ #include "config.h" @@ -24,10 +26,11 @@ #include "ircd.h" #include "ircd_alloc.h" +#include "ircd_features.h" #include "ircd_log.h" #include "s_debug.h" -#include +/* #include -- Now using assert in ircd_log.h */ #include #include #include @@ -37,10 +40,8 @@ #include #include -#define DEVPOLL_ERROR_THRESHOLD 20 /* after 20 devpoll errors, restart */ -#define ERROR_EXPIRE_TIME 3600 /* expire errors after an hour */ - -#define POLLS_PER_DEVPOLL 20 /* get 20 pollfd's per turn */ +#define DEVPOLL_ERROR_THRESHOLD 20 /**< after 20 devpoll errors, restart */ +#define ERROR_EXPIRE_TIME 3600 /**< expire errors after an hour */ /* Figure out what bits to set for read */ #if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM) @@ -62,21 +63,27 @@ # define POLLWRITEFLAGS POLLWRNORM #endif -/* Figure out what bits indicate errors */ -#ifdef POLLHUP -# define POLLERRORS (POLLHUP|POLLERR) -#else -# define POLLERRORS POLLERR -#endif - +/** Array of active Socket structures, indexed by file descriptor. */ static struct Socket** sockList; +/** Maximum file descriptor supported, plus one. */ static int devpoll_max; +/** File descriptor for /dev/poll device. */ static int devpoll_fd; +/** Number of recent errors from /dev/poll. */ static int errors = 0; +/** Periodic timer to forget errors. */ static struct Timer clear_error; - -/* decrements the error count once per hour */ +/** Array of currently polled file descriptors. */ +static struct pollfd *polls; +/** Number of ::polls elements that have been populated. */ +static int polls_used; +/** Current processing position in ::polls. */ +static int polls_i; + +/** Decrement the error count (once per hour). + * @param[in] ev Expired timer event (ignored). + */ static void error_clear(struct Event* ev) { @@ -84,7 +91,10 @@ error_clear(struct Event* ev) timer_del(ev_timer(ev)); } -/* initialize the devpoll engine */ +/** Initialize the /dev/poll engine. + * @param[in] max_sockets Maximum number of file descriptors to support. + * @return Non-zero on success, or zero on failure. + */ static int engine_init(int max_sockets) { @@ -108,7 +118,11 @@ engine_init(int max_sockets) return 1; } -/* Figure out what events go with a given state */ +/** Figure out what events go with a given state. + * @param[in] state %Socket state to consider. + * @param[in] events User-specified preferred event set. + * @return Actual set of preferred events. + */ static unsigned int state_to_events(enum SocketState state, unsigned int events) { @@ -131,7 +145,10 @@ state_to_events(enum SocketState state, unsigned int events) return 0; } -/* Reset the desired events */ +/** Set the desired events for a socket. + * @param[in,out] sock Socket to operate on. + * @param[in] events User-specified preferred event set. + */ static void set_events(struct Socket* sock, unsigned int events) { @@ -174,7 +191,10 @@ set_events(struct Socket* sock, unsigned int events) s_ed_int(sock) = 1; /* mark that we've added a pollfd */ } -/* add a socket to be listened on */ +/** Add a socket to the event engine. + * @param[in] sock Socket to add to engine. + * @return Non-zero on success, or zero on error. + */ static int engine_add(struct Socket* sock) { @@ -200,7 +220,10 @@ engine_add(struct Socket* sock) return 1; /* success */ } -/* socket switching to new state */ +/** Handle state transition for a socket. + * @param[in] sock Socket changing state. + * @param[in] new_state New state for socket. + */ static void engine_state(struct Socket* sock, enum SocketState new_state) { @@ -214,7 +237,10 @@ engine_state(struct Socket* sock, enum SocketState new_state) set_events(sock, state_to_events(new_state, s_events(sock))); } -/* socket events changing */ +/** Handle change to preferred socket events. + * @param[in] sock Socket getting new interest list. + * @param[in] new_events New set of interesting events for socket. + */ static void engine_events(struct Socket* sock, unsigned int new_events) { @@ -228,10 +254,14 @@ engine_events(struct Socket* sock, unsigned int new_events) set_events(sock, state_to_events(s_state(sock), new_events)); } -/* socket going away */ +/** Remove a socket from the event engine. + * @param[in] sock Socket being destroyed. + */ static void engine_delete(struct Socket* sock) { + int ii; + assert(0 != sock); assert(sock == sockList[s_fd(sock)]); @@ -241,42 +271,61 @@ engine_delete(struct Socket* sock) set_events(sock, 0); /* get rid of the socket */ sockList[s_fd(sock)] = 0; /* zero the socket list entry */ + + /* Drop any unprocessed events citing this socket. */ + for (ii = polls_i; ii < polls_used; ii++) { + if (polls[ii].fd == s_fd(sock)) { + polls[ii] = polls[--polls_used]; + } + } } -/* engine event loop */ +/** Run engine event loop. + * @param[in] gen Lists of generators of various types. + */ static void engine_loop(struct Generators* gen) { struct dvpoll dopoll; - struct pollfd polls[POLLS_PER_DEVPOLL]; + int polls_count; struct Socket* sock; + struct pollfd *pfd; int nfds; int i; int errcode; - size_t codesize; + socklen_t codesize; + + if ((polls_count = feature_int(FEAT_POLLS_PER_LOOP)) < 20) + polls_count = 20; + polls = (struct pollfd *)MyMalloc(sizeof(struct pollfd) * polls_count); while (running) { + if ((i = feature_int(FEAT_POLLS_PER_LOOP)) >= 20 && i != polls_count) { + polls = (struct pollfd *)MyRealloc(polls, sizeof(struct pollfd) * i); + polls_count = i; + } + dopoll.dp_fds = polls; /* set up the struct dvpoll */ - dopoll.dp_nfds = POLLS_PER_DEVPOLL; + dopoll.dp_nfds = polls_count; /* calculate the proper timeout */ dopoll.dp_timeout = timer_next(gen) ? (timer_next(gen) - CurrentTime) * 1000 : -1; - Debug((DEBUG_INFO, "devpoll: delay: %Tu (%Tu) %d", timer_next(gen), + Debug((DEBUG_ENGINE, "devpoll: delay: %Tu (%Tu) %d", timer_next(gen), CurrentTime, dopoll.dp_timeout)); /* check for active files */ - nfds = ioctl(devpoll_fd, DP_POLL, &dopoll); + polls_used = ioctl(devpoll_fd, DP_POLL, &dopoll); CurrentTime = time(0); /* set current time... */ - if (nfds < 0) { + if (polls_used < 0) { if (errno != EINTR) { /* ignore interrupts */ /* Log the poll error */ log_write(LS_SOCKET, L_ERROR, 0, "ioctl(DP_POLL) error: %m"); if (!errors++) - timer_add(&clear_error, error_clear, 0, TT_PERIODIC, + timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC, ERROR_EXPIRE_TIME); else if (errors > DEVPOLL_ERROR_THRESHOLD) /* too many errors... */ server_restart("too many /dev/poll errors"); @@ -287,15 +336,16 @@ engine_loop(struct Generators* gen) continue; } - for (i = 0; i < nfds; i++) { - assert(-1 < polls[i].fd); - assert(0 != sockList[polls[i].fd]); - assert(s_fd(sockList[polls[i].fd]) == polls[i].fd); + for (polls_i = 0; polls_i < polls_used; polls_i++) { + pfd = &polls[polls_i]; + assert(-1 < pfd->fd); - sock = sockList[polls[i].fd]; + sock = sockList[pfd->fd]; if (!sock) /* slots may become empty while processing events */ continue; + assert(s_fd(sock) == pfd->fd); + gen_ref_inc(sock); /* can't have it going away on us */ Debug((DEBUG_ENGINE, "devpoll: Checking socket %p (fd %d) state %s, " @@ -318,23 +368,34 @@ engine_loop(struct Generators* gen) } } + assert(!(pfd->revents & POLLERR)); + +#ifdef POLLHUP + if (pfd->revents & POLLHUP) { /* hang-up on socket */ + Debug((DEBUG_ENGINE, "devpoll: EOF from client (POLLHUP)")); + event_generate(ET_EOF, sock, 0); + nfds--; + continue; + } +#endif /* POLLHUP */ + switch (s_state(sock)) { case SS_CONNECTING: - if (polls[i].revents & POLLWRITEFLAGS) { /* connection completed */ + if (pfd->revents & POLLWRITEFLAGS) { /* connection completed */ Debug((DEBUG_ENGINE, "devpoll: Connection completed")); event_generate(ET_CONNECT, sock, 0); } break; case SS_LISTENING: - if (polls[i].revents & POLLREADFLAGS) { /* connect. to be accept. */ + if (pfd->revents & POLLREADFLAGS) { /* connect. to be accept. */ Debug((DEBUG_ENGINE, "devpoll: Ready for accept")); event_generate(ET_ACCEPT, sock, 0); } break; case SS_NOTSOCK: - if (polls[i].revents & POLLREADFLAGS) { /* data on socket */ + if (pfd->revents & POLLREADFLAGS) { /* data on socket */ /* can't peek; it's not a socket */ Debug((DEBUG_ENGINE, "devpoll: non-socket readable")); event_generate(ET_READ, sock, 0); @@ -342,7 +403,7 @@ engine_loop(struct Generators* gen) break; case SS_CONNECTED: - if (polls[i].revents & POLLREADFLAGS) { /* data on socket */ + if (pfd->revents & POLLREADFLAGS) { /* data on socket */ char c; switch (recv(s_fd(sock), &c, 1, MSG_PEEK)) { /* check EOF */ @@ -367,26 +428,24 @@ engine_loop(struct Generators* gen) break; } } - if (polls[i].revents & POLLWRITEFLAGS) { /* socket writable */ + if (pfd->revents & POLLWRITEFLAGS) { /* socket writable */ Debug((DEBUG_ENGINE, "devpoll: Data can be written")); event_generate(ET_WRITE, sock, 0); } break; case SS_DATAGRAM: case SS_CONNECTDG: - if (polls[i].revents & POLLREADFLAGS) { /* socket readable */ + if (pfd->revents & POLLREADFLAGS) { /* socket readable */ Debug((DEBUG_ENGINE, "devpoll: Datagram to be read")); event_generate(ET_READ, sock, 0); } - if (polls[i].revents & POLLWRITEFLAGS) { /* socket writable */ + if (pfd->revents & POLLWRITEFLAGS) { /* socket writable */ Debug((DEBUG_ENGINE, "devpoll: Datagram can be written")); event_generate(ET_WRITE, sock, 0); } break; } - assert(s_fd(sock) == polls[i].fd); - gen_ref_dec(sock); /* we're done with it */ } @@ -394,6 +453,7 @@ engine_loop(struct Generators* gen) } } +/** Descriptor for /dev/poll event engine. */ struct Engine engine_devpoll = { "/dev/poll", /* Engine name */ engine_init, /* Engine initialization function */