Store sessions in an RB tree by name rather than a list, this is tidier

and allows them to easily be shown sorted in various lists
(list-sessions/choose-sessions).

Keep a session index which is used in a couple of places internally but
make it an ever-increasing number rather than filling in gaps with new
sessions.
This commit is contained in:
Nicholas Marriott 2010-12-21 22:37:59 +00:00
parent 1b8488ee75
commit acf13ce978
12 changed files with 143 additions and 183 deletions

View File

@ -47,7 +47,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
char *overrides, *cause; char *overrides, *cause;
u_int i; u_int i;
if (ARRAY_LENGTH(&sessions) == 0) { if (RB_EMPTY(&sessions)) {
ctx->error(ctx, "no sessions"); ctx->error(ctx, "no sessions");
return (-1); return (-1);
} }

View File

@ -55,7 +55,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
struct winlink *wl; struct winlink *wl;
struct session *s; struct session *s;
struct session_group *sg; struct session_group *sg;
u_int i, idx, sgidx, cur; u_int idx, sgidx, cur;
char tmp[64]; char tmp[64];
if (ctx->curclient == NULL) { if (ctx->curclient == NULL) {
@ -70,10 +70,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
return (0); return (0);
cur = idx = 0; cur = idx = 0;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
if (s == ctx->curclient->session) if (s == ctx->curclient->session)
cur = idx; cur = idx;
idx++; idx++;
@ -86,7 +83,7 @@ cmd_choose_session_exec(struct cmd *self, struct cmd_ctx *ctx)
xsnprintf(tmp, sizeof tmp, " (group %u)", sgidx); xsnprintf(tmp, sizeof tmp, " (group %u)", sgidx);
} }
window_choose_add(wl->window->active, i, window_choose_add(wl->window->active, s->idx,
"%s: %u windows [%ux%u]%s%s", s->name, "%s: %u windows [%ux%u]%s%s", s->name,
winlink_count(&s->windows), s->sx, s->sy, winlink_count(&s->windows), s->sx, s->sy,
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
@ -120,9 +117,7 @@ cmd_choose_session_callback(void *data, int idx)
if (cdata->client->flags & CLIENT_DEAD) if (cdata->client->flags & CLIENT_DEAD)
return; return;
if ((u_int) idx > ARRAY_LENGTH(&sessions) - 1) s = session_find_by_index(idx);
return;
s = ARRAY_ITEM(&sessions, idx);
if (s == NULL) if (s == NULL)
return; return;
template = cmd_template_replace(cdata->template, s->name, 1); template = cmd_template_replace(cdata->template, s->name, 1);

View File

@ -46,14 +46,10 @@ cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
struct session *s; struct session *s;
struct session_group *sg; struct session_group *sg;
char *tim, tmp[64]; char *tim, tmp[64];
u_int i, idx; u_int idx;
time_t t; time_t t;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
sg = session_group_find(s); sg = session_group_find(s);
if (sg == NULL) if (sg == NULL)
*tmp = '\0'; *tmp = '\0';

View File

@ -53,8 +53,10 @@ cmd_rename_session_exec(struct cmd *self, struct cmd_ctx *ctx)
if ((s = cmd_find_session(ctx, data->target)) == NULL) if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1); return (-1);
RB_REMOVE(sessions, &sessions, s);
xfree(s->name); xfree(s->name);
s->name = xstrdup(data->arg); s->name = xstrdup(data->arg);
RB_INSERT(sessions, &sessions, s);
server_status_session(s); server_status_session(s);

View File

@ -81,8 +81,6 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
else else
ctx->print(ctx, "configuration file not specified"); ctx->print(ctx, "configuration file not specified");
ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION); ctx->print(ctx, "protocol version is %d", PROTOCOL_VERSION);
ctx->print(ctx, "%u clients, %u sessions",
ARRAY_LENGTH(&clients), ARRAY_LENGTH(&sessions));
ctx->print(ctx, "%s", ""); ctx->print(ctx, "%s", "");
ctx->print(ctx, "Clients:"); ctx->print(ctx, "Clients:");
@ -101,19 +99,14 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
ctx->print(ctx, "Sessions: [%zu/%zu]", ctx->print(ctx, "Sessions: [%zu/%zu]",
sizeof (struct grid_cell), sizeof (struct grid_utf8)); sizeof (struct grid_cell), sizeof (struct grid_utf8));
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
t = s->creation_time.tv_sec; t = s->creation_time.tv_sec;
tim = ctime(&t); tim = ctime(&t);
*strchr(tim, '\n') = '\0'; *strchr(tim, '\n') = '\0';
ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] " ctx->print(ctx, "%2u: %s: %u windows (created %s) [%ux%u] "
"[flags=0x%x, references=%u]", i, s->name, "[flags=0x%x]", s->idx, s->name,
winlink_count(&s->windows), tim, s->sx, s->sy, s->flags, winlink_count(&s->windows), tim, s->sx, s->sy, s->flags);
s->references);
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
w = wl->window; w = wl->window;
ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, " ctx->print(ctx, "%4u: %s [%ux%u] [flags=0x%x, "

57
cmd.c
View File

@ -112,7 +112,8 @@ const struct cmd_entry *cmd_table[] = {
NULL NULL
}; };
struct session *cmd_choose_session(struct sessions *); struct session *cmd_choose_session_list(struct sessionslist *);
struct session *cmd_choose_session(void);
struct client *cmd_choose_client(struct clients *); struct client *cmd_choose_client(struct clients *);
struct client *cmd_lookup_client(const char *); struct client *cmd_lookup_client(const char *);
struct session *cmd_lookup_session(const char *, int *); struct session *cmd_lookup_session(const char *, int *);
@ -316,10 +317,9 @@ cmd_current_session(struct cmd_ctx *ctx)
struct msg_command_data *data = ctx->msgdata; struct msg_command_data *data = ctx->msgdata;
struct client *c = ctx->cmdclient; struct client *c = ctx->cmdclient;
struct session *s; struct session *s;
struct sessions ss; struct sessionslist ss;
struct winlink *wl; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
u_int i;
int found; int found;
if (ctx->curclient != NULL && ctx->curclient->session != NULL) if (ctx->curclient != NULL && ctx->curclient->session != NULL)
@ -332,9 +332,7 @@ cmd_current_session(struct cmd_ctx *ctx)
*/ */
if (c != NULL && c->tty.path != NULL) { if (c != NULL && c->tty.path != NULL) {
ARRAY_INIT(&ss); ARRAY_INIT(&ss);
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
found = 0; found = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
@ -350,25 +348,43 @@ cmd_current_session(struct cmd_ctx *ctx)
ARRAY_ADD(&ss, s); ARRAY_ADD(&ss, s);
} }
s = cmd_choose_session(&ss); s = cmd_choose_session_list(&ss);
ARRAY_FREE(&ss); ARRAY_FREE(&ss);
if (s != NULL) if (s != NULL)
return (s); return (s);
} }
/* Use the session from the TMUX environment variable. */ /* Use the session from the TMUX environment variable. */
if (data != NULL && if (data != NULL && data->pid == getpid()) {
data->pid == getpid() && s = session_find_by_index(data->idx);
data->idx <= ARRAY_LENGTH(&sessions) && if (s != NULL)
(s = ARRAY_ITEM(&sessions, data->idx)) != NULL) return (s);
return (s); }
return (cmd_choose_session(&sessions)); return (cmd_choose_session());
}
/* Find the most recently used session. */
struct session *
cmd_choose_session(void)
{
struct session *s, *sbest;
struct timeval *tv = NULL;
sbest = NULL;
RB_FOREACH(s, sessions, &sessions) {
if (tv == NULL || timercmp(&s->activity_time, tv, >)) {
sbest = s;
tv = &s->activity_time;
}
}
return (sbest);
} }
/* Find the most recently used session from a list. */ /* Find the most recently used session from a list. */
struct session * struct session *
cmd_choose_session(struct sessions *ss) cmd_choose_session_list(struct sessionslist *ss)
{ {
struct session *s, *sbest; struct session *s, *sbest;
struct timeval *tv = NULL; struct timeval *tv = NULL;
@ -516,7 +532,6 @@ struct session *
cmd_lookup_session(const char *name, int *ambiguous) cmd_lookup_session(const char *name, int *ambiguous)
{ {
struct session *s, *sfound; struct session *s, *sfound;
u_int i;
*ambiguous = 0; *ambiguous = 0;
@ -525,21 +540,15 @@ cmd_lookup_session(const char *name, int *ambiguous)
* be unique so an exact match can't be ambigious and can just be * be unique so an exact match can't be ambigious and can just be
* returned. * returned.
*/ */
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { if ((s = session_find(name)) != NULL)
if ((s = ARRAY_ITEM(&sessions, i)) == NULL) return (s);
continue;
if (strcmp(name, s->name) == 0)
return (s);
}
/* /*
* Otherwise look for partial matches, returning early if it is found to * Otherwise look for partial matches, returning early if it is found to
* be ambiguous. * be ambiguous.
*/ */
sfound = NULL; sfound = NULL;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (strncmp(name, s->name, strlen(name)) == 0 || if (strncmp(name, s->name, strlen(name)) == 0 ||
fnmatch(name, s->name, 0) == 0) { fnmatch(name, s->name, 0) == 0) {
if (sfound != NULL) { if (sfound != NULL) {

View File

@ -52,11 +52,7 @@ recalculate_sizes(void)
u_int i, j, ssx, ssy, has, limit; u_int i, j, ssx, ssy, has, limit;
int flag; int flag;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
s = ARRAY_ITEM(&sessions, i);
if (s == NULL)
continue;
ssx = ssy = UINT_MAX; ssx = ssy = UINT_MAX;
for (j = 0; j < ARRAY_LENGTH(&clients); j++) { for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
c = ARRAY_ITEM(&clients, j); c = ARRAY_ITEM(&clients, j);
@ -98,9 +94,8 @@ recalculate_sizes(void)
flag = options_get_number(&w->options, "aggressive-resize"); flag = options_get_number(&w->options, "aggressive-resize");
ssx = ssy = UINT_MAX; ssx = ssy = UINT_MAX;
for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { RB_FOREACH(s, sessions, &sessions) {
s = ARRAY_ITEM(&sessions, j); if (s->flags & SESSION_UNATTACHED)
if (s == NULL || s->flags & SESSION_UNATTACHED)
continue; continue;
if (flag) if (flag)
has = s->curw->window == w; has = s->curw->window == w;

View File

@ -30,13 +30,10 @@ void server_callback_identify(int, short, void *);
void void
server_fill_environ(struct session *s, struct environ *env) server_fill_environ(struct session *s, struct environ *env)
{ {
char tmuxvar[MAXPATHLEN], *term; char tmuxvar[MAXPATHLEN], *term;
u_int idx;
if (session_index(s, &idx) != 0)
fatalx("session not found");
xsnprintf(tmuxvar, sizeof tmuxvar, xsnprintf(tmuxvar, sizeof tmuxvar,
"%s,%ld,%u", socket_path, (long) getpid(), idx); "%s,%ld,%u", socket_path, (long) getpid(), s->idx);
environ_set(env, "TMUX", tmuxvar); environ_set(env, "TMUX", tmuxvar);
term = options_get_string(&s->options, "default-terminal"); term = options_get_string(&s->options, "default-terminal");
@ -175,7 +172,6 @@ void
server_status_window(struct window *w) server_status_window(struct window *w)
{ {
struct session *s; struct session *s;
u_int i;
/* /*
* This is slightly different. We want to redraw the status line of any * This is slightly different. We want to redraw the status line of any
@ -183,9 +179,8 @@ server_status_window(struct window *w)
* current window. * current window.
*/ */
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
s = ARRAY_ITEM(&sessions, i); if (session_has(s, w) != NULL)
if (s != NULL && session_has(s, w) != NULL)
server_status_session(s); server_status_session(s);
} }
} }
@ -246,11 +241,9 @@ server_kill_window(struct window *w)
{ {
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
s = ARRAY_ITEM(&sessions, i); if (session_has(s, w) == NULL)
if (s == NULL || session_has(s, w) == NULL)
continue; continue;
while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) { while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) {
if (session_detach(s, wl)) { if (session_detach(s, wl)) {
@ -365,12 +358,10 @@ struct session *
server_next_session(struct session *s) server_next_session(struct session *s)
{ {
struct session *s_loop, *s_out; struct session *s_loop, *s_out;
u_int i;
s_out = NULL; s_out = NULL;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s_loop, sessions, &sessions) {
s_loop = ARRAY_ITEM(&sessions, i); if (s_loop == s)
if (s_loop == NULL || s_loop == s)
continue; continue;
if (s_out == NULL || if (s_out == NULL ||
timercmp(&s_loop->activity_time, &s_out->activity_time, <)) timercmp(&s_loop->activity_time, &s_out->activity_time, <))
@ -411,15 +402,13 @@ void
server_check_unattached (void) server_check_unattached (void)
{ {
struct session *s; struct session *s;
u_int i;
/* /*
* If any sessions are no longer attached and have destroy-unattached * If any sessions are no longer attached and have destroy-unattached
* set, collect them. * set, collect them.
*/ */
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
s = ARRAY_ITEM(&sessions, i); if (!(s->flags & SESSION_UNATTACHED))
if (s == NULL || !(s->flags & SESSION_UNATTACHED))
continue; continue;
if (options_get_number (&s->options, "destroy-unattached")) if (options_get_number (&s->options, "destroy-unattached"))
session_destroy(s); session_destroy(s);

View File

@ -38,17 +38,14 @@ server_window_loop(void)
struct winlink *wl; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
struct session *s; struct session *s;
u_int i, j; u_int i;
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;
for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { RB_FOREACH(s, sessions, &sessions) {
s = ARRAY_ITEM(&sessions, j);
if (s == NULL)
continue;
wl = session_has(s, w); wl = session_has(s, w);
if (wl == NULL) if (wl == NULL)
continue; continue;

View File

@ -147,8 +147,8 @@ server_start(void)
ARRAY_INIT(&windows); ARRAY_INIT(&windows);
ARRAY_INIT(&clients); ARRAY_INIT(&clients);
ARRAY_INIT(&dead_clients); ARRAY_INIT(&dead_clients);
ARRAY_INIT(&sessions); RB_INIT(&sessions);
ARRAY_INIT(&dead_sessions); RB_INIT(&dead_sessions);
TAILQ_INIT(&session_groups); TAILQ_INIT(&session_groups);
mode_key_init_trees(); mode_key_init_trees();
key_bindings_init(); key_bindings_init();
@ -174,8 +174,8 @@ server_start(void)
* If there is a session already, put the current window and pane into * If there is a session already, put the current window and pane into
* more mode. * more mode.
*/ */
if (!ARRAY_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) { if (!RB_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) {
wp = ARRAY_FIRST(&sessions)->curw->window->active; wp = RB_MIN(sessions, &sessions)->curw->window->active;
window_pane_set_mode(wp, &window_copy_mode); window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp); window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) { for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
@ -223,10 +223,8 @@ server_should_shutdown(void)
u_int i; u_int i;
if (!options_get_number(&global_options, "exit-unattached")) { if (!options_get_number(&global_options, "exit-unattached")) {
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { if (!RB_EMPTY(&sessions))
if (ARRAY_ITEM(&sessions, i) != NULL) return (0);
return (0);
}
} }
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if (ARRAY_ITEM(&clients, i) != NULL) if (ARRAY_ITEM(&clients, i) != NULL)
@ -240,7 +238,7 @@ void
server_send_shutdown(void) server_send_shutdown(void)
{ {
struct client *c; struct client *c;
struct session *s; struct session *s, *next_s;
u_int i; u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@ -254,9 +252,11 @@ server_send_shutdown(void)
} }
} }
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s = RB_MIN(sessions, &sessions);
if ((s = ARRAY_ITEM(&sessions, i)) != NULL) while (s != NULL) {
session_destroy(s); next_s = RB_NEXT(sessions, &sessions, s);
session_destroy(s);
s = next_s;
} }
} }
@ -264,16 +264,19 @@ server_send_shutdown(void)
void void
server_clean_dead(void) server_clean_dead(void)
{ {
struct session *s; struct session *s, *next_s;
struct client *c; struct client *c;
u_int i; u_int i;
for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) { s = RB_MIN(sessions, &dead_sessions);
s = ARRAY_ITEM(&dead_sessions, i); while (s != NULL) {
if (s == NULL || s->references != 0) next_s = RB_NEXT(sessions, &dead_sessions, s);
continue; if (s->references == 0) {
ARRAY_SET(&dead_sessions, i, NULL); RB_REMOVE(sessions, &dead_sessions, s);
xfree(s); xfree(s->name);
xfree(s);
}
s = next_s;
} }
for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
@ -290,15 +293,13 @@ void
server_update_socket(void) server_update_socket(void)
{ {
struct session *s; struct session *s;
u_int i;
static int last = -1; static int last = -1;
int n, mode; int n, mode;
struct stat sb; struct stat sb;
n = 0; n = 0;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
s = ARRAY_ITEM(&sessions, i); if (!(s->flags & SESSION_UNATTACHED)) {
if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
n++; n++;
break; break;
} }
@ -485,15 +486,11 @@ void
server_lock_server(void) server_lock_server(void)
{ {
struct session *s; struct session *s;
u_int i;
int timeout; int timeout;
time_t t; time_t t;
t = time(NULL); t = time(NULL);
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (s->flags & SESSION_UNATTACHED) { if (s->flags & SESSION_UNATTACHED) {
if (gettimeofday(&s->activity_time, NULL) != 0) if (gettimeofday(&s->activity_time, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday failed");
@ -514,15 +511,11 @@ void
server_lock_sessions(void) server_lock_sessions(void)
{ {
struct session *s; struct session *s;
u_int i;
int timeout; int timeout;
time_t t; time_t t;
t = time(NULL); t = time(NULL);
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { RB_FOREACH(s, sessions, &sessions) {
if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
continue;
if (s->flags & SESSION_UNATTACHED) { if (s->flags & SESSION_UNATTACHED) {
if (gettimeofday(&s->activity_time, NULL) != 0) if (gettimeofday(&s->activity_time, NULL) != 0)
fatal("gettimeofday failed"); fatal("gettimeofday failed");

113
session.c
View File

@ -30,11 +30,20 @@
/* Global session list. */ /* Global session list. */
struct sessions sessions; struct sessions sessions;
struct sessions dead_sessions; struct sessions dead_sessions;
u_int next_session;
struct session_groups session_groups; struct session_groups session_groups;
struct winlink *session_next_alert(struct winlink *); struct winlink *session_next_alert(struct winlink *);
struct winlink *session_previous_alert(struct winlink *); struct winlink *session_previous_alert(struct winlink *);
RB_GENERATE(sessions, session, entry, session_cmp);
int
session_cmp(struct session *s1, struct session *s2)
{
return (strcmp(s1->name, s2->name));
}
/* /*
* Find if session is still alive. This is true if it is still on the global * Find if session is still alive. This is true if it is still on the global
* sessions list. * sessions list.
@ -42,24 +51,35 @@ struct winlink *session_previous_alert(struct winlink *);
int int
session_alive(struct session *s) session_alive(struct session *s)
{ {
u_int idx; struct session *s_loop;
return (session_index(s, &idx) == 0); RB_FOREACH(s_loop, sessions, &sessions) {
if (s_loop == s)
return (1);
}
return (0);
} }
/* Find session by name. */ /* Find session by name. */
struct session * struct session *
session_find(const char *name) session_find(const char *name)
{ {
struct session *s; struct session s;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s.name = (char *) name;
s = ARRAY_ITEM(&sessions, i); return (RB_FIND(sessions, &sessions, &s));
if (s != NULL && strcmp(s->name, name) == 0) }
/* Find session by index. */
struct session *
session_find_by_index(u_int idx)
{
struct session *s;
RB_FOREACH(s, sessions, &sessions) {
if (s->idx == idx)
return (s); return (s);
} }
return (NULL); return (NULL);
} }
@ -70,7 +90,6 @@ session_create(const char *name, const char *cmd, const char *cwd,
char **cause) char **cause)
{ {
struct session *s; struct session *s;
u_int i;
s = xmalloc(sizeof *s); s = xmalloc(sizeof *s);
s->references = 0; s->references = 0;
@ -102,19 +121,12 @@ session_create(const char *name, const char *cmd, const char *cwd,
s->sx = sx; s->sx = sx;
s->sy = sy; s->sy = sy;
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { s->idx = next_session++;
if (ARRAY_ITEM(&sessions, i) == NULL) {
ARRAY_SET(&sessions, i, s);
break;
}
}
if (i == ARRAY_LENGTH(&sessions))
ARRAY_ADD(&sessions, s);
if (name != NULL) if (name != NULL)
s->name = xstrdup(name); s->name = xstrdup(name);
else else
xasprintf(&s->name, "%u", i); xasprintf(&s->name, "%u", s->idx);
RB_INSERT(sessions, &sessions, s);
if (cmd != NULL) { if (cmd != NULL) {
if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) { if (session_new(s, NULL, cmd, cwd, idx, cause) == NULL) {
@ -133,15 +145,9 @@ session_create(const char *name, const char *cmd, const char *cwd,
void void
session_destroy(struct session *s) session_destroy(struct session *s)
{ {
u_int i;
log_debug("session %s destroyed", s->name); log_debug("session %s destroyed", s->name);
if (session_index(s, &i) != 0) RB_REMOVE(sessions, &sessions, s);
fatalx("session not found");
ARRAY_SET(&sessions, i, NULL);
while (!ARRAY_EMPTY(&sessions) && ARRAY_LAST(&sessions) == NULL)
ARRAY_TRUNC(&sessions, 1);
if (s->tio != NULL) if (s->tio != NULL)
xfree(s->tio); xfree(s->tio);
@ -157,27 +163,8 @@ session_destroy(struct session *s)
winlink_remove(&s->windows, RB_ROOT(&s->windows)); winlink_remove(&s->windows, RB_ROOT(&s->windows));
xfree(s->cwd); xfree(s->cwd);
xfree(s->name);
for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) { RB_INSERT(sessions, &dead_sessions, s);
if (ARRAY_ITEM(&dead_sessions, i) == NULL) {
ARRAY_SET(&dead_sessions, i, s);
break;
}
}
if (i == ARRAY_LENGTH(&dead_sessions))
ARRAY_ADD(&dead_sessions, s);
}
/* Find session index. */
int
session_index(struct session *s, u_int *i)
{
for (*i = 0; *i < ARRAY_LENGTH(&sessions); (*i)++) {
if (s == ARRAY_ITEM(&sessions, *i))
return (0);
}
return (-1);
} }
/* Find the next usable session. */ /* Find the next usable session. */
@ -185,19 +172,18 @@ struct session *
session_next_session(struct session *s) session_next_session(struct session *s)
{ {
struct session *s2; struct session *s2;
u_int i;
if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) if (RB_EMPTY(&sessions) || !session_alive(s))
return (NULL); return (NULL);
s2 = s;
do { do {
if (i == ARRAY_LENGTH(&sessions) - 1) s2 = RB_NEXT(sessions, &sessions, s2);
i = 0; if (s2 == NULL)
else s2 = RB_MIN(sessions, &sessions);
i++; } while (s2 != s);
s2 = ARRAY_ITEM(&sessions, i); if (s2 == s)
} while (s2 == NULL); return (NULL);
return (s2); return (s2);
} }
@ -206,19 +192,18 @@ struct session *
session_previous_session(struct session *s) session_previous_session(struct session *s)
{ {
struct session *s2; struct session *s2;
u_int i;
if (ARRAY_LENGTH(&sessions) == 0 || session_index(s, &i) != 0) if (RB_EMPTY(&sessions) || !session_alive(s))
return (NULL); return (NULL);
s2 = s;
do { do {
if (i == 0) s2 = RB_PREV(sessions, &sessions, s2);
i = ARRAY_LENGTH(&sessions) - 1; if (s2 == NULL)
else s2 = RB_MAX(sessions, &sessions);
i--; } while (s2 != s);
s2 = ARRAY_ITEM(&sessions, i); if (s2 == s)
} while (s2 == NULL); return (NULL);
return (s2); return (s2);
} }

10
tmux.h
View File

@ -930,6 +930,8 @@ struct session_group {
TAILQ_HEAD(session_groups, session_group); TAILQ_HEAD(session_groups, session_group);
struct session { struct session {
u_int idx;
char *name; char *name;
char *cwd; char *cwd;
@ -957,8 +959,10 @@ struct session {
int references; int references;
TAILQ_ENTRY(session) gentry; TAILQ_ENTRY(session) gentry;
RB_ENTRY(session) entry;
}; };
ARRAY_DECL(sessions, struct session *); RB_HEAD(sessions, session);
ARRAY_DECL(sessionslist, struct session *);
/* TTY information. */ /* TTY information. */
struct tty_key { struct tty_key {
@ -1967,13 +1971,15 @@ void clear_signals(int);
extern struct sessions sessions; extern struct sessions sessions;
extern struct sessions dead_sessions; extern struct sessions dead_sessions;
extern struct session_groups session_groups; extern struct session_groups session_groups;
int session_cmp(struct session *, struct session *);
RB_PROTOTYPE(sessions, session, entry, session_cmp);
int session_alive(struct session *); int session_alive(struct session *);
struct session *session_find(const char *); struct session *session_find(const char *);
struct session *session_find_by_index(u_int);
struct session *session_create(const char *, const char *, const char *, struct session *session_create(const char *, const char *, const char *,
struct environ *, struct termios *, int, u_int, u_int, struct environ *, struct termios *, int, u_int, u_int,
char **); char **);
void session_destroy(struct session *); void session_destroy(struct session *);
int session_index(struct session *, u_int *);
struct session *session_next_session(struct session *); struct session *session_next_session(struct session *);
struct session *session_previous_session(struct session *); struct session *session_previous_session(struct session *);
struct winlink *session_new(struct session *, struct winlink *session_new(struct session *,