Rather than running status-left, status-right and window title #() with popen

immediately every redraw, queue them up and run them in the background,
starting each once every status-interval. The actual status line uses the
output from the last run.

This brings several advantages:

- tmux itself may be called from inside #() without causing the server to hang;
- likewise, sleep or similar doesn't cause the server to block;
- commands aren't run excessively often when redrawing;
- commands shared by status-left and status-right, or used multiple times, will
  only be run once.

run-shell and if-shell still use system()/popen() but will be changed over to
use this too later.
This commit is contained in:
Nicholas Marriott
2009-10-10 15:03:01 +00:00
parent 4658c063d5
commit 6bca92db4d
9 changed files with 364 additions and 46 deletions

View File

@ -72,6 +72,10 @@ void server_fill_windows(void);
void server_handle_windows(void);
void server_fill_clients(void);
void server_handle_clients(void);
void server_fill_jobs(void);
void server_fill_jobs1(struct jobs *);
void server_handle_jobs(void);
void server_handle_jobs1(struct jobs *);
void server_accept_client(int);
void server_handle_client(struct client *);
void server_handle_window(struct window *, struct window_pane *);
@ -190,7 +194,9 @@ server_create_client(int fd)
c->session = NULL;
c->tty.sx = 80;
c->tty.sy = 24;
screen_init(&c->status, c->tty.sx, 1, 0);
job_tree_init(&c->status_jobs);
c->message_string = NULL;
@ -370,6 +376,7 @@ server_main(int srv_fd)
server_poll_add(srv_fd, POLLIN);
/* Fill window and client sockets. */
server_fill_jobs();
server_fill_windows();
server_fill_clients();
@ -412,6 +419,7 @@ server_main(int srv_fd)
* windows, so windows must come first to avoid messing up by
* increasing the array size.
*/
server_handle_jobs();
server_handle_windows();
server_handle_clients();
@ -648,7 +656,7 @@ server_set_title(struct client *c)
template = options_get_string(&s->options, "set-titles-string");
title = status_replace(c->session, template, time(NULL));
title = status_replace(c, template, time(NULL));
if (c->title == NULL || strcmp(title, c->title) != 0) {
if (c->title != NULL)
xfree(c->title);
@ -663,6 +671,7 @@ void
server_check_timers(struct client *c)
{
struct session *s;
struct job *job;
struct timeval tv;
u_int interval;
@ -694,8 +703,12 @@ server_check_timers(struct client *c)
if (interval == 0)
return;
if (tv.tv_sec < c->status_timer.tv_sec ||
((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval)
((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) {
/* Run the jobs for this client and schedule for redraw. */
RB_FOREACH(job, jobs, &c->status_jobs)
job_run(job);
c->flags |= CLIENT_STATUS;
}
}
/* Fill client pollfds. */
@ -747,6 +760,66 @@ server_fill_clients(void)
}
}
/* Fill in job fds. */
void
server_fill_jobs(void)
{
struct client *c;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL)
server_fill_jobs1(&c->status_jobs);
}
}
void
server_fill_jobs1(struct jobs *jobs)
{
struct job *job;
RB_FOREACH(job, jobs, jobs) {
if (job->fd == -1)
continue;
server_poll_add(job->fd, POLLIN);
}
}
/* Handle job fds. */
void
server_handle_jobs(void)
{
struct client *c;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
c = ARRAY_ITEM(&clients, i);
if (c != NULL)
server_handle_jobs1(&c->status_jobs);
}
}
void
server_handle_jobs1(struct jobs *jobs)
{
struct job *job;
struct pollfd *pfd;
RB_FOREACH(job, jobs, jobs) {
if (job->fd == -1)
continue;
if ((pfd = server_poll_lookup(job->fd)) == NULL)
continue;
if (buffer_poll(pfd, job->out, NULL) != 0) {
close(job->fd);
job->fd = -1;
if (job->callbackfn != NULL)
job->callbackfn(job);
}
}
}
/* Handle client pollfds. */
void
server_handle_clients(void)
@ -991,6 +1064,7 @@ server_lost_client(struct client *c)
tty_free(&c->tty);
screen_free(&c->status);
job_tree_free(&c->status_jobs);
if (c->title != NULL)
xfree(c->title);