mirror of
https://github.com/tmux/tmux.git
synced 2024-12-13 18:38:48 +00:00
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:
parent
bf38a311da
commit
93b353d353
218
server.c
218
server.c
@ -45,16 +45,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 *);
|
||||||
@ -72,6 +89,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)
|
||||||
@ -245,7 +331,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;
|
||||||
@ -279,26 +364,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;
|
||||||
@ -306,21 +378,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);
|
||||||
@ -337,8 +411,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();
|
||||||
@ -346,8 +420,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)
|
||||||
@ -464,35 +537,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++) {
|
||||||
@ -501,14 +575,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);
|
||||||
@ -624,12 +699,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);
|
||||||
@ -637,27 +713,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)++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -677,25 +748,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -703,26 +775,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)++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user