From 899e629bf0bc6053112cec5b65a63f1dd2330001 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 19 Oct 2016 09:22:07 +0000 Subject: [PATCH] Alerts are too slow, so rather than walking all sessions and windows, add a link of winlinks to each window and a pointer to the session to each winlink. Also rewrite the alerts processing to return to the old behaviour (alert in any window sets the flag on any winlink). --- alerts.c | 248 +++++++++++++++++++++++++++--------------------- server-client.c | 9 +- session.c | 8 +- tmux.h | 8 +- window.c | 39 ++++---- 5 files changed, 179 insertions(+), 133 deletions(-) diff --git a/alerts.c b/alerts.c index ef869ae8..e0b2bf01 100644 --- a/alerts.c +++ b/alerts.c @@ -19,6 +19,7 @@ #include #include +#include #include "tmux.h" @@ -29,13 +30,16 @@ static int alerts_enabled(struct window *, int); static void alerts_callback(int, short, void *); static void alerts_reset(struct window *); -static void alerts_run_hook(struct session *, struct winlink *, int); -static int alerts_check_all(struct session *, struct winlink *); -static int alerts_check_bell(struct session *, struct winlink *); -static int alerts_check_activity(struct session *, struct winlink *); -static int alerts_check_silence(struct session *, struct winlink *); +static int alerts_check_all(struct window *); +static int alerts_check_bell(struct window *); +static int alerts_check_activity(struct window *); +static int alerts_check_silence(struct window *); +static void printflike(2, 3) alerts_set_message(struct session *, const char *, + ...); static void alerts_ring_bell(struct session *); +static TAILQ_HEAD(, window) alerts_list = TAILQ_HEAD_INITIALIZER(alerts_list); + static void alerts_timer(__unused int fd, __unused short events, void *arg) { @@ -49,53 +53,28 @@ alerts_timer(__unused int fd, __unused short events, void *arg) static void alerts_callback(__unused int fd, __unused short events, __unused void *arg) { - struct window *w; - struct session *s; - struct winlink *wl; - int flags, alerts; + struct window *w, *w1; + int alerts; - RB_FOREACH(w, windows, &windows) { - RB_FOREACH(s, sessions, &sessions) { - RB_FOREACH(wl, winlinks, &s->windows) { - if (wl->window != w) - continue; - flags = w->flags; + TAILQ_FOREACH_SAFE(w, &alerts_list, alerts_entry, w1) { + alerts = alerts_check_all(w); + log_debug("@%u alerts check, alerts %#x", w->id, alerts); - alerts = alerts_check_all(s, wl); - - log_debug("%s:%d @%u alerts check, alerts %#x, " - "flags %#x", s->name, wl->idx, w->id, - alerts, flags); - } - } + w->alerts_queued = 0; + TAILQ_REMOVE(&alerts_list, w, alerts_entry); + window_remove_ref(w); } alerts_fired = 0; } -static void -alerts_run_hook(struct session *s, struct winlink *wl, int flags) -{ - if (flags & WINDOW_BELL) - notify_winlink("alert-bell", s, wl); - if (flags & WINDOW_SILENCE) - notify_winlink("alert-silence", s, wl); - if (flags & WINDOW_ACTIVITY) - notify_winlink("alert-activity", s, wl); -} - static int -alerts_check_all(struct session *s, struct winlink *wl) +alerts_check_all(struct window *w) { int alerts; - alerts = alerts_check_bell(s, wl); - alerts |= alerts_check_activity(s, wl); - alerts |= alerts_check_silence(s, wl); - if (alerts != 0) { - alerts_run_hook(s, wl, alerts); - server_status_session(s); - } - + alerts = alerts_check_bell(w); + alerts |= alerts_check_activity(w); + alerts |= alerts_check_silence(w); return (alerts); } @@ -105,7 +84,7 @@ alerts_check_session(struct session *s) struct winlink *wl; RB_FOREACH(wl, winlinks, &s->windows) - alerts_check_all(s, wl); + alerts_check_all(wl->window); } static int @@ -163,6 +142,12 @@ alerts_queue(struct window *w, int flags) log_debug("@%u alerts flags added %#x", w->id, flags); } + if (!w->alerts_queued) { + w->alerts_queued = 1; + TAILQ_INSERT_TAIL(&alerts_list, w, alerts_entry); + w->references++; + } + if (!alerts_fired && alerts_enabled(w, flags)) { log_debug("alerts check queued (by @%u)", w->id); event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL); @@ -171,112 +156,157 @@ alerts_queue(struct window *w, int flags) } static int -alerts_check_bell(struct session *s, struct winlink *wl) +alerts_check_bell(struct window *w) { + struct window *ws; + struct winlink *wl; + struct session *s; struct client *c; - struct window *w = wl->window; int action, visual; - if (!(w->flags & WINDOW_BELL)) - return (0); - if (s->curw != wl) { - wl->flags |= WINLINK_BELL; - w->flags &= ~WINDOW_BELL; - } - if (s->curw->window == w) - w->flags &= ~WINDOW_BELL; - - action = options_get_number(s->options, "bell-action"); - if (action == BELL_NONE) + if (~w->flags & WINDOW_BELL) return (0); - visual = options_get_number(s->options, "visual-bell"); - TAILQ_FOREACH(c, &clients, entry) { - if (c->session != s || c->flags & CLIENT_CONTROL) - continue; - if (!visual) { - if ((action == BELL_CURRENT && - c->session->curw->window == w) || - (action == BELL_OTHER && - c->session->curw->window != w) || - action == BELL_ANY) - tty_putcode(&c->tty, TTYC_BEL); + TAILQ_FOREACH(wl, &w->winlinks, wentry) + wl->session->flags &= ~SESSION_ALERTED; + + TAILQ_FOREACH(wl, &w->winlinks, wentry) { + if (wl->flags & WINLINK_BELL) continue; + s = wl->session; + if (s->curw != wl) { + wl->flags |= WINLINK_BELL; + notify_winlink("alert-bell", s, wl); + } + + if (s->flags & SESSION_ALERTED) + continue; + s->flags |= SESSION_ALERTED; + + action = options_get_number(s->options, "bell-action"); + if (action == BELL_NONE) + return (0); + + visual = options_get_number(s->options, "visual-bell"); + TAILQ_FOREACH(c, &clients, entry) { + if (c->session != s || c->flags & CLIENT_CONTROL) + continue; + ws = c->session->curw->window; + + if (action == BELL_CURRENT && ws != w) + action = BELL_NONE; + if (action == BELL_OTHER && ws != w) + action = BELL_NONE; + + if (!visual) { + if (action != BELL_NONE) + tty_putcode(&c->tty, TTYC_BEL); + continue; + } + if (action == BELL_CURRENT) + status_message_set(c, "Bell in current window"); + else if (action != BELL_NONE) { + status_message_set(c, "Bell in window %d", + wl->idx); + } } - if (action == BELL_CURRENT && c->session->curw->window == w) - status_message_set(c, "Bell in current window"); - else if (action == BELL_ANY || (action == BELL_OTHER && - c->session->curw->window != w)) - status_message_set(c, "Bell in window %d", wl->idx); } return (WINDOW_BELL); } static int -alerts_check_activity(struct session *s, struct winlink *wl) +alerts_check_activity(struct window *w) { - struct client *c; - struct window *w = wl->window; + struct winlink *wl; + struct session *s; - if (s->curw->window == w) - w->flags &= ~WINDOW_ACTIVITY; - - if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY) + if (~w->flags & WINDOW_ACTIVITY) return (0); - if (s->curw == wl) - return (0); - if (!options_get_number(w->options, "monitor-activity")) return (0); - if (options_get_number(s->options, "bell-on-alert")) - alerts_ring_bell(s); - wl->flags |= WINLINK_ACTIVITY; + TAILQ_FOREACH(wl, &w->winlinks, wentry) + wl->session->flags &= ~SESSION_ALERTED; - if (options_get_number(s->options, "visual-activity")) { - TAILQ_FOREACH(c, &clients, entry) { - if (c->session != s) - continue; - status_message_set(c, "Activity in window %d", wl->idx); + TAILQ_FOREACH(wl, &w->winlinks, wentry) { + if (wl->flags & WINLINK_ACTIVITY) + continue; + s = wl->session; + if (s->curw != wl) { + wl->flags |= WINLINK_ACTIVITY; + notify_winlink("alert-activity", s, wl); } + + if (s->flags & SESSION_ALERTED) + continue; + s->flags |= SESSION_ALERTED; + + if (options_get_number(s->options, "bell-on-alert")) + alerts_ring_bell(s); + if (options_get_number(s->options, "visual-activity")) + alerts_set_message(s, "Activity in window %d", wl->idx); } return (WINDOW_ACTIVITY); } static int -alerts_check_silence(struct session *s, struct winlink *wl) +alerts_check_silence(struct window *w) { - struct client *c; - struct window *w = wl->window; + struct winlink *wl; + struct session *s; - if (s->curw->window == w) - w->flags &= ~WINDOW_SILENCE; - - if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE) + if (~w->flags & WINDOW_SILENCE) return (0); - if (s->curw == wl) + if (!options_get_number(w->options, "monitor-silence")) return (0); - if (options_get_number(w->options, "monitor-silence") == 0) - return (0); + TAILQ_FOREACH(wl, &w->winlinks, wentry) + wl->session->flags &= ~SESSION_ALERTED; - if (options_get_number(s->options, "bell-on-alert")) - alerts_ring_bell(s); - wl->flags |= WINLINK_SILENCE; - - if (options_get_number(s->options, "visual-silence")) { - TAILQ_FOREACH(c, &clients, entry) { - if (c->session != s) - continue; - status_message_set(c, "Silence in window %d", wl->idx); + TAILQ_FOREACH(wl, &w->winlinks, wentry) { + if (wl->flags & WINLINK_SILENCE) + continue; + s = wl->session; + if (s->curw != wl) { + wl->flags |= WINLINK_SILENCE; + notify_winlink("alert-silence", s, wl); } + + if (s->flags & SESSION_ALERTED) + continue; + s->flags |= SESSION_ALERTED; + + if (options_get_number(s->options, "bell-on-alert")) + alerts_ring_bell(s); + + if (!options_get_number(s->options, "visual-silence")) + alerts_set_message(s, "Silence in window %d", wl->idx); } return (WINDOW_SILENCE); } +static void +alerts_set_message(struct session *s, const char *fmt, ...) +{ + struct client *c; + va_list ap; + char *message; + + va_start(ap, fmt); + xvasprintf(&message, fmt, ap); + va_end(ap); + + TAILQ_FOREACH(c, &clients, entry) { + if (c->session == s) + status_message_set(c, "%s", message); + } + + free(message); +} + static void alerts_ring_bell(struct session *s) { diff --git a/server-client.c b/server-client.c index 98a28738..b92bada5 100644 --- a/server-client.c +++ b/server-client.c @@ -853,6 +853,7 @@ server_client_loop(void) struct client *c; struct window *w; struct window_pane *wp; + int focus; TAILQ_FOREACH(c, &clients, entry) { server_client_check_exit(c); @@ -866,11 +867,13 @@ server_client_loop(void) * Any windows will have been redrawn as part of clients, so clear * their flags now. Also check pane focus and resize. */ + focus = options_get_number(global_options, "focus-events"); RB_FOREACH(w, windows, &windows) { w->flags &= ~WINDOW_REDRAW; TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->fd != -1) { - server_client_check_focus(wp); + if (focus) + server_client_check_focus(wp); server_client_check_resize(wp); } wp->flags &= ~PANE_REDRAW; @@ -937,10 +940,6 @@ server_client_check_focus(struct window_pane *wp) struct client *c; int push; - /* Are focus events off? */ - if (!options_get_number(global_options, "focus-events")) - return; - /* Do we need to push the focus state? */ push = wp->flags & PANE_FOCUSPUSH; wp->flags &= ~PANE_FOCUSPUSH; diff --git a/session.c b/session.c index fa43a74e..19a6f139 100644 --- a/session.c +++ b/session.c @@ -337,6 +337,7 @@ session_new(struct session *s, const char *name, int argc, char **argv, xasprintf(cause, "index in use: %d", idx); return (NULL); } + wl->session = s; env = environ_create(); environ_copy(global_environ, env); @@ -373,6 +374,7 @@ session_attach(struct session *s, struct window *w, int idx, char **cause) xasprintf(cause, "index in use: %d", idx); return (NULL); } + wl->session = s; winlink_set_window(wl, w); notify_session_window("window-linked", s, w); @@ -409,8 +411,8 @@ session_has(struct session *s, struct window *w) { struct winlink *wl; - RB_FOREACH(wl, winlinks, &s->windows) { - if (wl->window == w) + TAILQ_FOREACH(wl, &w->winlinks, wentry) { + if (wl->session == s) return (1); } return (0); @@ -679,6 +681,7 @@ session_group_synchronize1(struct session *target, struct session *s) /* Link all the windows from the target. */ RB_FOREACH(wl, winlinks, ww) { wl2 = winlink_add(&s->windows, wl->idx); + wl2->session = s; winlink_set_window(wl2, wl->window); notify_session_window("window-linked", s, wl2->window); wl2->flags |= wl->flags & WINLINK_ALERTFLAGS; @@ -729,6 +732,7 @@ session_renumber_windows(struct session *s) /* Go through the winlinks and assign new indexes. */ RB_FOREACH(wl, winlinks, &old_wins) { wl_new = winlink_add(&s->windows, new_idx); + wl_new->session = s; winlink_set_window(wl_new, wl->window); wl_new->flags |= wl->flags & WINLINK_ALERTFLAGS; diff --git a/tmux.h b/tmux.h index ae4b75dd..1ec2d3ca 100644 --- a/tmux.h +++ b/tmux.h @@ -889,12 +889,16 @@ struct window { #define WINDOW_STYLECHANGED 0x8000 #define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) + int alerts_queued; + TAILQ_ENTRY(window) alerts_entry; + struct options *options; struct grid_cell style; struct grid_cell active_style; u_int references; + TAILQ_HEAD(, winlink) winlinks; RB_ENTRY(window) entry; }; @@ -903,6 +907,7 @@ RB_HEAD(windows, window); /* Entry on local window list. */ struct winlink { int idx; + struct session *session; struct window *window; size_t status_width; @@ -916,6 +921,7 @@ struct winlink { #define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_SILENCE) RB_ENTRY(winlink) entry; + TAILQ_ENTRY(winlink) wentry; TAILQ_ENTRY(winlink) sentry; }; RB_HEAD(winlinks, winlink); @@ -990,6 +996,7 @@ struct session { #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ #define SESSION_PASTING 0x2 +#define SESSION_ALERTED 0x4 int flags; u_int attached; @@ -2069,7 +2076,6 @@ struct window *window_create(u_int, u_int); struct window *window_create_spawn(const char *, int, char **, const char *, const char *, const char *, struct environ *, struct termios *, u_int, u_int, u_int, char **); -void window_destroy(struct window *); struct window_pane *window_get_active_at(struct window *, u_int, u_int); struct window_pane *window_find_string(struct window *, const char *); int window_has_pane(struct window *, struct window_pane *); diff --git a/window.c b/window.c index 8ef54084..56878a19 100644 --- a/window.c +++ b/window.c @@ -60,6 +60,8 @@ static u_int next_window_pane_id; static u_int next_window_id; static u_int next_active_point; +static void window_destroy(struct window *); + static struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); static void window_pane_destroy(struct window_pane *); @@ -184,6 +186,11 @@ winlink_add(struct winlinks *wwl, int idx) void winlink_set_window(struct winlink *wl, struct window *w) { + if (wl->window != NULL) { + TAILQ_REMOVE(&wl->window->winlinks, wl, wentry); + window_remove_ref(w); + } + TAILQ_INSERT_TAIL(&w->winlinks, wl, wentry); wl->window = w; w->references++; } @@ -193,12 +200,14 @@ winlink_remove(struct winlinks *wwl, struct winlink *wl) { struct window *w = wl->window; + if (w != NULL) { + TAILQ_REMOVE(&w->winlinks, wl, wentry); + window_remove_ref(w); + } + RB_REMOVE(winlinks, wwl, wl); free(wl->status_text); free(wl); - - if (w != NULL) - window_remove_ref(w); } struct winlink * @@ -313,6 +322,7 @@ window_create(u_int sx, u_int sy) w->options = options_create(global_w_options); w->references = 0; + TAILQ_INIT(&w->winlinks); w->id = next_window_id++; RB_INSERT(windows, &windows, w); @@ -350,9 +360,12 @@ window_create_spawn(const char *name, int argc, char **argv, const char *path, return (w); } -void +static void window_destroy(struct window *w) { + if (!TAILQ_EMPTY(&w->winlinks)) + fatalx("window destroyed with winlinks"); + RB_REMOVE(windows, &windows, w); if (w->layout_root != NULL) @@ -1421,19 +1434,13 @@ window_pane_find_right(struct window_pane *wp) void winlink_clear_flags(struct winlink *wl) { - struct session *s; - struct winlink *wl_loop; + struct winlink *loop; - RB_FOREACH(s, sessions, &sessions) { - RB_FOREACH(wl_loop, winlinks, &s->windows) { - if (wl_loop->window != wl->window) - continue; - if ((wl_loop->flags & WINLINK_ALERTFLAGS) == 0) - continue; - - wl_loop->flags &= ~WINLINK_ALERTFLAGS; - wl_loop->window->flags &= ~WINDOW_ALERTFLAGS; - server_status_session(s); + wl->window->flags &= ~WINDOW_ALERTFLAGS; + TAILQ_FOREACH(loop, &wl->window->winlinks, wentry) { + if ((loop->flags & WINLINK_ALERTFLAGS) != 0) { + loop->flags &= ~WINLINK_ALERTFLAGS; + server_status_session(loop->session); } } }