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.
This commit is contained in:
Tiago Cunha 2009-10-11 23:25:44 +00:00
parent 0e5f20a97d
commit a4ea6a9d19

220
server.c
View File

@ -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> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -44,16 +44,33 @@
struct clients clients; struct clients clients;
struct clients dead_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); void server_create_client(int);
int server_create_socket(void); int server_create_socket(void);
int server_main(int); int server_main(int);
void server_shutdown(void); void server_shutdown(void);
int server_should_shutdown(void); int server_should_shutdown(void);
void server_child_signal(void); void server_child_signal(void);
void server_fill_windows(struct pollfd **); void server_fill_windows(void);
void server_handle_windows(struct pollfd **); void server_handle_windows(void);
void server_fill_clients(struct pollfd **); void server_fill_clients(void);
void server_handle_clients(struct pollfd **); void server_handle_clients(void);
void server_accept_client(int); void server_accept_client(int);
void server_handle_client(struct client *); void server_handle_client(struct client *);
void server_handle_window(struct window *, struct window_pane *); void server_handle_window(struct window *, struct window_pane *);
@ -71,6 +88,75 @@ void server_check_timers(struct client *);
void server_second_timers(void); void server_second_timers(void);
int server_update_socket(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. */ /* Create a new client. */
void void
server_create_client(int fd) server_create_client(int fd)
@ -248,7 +334,6 @@ server_create_socket(void)
int int
server_main(int srv_fd) server_main(int srv_fd)
{ {
struct window *w;
struct pollfd *pfds, *pfd; struct pollfd *pfds, *pfd;
int nfds, xtimeout; int nfds, xtimeout;
u_int i; u_int i;
@ -282,26 +367,13 @@ server_main(int srv_fd)
sigusr1 = 0; sigusr1 = 0;
} }
/* Initialise pollfd array. */ /* Initialise pollfd array and add server socket. */
nfds = 1; server_poll_reset();
for (i = 0; i < ARRAY_LENGTH(&windows); i++) { server_poll_add(srv_fd, POLLIN);
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++;
/* Fill window and client sockets. */ /* Fill window and client sockets. */
server_fill_windows(&pfd); server_fill_windows();
server_fill_clients(&pfd); server_fill_clients();
/* Update socket permissions. */ /* Update socket permissions. */
xtimeout = INFTIM; xtimeout = INFTIM;
@ -309,21 +381,23 @@ server_main(int srv_fd)
xtimeout = POLL_TIMEOUT; xtimeout = POLL_TIMEOUT;
/* Do the poll. */ /* Do the poll. */
pfds = server_poll_flatten(&nfds);
log_debug("polling %d", nfds);
if (poll(pfds, nfds, xtimeout) == -1) { if (poll(pfds, nfds, xtimeout) == -1) {
if (errno == EAGAIN || errno == EINTR) if (errno == EAGAIN || errno == EINTR)
continue; continue;
fatal("poll failed"); fatal("poll failed");
} }
pfd = pfds; server_poll_parse(pfds);
/* Handle server socket. */ /* Handle server socket. */
pfd = server_poll_lookup(srv_fd);
if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP))
fatalx("lost server socket"); fatalx("lost server socket");
if (pfd->revents & POLLIN) { if (pfd->revents & POLLIN) {
server_accept_client(srv_fd); server_accept_client(srv_fd);
continue; continue;
} }
pfd++;
/* Call second-based timers. */ /* Call second-based timers. */
now = time(NULL); now = time(NULL);
@ -340,8 +414,8 @@ server_main(int srv_fd)
* windows, so windows must come first to avoid messing up by * windows, so windows must come first to avoid messing up by
* increasing the array size. * increasing the array size.
*/ */
server_handle_windows(&pfd); server_handle_windows();
server_handle_clients(&pfd); server_handle_clients();
/* Collect any unset key bindings. */ /* Collect any unset key bindings. */
key_bindings_clean(); key_bindings_clean();
@ -349,8 +423,7 @@ server_main(int srv_fd)
/* Collect dead clients and sessions. */ /* Collect dead clients and sessions. */
server_clean_dead(); server_clean_dead();
} }
if (pfds != NULL) server_poll_reset();
xfree(pfds);
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
if (ARRAY_ITEM(&sessions, i) != NULL) if (ARRAY_ITEM(&sessions, i) != NULL)
@ -467,35 +540,36 @@ server_child_signal(void)
/* Fill window pollfds. */ /* Fill window pollfds. */
void void
server_fill_windows(struct pollfd **pfd) server_fill_windows(void)
{ {
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp;
u_int i; u_int i;
int events;
for (i = 0; i < ARRAY_LENGTH(&windows); i++) { for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
w = ARRAY_ITEM(&windows, i); w = ARRAY_ITEM(&windows, i);
if (w == NULL) if (w == NULL)
continue; continue;
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
(*pfd)->fd = wp->fd; if (wp->fd == -1)
if (wp->fd != -1) { continue;
(*pfd)->events = POLLIN; events = POLLIN;
if (BUFFER_USED(wp->out) > 0) if (BUFFER_USED(wp->out) > 0)
(*pfd)->events |= POLLOUT; events |= POLLOUT;
} server_poll_add(wp->fd, events);
(*pfd)++;
} }
} }
} }
/* Handle window pollfds. */ /* Handle window pollfds. */
void void
server_handle_windows(struct pollfd **pfd) server_handle_windows(void)
{ {
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp;
struct pollfd *pfd;
u_int i; u_int i;
for (i = 0; i < ARRAY_LENGTH(&windows); i++) { for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
@ -504,14 +578,15 @@ server_handle_windows(struct pollfd **pfd)
continue; continue;
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->fd != -1) { if (wp->fd == -1)
if (buffer_poll(*pfd, wp->in, wp->out) != 0) { continue;
close(wp->fd); if ((pfd = server_poll_lookup(wp->fd)) == NULL)
wp->fd = -1; continue;
} else if (buffer_poll(pfd, wp->in, wp->out) != 0) {
server_handle_window(w, wp); close(wp->fd);
} wp->fd = -1;
(*pfd)++; } else
server_handle_window(w, wp);
} }
server_check_window(w); server_check_window(w);
@ -627,12 +702,13 @@ server_check_timers(struct client *c)
/* Fill client pollfds. */ /* Fill client pollfds. */
void void
server_fill_clients(struct pollfd **pfd) server_fill_clients(void)
{ {
struct client *c; struct client *c;
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp;
u_int i; u_int i;
int events;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
@ -640,27 +716,22 @@ server_fill_clients(struct pollfd **pfd)
server_check_timers(c); server_check_timers(c);
server_check_redraw(c); server_check_redraw(c);
if (c == NULL) if (c != NULL) {
(*pfd)->fd = -1; events = 0;
else {
(*pfd)->fd = c->ibuf.fd;
if (!(c->flags & CLIENT_BAD)) if (!(c->flags & CLIENT_BAD))
(*pfd)->events |= POLLIN; events |= POLLIN;
if (c->ibuf.w.queued > 0) 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 || if (c != NULL && !(c->flags & CLIENT_SUSPENDED) &&
c->tty.fd == -1 || c->session == NULL) c->tty.fd != -1 && c->session != NULL) {
(*pfd)->fd = -1; events = POLLIN;
else {
(*pfd)->fd = c->tty.fd;
(*pfd)->events = POLLIN;
if (BUFFER_USED(c->tty.out) > 0) 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. */ /* Handle client pollfds. */
void void
server_handle_clients(struct pollfd **pfd) server_handle_clients(void)
{ {
struct client *c; struct client *c;
struct pollfd *pfd;
u_int i; u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i); c = ARRAY_ITEM(&clients, i);
if (c != NULL) { 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); server_lost_client(c);
(*pfd) += 2;
continue; continue;
} }
if ((*pfd)->revents & POLLOUT) { if (pfd->revents & POLLOUT) {
if (msgbuf_write(&c->ibuf.w) < 0) { if (msgbuf_write(&c->ibuf.w) < 0) {
server_lost_client(c); server_lost_client(c);
(*pfd) += 2;
continue; continue;
} }
} }
@ -706,26 +778,24 @@ server_handle_clients(struct pollfd **pfd)
if (c->flags & CLIENT_BAD) { if (c->flags & CLIENT_BAD) {
if (c->ibuf.w.queued == 0) if (c->ibuf.w.queued == 0)
server_lost_client(c); server_lost_client(c);
(*pfd) += 2;
continue; continue;
} else if ((*pfd)->revents & POLLIN) { } else if (pfd->revents & POLLIN) {
if (server_msg_dispatch(c) != 0) { if (server_msg_dispatch(c) != 0) {
server_lost_client(c); server_lost_client(c);
(*pfd) += 2;
continue; continue;
} }
} }
} }
(*pfd)++;
if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && if (c != NULL && !(c->flags & CLIENT_SUSPENDED) &&
c->tty.fd != -1 && c->session != NULL) { 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); server_lost_client(c);
else else
server_handle_client(c); server_handle_client(c);
} }
(*pfd)++;
} }
} }