diff options
author | Tiago Cunha <tcunha@gmx.com> | 2009-10-11 23:25:44 +0000 |
---|---|---|
committer | Tiago Cunha <tcunha@gmx.com> | 2009-10-11 23:25:44 +0000 |
commit | a4ea6a9d19ef9dc4290a9cd15e352a414198d268 (patch) | |
tree | a6eb5097016407888440d2feef669d806eb23059 | |
parent | 0e5f20a97dd341bb16b5551406c253c1c95ee9e9 (diff) | |
download | rtmux-a4ea6a9d19ef9dc4290a9cd15e352a414198d268.tar.gz rtmux-a4ea6a9d19ef9dc4290a9cd15e352a414198d268.tar.bz2 rtmux-a4ea6a9d19ef9dc4290a9cd15e352a414198d268.zip |
Sync OpenBSD patchset 369:
Instead of passing a struct pollfd ** around through various functions, build
them into a tree and then convert into a flat poll array before and after poll.
This adds a little code but should reduce annoying problems with ordering when
adding new things that also need to be polled.
-rw-r--r-- | server.c | 222 |
1 files changed, 146 insertions, 76 deletions
@@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.195 2009-10-06 14:00:50 tcunha Exp $ */ +/* $Id: server.c,v 1.196 2009-10-11 23:25:44 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -44,16 +44,33 @@ struct clients clients; struct clients dead_clients; +/* Mapping of a pollfd to an fd independent of its position in the array. */ +struct poll_item { + struct pollfd pfd; + + RB_ENTRY(poll_item) entry; +}; +RB_HEAD(poll_items, poll_item) poll_items; + +int server_poll_cmp(struct poll_item *, struct poll_item *); +struct pollfd *server_poll_lookup(int); +void server_poll_add(int, int); +struct pollfd *server_poll_flatten(int *); +void server_poll_parse(struct pollfd *); +void server_poll_reset(void); +RB_PROTOTYPE(poll_items, poll_item, entry, server_poll_cmp); +RB_GENERATE(poll_items, poll_item, entry, server_poll_cmp); + void server_create_client(int); int server_create_socket(void); int server_main(int); void server_shutdown(void); int server_should_shutdown(void); void server_child_signal(void); -void server_fill_windows(struct pollfd **); -void server_handle_windows(struct pollfd **); -void server_fill_clients(struct pollfd **); -void server_handle_clients(struct pollfd **); +void server_fill_windows(void); +void server_handle_windows(void); +void server_fill_clients(void); +void server_handle_clients(void); void server_accept_client(int); void server_handle_client(struct client *); void server_handle_window(struct window *, struct window_pane *); @@ -71,6 +88,75 @@ void server_check_timers(struct client *); void server_second_timers(void); int server_update_socket(void); +int +server_poll_cmp(struct poll_item *pitem1, struct poll_item *pitem2) +{ + return (pitem1->pfd.fd - pitem2->pfd.fd); +} + +struct pollfd * +server_poll_lookup(int fd) +{ + struct poll_item pitem; + + pitem.pfd.fd = fd; + return (&RB_FIND(poll_items, &poll_items, &pitem)->pfd); +} + +void +server_poll_add(int fd, int events) +{ + struct poll_item *pitem; + + pitem = xmalloc(sizeof *pitem); + pitem->pfd.fd = fd; + pitem->pfd.events = events; + RB_INSERT(poll_items, &poll_items, pitem); +} + +struct pollfd * +server_poll_flatten(int *nfds) +{ + struct poll_item *pitem; + struct pollfd *pfds; + + pfds = NULL; + *nfds = 0; + RB_FOREACH(pitem, poll_items, &poll_items) { + pfds = xrealloc(pfds, (*nfds) + 1, sizeof *pfds); + pfds[*nfds].fd = pitem->pfd.fd; + pfds[*nfds].events = pitem->pfd.events; + (*nfds)++; + } + return (pfds); +} + +void +server_poll_parse(struct pollfd *pfds) +{ + struct poll_item *pitem; + int nfds; + + nfds = 0; + RB_FOREACH(pitem, poll_items, &poll_items) { + pitem->pfd.revents = pfds[nfds].revents; + nfds++; + } + xfree(pfds); +} + +void +server_poll_reset(void) +{ + struct poll_item *pitem; + + while (!RB_EMPTY(&poll_items)) { + pitem = RB_ROOT(&poll_items); + RB_REMOVE(poll_items, &poll_items, pitem); + xfree(pitem); + } +} + /* Create a new client. */ void server_create_client(int fd) @@ -248,7 +334,6 @@ server_create_socket(void) int server_main(int srv_fd) { - struct window *w; struct pollfd *pfds, *pfd; int nfds, xtimeout; u_int i; @@ -282,26 +367,13 @@ server_main(int srv_fd) sigusr1 = 0; } - /* Initialise pollfd array. */ - nfds = 1; - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w != NULL) - nfds += window_count_panes(w); - } - nfds += ARRAY_LENGTH(&clients) * 2; - pfds = xrealloc(pfds, nfds, sizeof *pfds); - memset(pfds, 0, nfds * sizeof *pfds); - pfd = pfds; - - /* Fill server socket. */ - pfd->fd = srv_fd; - pfd->events = POLLIN; - pfd++; + /* Initialise pollfd array and add server socket. */ + server_poll_reset(); + server_poll_add(srv_fd, POLLIN); /* Fill window and client sockets. */ - server_fill_windows(&pfd); - server_fill_clients(&pfd); + server_fill_windows(); + server_fill_clients(); /* Update socket permissions. */ xtimeout = INFTIM; @@ -309,21 +381,23 @@ server_main(int srv_fd) xtimeout = POLL_TIMEOUT; /* Do the poll. */ + pfds = server_poll_flatten(&nfds); + log_debug("polling %d", nfds); if (poll(pfds, nfds, xtimeout) == -1) { if (errno == EAGAIN || errno == EINTR) continue; fatal("poll failed"); } - pfd = pfds; + server_poll_parse(pfds); /* Handle server socket. */ + pfd = server_poll_lookup(srv_fd); if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) fatalx("lost server socket"); if (pfd->revents & POLLIN) { server_accept_client(srv_fd); continue; } - pfd++; /* Call second-based timers. */ now = time(NULL); @@ -340,8 +414,8 @@ server_main(int srv_fd) * windows, so windows must come first to avoid messing up by * increasing the array size. */ - server_handle_windows(&pfd); - server_handle_clients(&pfd); + server_handle_windows(); + server_handle_clients(); /* Collect any unset key bindings. */ key_bindings_clean(); @@ -349,8 +423,7 @@ server_main(int srv_fd) /* Collect dead clients and sessions. */ server_clean_dead(); } - if (pfds != NULL) - xfree(pfds); + server_poll_reset(); for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { if (ARRAY_ITEM(&sessions, i) != NULL) @@ -467,35 +540,36 @@ server_child_signal(void) /* Fill window pollfds. */ void -server_fill_windows(struct pollfd **pfd) +server_fill_windows(void) { struct window *w; struct window_pane *wp; u_int i; + int events; for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); if (w == NULL) continue; - TAILQ_FOREACH(wp, &w->panes, entry) { - (*pfd)->fd = wp->fd; - if (wp->fd != -1) { - (*pfd)->events = POLLIN; - if (BUFFER_USED(wp->out) > 0) - (*pfd)->events |= POLLOUT; - } - (*pfd)++; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->fd == -1) + continue; + events = POLLIN; + if (BUFFER_USED(wp->out) > 0) + events |= POLLOUT; + server_poll_add(wp->fd, events); } } } /* Handle window pollfds. */ void -server_handle_windows(struct pollfd **pfd) +server_handle_windows(void) { struct window *w; struct window_pane *wp; + struct pollfd *pfd; u_int i; for (i = 0; i < ARRAY_LENGTH(&windows); i++) { @@ -504,14 +578,15 @@ server_handle_windows(struct pollfd **pfd) continue; TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->fd != -1) { - if (buffer_poll(*pfd, wp->in, wp->out) != 0) { - close(wp->fd); - wp->fd = -1; - } else - server_handle_window(w, wp); - } - (*pfd)++; + if (wp->fd == -1) + continue; + if ((pfd = server_poll_lookup(wp->fd)) == NULL) + continue; + if (buffer_poll(pfd, wp->in, wp->out) != 0) { + close(wp->fd); + wp->fd = -1; + } else + server_handle_window(w, wp); } server_check_window(w); @@ -627,12 +702,13 @@ server_check_timers(struct client *c) /* Fill client pollfds. */ void -server_fill_clients(struct pollfd **pfd) +server_fill_clients(void) { struct client *c; struct window *w; struct window_pane *wp; u_int i; + int events; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); @@ -640,27 +716,22 @@ server_fill_clients(struct pollfd **pfd) server_check_timers(c); server_check_redraw(c); - if (c == NULL) - (*pfd)->fd = -1; - else { - (*pfd)->fd = c->ibuf.fd; + if (c != NULL) { + events = 0; if (!(c->flags & CLIENT_BAD)) - (*pfd)->events |= POLLIN; + events |= POLLIN; if (c->ibuf.w.queued > 0) - (*pfd)->events |= POLLOUT; + events |= POLLOUT; + server_poll_add(c->ibuf.fd, events); } - (*pfd)++; - - if (c == NULL || c->flags & CLIENT_SUSPENDED || - c->tty.fd == -1 || c->session == NULL) - (*pfd)->fd = -1; - else { - (*pfd)->fd = c->tty.fd; - (*pfd)->events = POLLIN; + + if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && + c->tty.fd != -1 && c->session != NULL) { + events = POLLIN; if (BUFFER_USED(c->tty.out) > 0) - (*pfd)->events |= POLLOUT; + events |= POLLOUT; + server_poll_add(c->tty.fd, events); } - (*pfd)++; } /* @@ -680,25 +751,26 @@ server_fill_clients(struct pollfd **pfd) /* Handle client pollfds. */ void -server_handle_clients(struct pollfd **pfd) +server_handle_clients(void) { struct client *c; + struct pollfd *pfd; u_int i; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c != NULL) { - if ((*pfd)->revents & (POLLERR|POLLNVAL|POLLHUP)) { + if ((pfd = server_poll_lookup(c->ibuf.fd)) == NULL) + continue; + if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) { server_lost_client(c); - (*pfd) += 2; continue; } - if ((*pfd)->revents & POLLOUT) { + if (pfd->revents & POLLOUT) { if (msgbuf_write(&c->ibuf.w) < 0) { server_lost_client(c); - (*pfd) += 2; continue; } } @@ -706,26 +778,24 @@ server_handle_clients(struct pollfd **pfd) if (c->flags & CLIENT_BAD) { if (c->ibuf.w.queued == 0) server_lost_client(c); - (*pfd) += 2; continue; - } else if ((*pfd)->revents & POLLIN) { + } else if (pfd->revents & POLLIN) { if (server_msg_dispatch(c) != 0) { server_lost_client(c); - (*pfd) += 2; continue; } } } - (*pfd)++; if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && c->tty.fd != -1 && c->session != NULL) { - if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0) + if ((pfd = server_poll_lookup(c->tty.fd)) == NULL) + continue; + if (buffer_poll(pfd, c->tty.in, c->tty.out) != 0) server_lost_client(c); else server_handle_client(c); } - (*pfd)++; } } |