Greetings list, The attached patch adds options to new-window, new-session, and split-window (commands which create panes) to signal a wait_channel when that pane is destroyed, for example after the contained process exits. Towards this end, it changes the life-cycle management code in cmd-wait-for.c to allow external holds on a wait_channel structure; these are only taken, at the moment, by the aforementioned commands.
It's something of an afternoon hack-job, so it might not be ideal. Comments and criticisms welcome; rotten tomatoes possibly understood but less welcome. ;) Cheers! --nwf;
diff --git a/cmd-new-session.c b/cmd-new-session.c
index b36de70..4cf72fc 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_new_session_entry = {
"Ac:dDF:n:Ps:t:x:y:", 0, -1,
"[-AdDP] [-c start-directory] [-F format] [-n window-name] "
"[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
- "[-y height] [command]",
+ "[-y height] [-W channel] [command]",
CMD_STARTSERVER|CMD_CANTNEST,
NULL,
cmd_new_session_exec
@@ -61,6 +61,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
u_int sx, sy;
struct format_tree *ft;
struct environ_entry *envent;
+ struct wait_channel *wc = NULL;
if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
cmdq_error(cmdq, "command or window name given with target");
@@ -214,10 +215,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
if (c != NULL)
environ_update(update, &c->environ, &env);
+ if (args_has(args, 'W'))
+ wc = wait_channel_hold_by_name(args_get(args,'W'));
+
/* Create the new session. */
idx = -1 - options_get_number(&global_s_options, "base-index");
s = session_create(newname, argc, argv, path, cwd, &env, tiop, idx, sx,
- sy, &cause);
+ sy, wc, &cause);
if (s == NULL) {
cmdq_error(cmdq, "create session failed: %s", cause);
free(cause);
diff --git a/cmd-new-window.c b/cmd-new-window.c
index cd0042e..d5987e8 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -34,8 +34,8 @@ enum cmd_retval cmd_new_window_exec(struct cmd *,
struct cmd_q *);
const struct cmd_entry cmd_new_window_entry = {
"new-window", "neww",
- "ac:dF:kn:Pt:", 0, -1,
- "[-adkP] [-c start-directory] [-F format] [-n window-name] "
+ "ac:dF:kn:Pt:W:", 0, -1,
+ "[-adkP] [-c start-directory] [-F format] [-n window-name] [-W channel]"
CMD_TARGET_WINDOW_USAGE " [command]",
0,
NULL,
@@ -54,6 +54,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
int argc, idx, last, detached, cwd, fd = -1;
struct format_tree *ft;
struct environ_entry *envent;
+ struct wait_channel *wc = NULL;
if (args_has(args, 'a')) {
wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
@@ -152,10 +153,13 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
}
}
+ if (args_has(args, 'W'))
+ wc = wait_channel_hold_by_name(args_get(args, 'W'));
+
if (idx == -1)
idx = -1 - options_get_number(&s->options, "base-index");
wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx,
- &cause);
+ wc, &cause);
if (wl == NULL) {
cmdq_error(cmdq, "create window failed: %s", cause);
free(cause);
diff --git a/cmd-split-window.c b/cmd-split-window.c
index ea047a3..9a4fc15 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -37,6 +37,7 @@ const struct cmd_entry cmd_split_window_entry = {
"split-window", "splitw",
"c:dF:l:hp:Pt:v", 0, -1,
"[-dhvP] [-c start-directory] [-F format] [-p percentage|-l size] "
+ "[-W channel] "
CMD_TARGET_PANE_USAGE " [command]",
0,
cmd_split_window_key_binding,
@@ -158,6 +159,10 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
}
new_wp = window_add_pane(w, hlimit);
+ if (args_has(args, 'W'))
+ new_wp->signal_on_destroy =
+ wait_channel_hold_by_name(args_get(args, 'W'));
+
path = NULL;
if (cmdq->client != NULL && cmdq->client->session == NULL)
envent = environ_find(&cmdq->client->environ, "PATH");
diff --git a/cmd-wait-for.c b/cmd-wait-for.c
index e251863..f0dd92b 100644
--- a/cmd-wait-for.c
+++ b/cmd-wait-for.c
@@ -43,6 +43,7 @@ struct wait_channel {
const char *name;
int locked;
+ u_int holds;
TAILQ_HEAD(, cmd_q) waiters;
TAILQ_HEAD(, cmd_q) lockers;
@@ -70,6 +71,70 @@ enum cmd_retval cmd_wait_for_lock(struct cmd_q *, const
char *,
enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *,
struct wait_channel *);
+static struct wait_channel *
+wait_channel_find_by_name(const char *name) {
+ struct wait_channel wc0;
+
+ wc0.name = name;
+ return RB_FIND(wait_channels, &wait_channels, &wc0);
+}
+
+static struct wait_channel *
+wait_channel_alloc(const char *name) {
+ struct wait_channel *wc = xmalloc(sizeof *wc);
+ wc->name = xstrdup(name);
+ wc->locked = 0;
+ TAILQ_INIT(&wc->waiters);
+ TAILQ_INIT(&wc->lockers);
+ RB_INSERT(wait_channels, &wait_channels, wc);
+
+ return wc;
+}
+
+static void
+wait_channel_try_free(struct wait_channel *wc) {
+ if (wc->holds > 0)
+ return;
+
+ if (!TAILQ_EMPTY(&wc->waiters))
+ return;
+
+ if (!TAILQ_EMPTY(&wc->lockers)) {
+ /* Should we assert that wc->locked == 1 ? */
+ return;
+ }
+
+ /* All references to this wait_channel are gone */
+ RB_REMOVE(wait_channels, &wait_channels, wc);
+ free((void*) wc->name);
+ free(wc);
+}
+
+static void
+wait_channel_hold(struct wait_channel *wc) {
+ wc->holds++;
+}
+
+struct wait_channel *
+wait_channel_hold_by_name(const char *name) {
+ struct wait_channel *wc = wait_channel_find_by_name(name);
+
+ if(!wc)
+ wc = wait_channel_alloc(name);
+
+ wait_channel_hold(wc);
+
+ return wc;
+}
+
+void
+wait_channel_unhold(struct wait_channel *wc) {
+ if(--wc->holds != 0)
+ return;
+
+ wait_channel_try_free(wc);
+}
+
enum cmd_retval
cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
{
@@ -89,28 +154,29 @@ cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
return (cmd_wait_for_wait(cmdq, name, wc));
}
+void
+wait_channel_signal(struct wait_channel *wc) {
+ struct cmd_q *wq, *wq1;
+
+ TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
+ TAILQ_REMOVE(&wc->waiters, wq, waitentry);
+ if (!cmdq_free(wq))
+ cmdq_continue(wq);
+ }
+}
+
enum cmd_retval
cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc)
{
- struct cmd_q *wq, *wq1;
-
if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) {
cmdq_error(cmdq, "no waiting clients on %s", name);
return (CMD_RETURN_ERROR);
}
- TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
- TAILQ_REMOVE(&wc->waiters, wq, waitentry);
- if (!cmdq_free(wq))
- cmdq_continue(wq);
- }
+ wait_channel_signal(wc);
- if (!wc->locked) {
- RB_REMOVE(wait_channels, &wait_channels, wc);
- free((void*) wc->name);
- free(wc);
- }
+ wait_channel_try_free(wc);
return (CMD_RETURN_NORMAL);
}
@@ -124,14 +190,8 @@ cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
return (CMD_RETURN_ERROR);
}
- if (wc == NULL) {
- wc = xmalloc(sizeof *wc);
- wc->name = xstrdup(name);
- wc->locked = 0;
- TAILQ_INIT(&wc->waiters);
- TAILQ_INIT(&wc->lockers);
- RB_INSERT(wait_channels, &wait_channels, wc);
- }
+ if (wc == NULL)
+ wc = wait_channel_alloc(name);
TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
cmdq->references++;
@@ -184,11 +244,7 @@ cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
cmdq_continue(wq);
} else {
wc->locked = 0;
- if (TAILQ_EMPTY(&wc->waiters)) {
- RB_REMOVE(wait_channels, &wait_channels, wc);
- free((void*) wc->name);
- free(wc);
- }
+ wait_channel_try_free(wc);
}
return (CMD_RETURN_NORMAL);
diff --git a/session.c b/session.c
index 2bcb1b9..bd50021 100644
--- a/session.c
+++ b/session.c
@@ -86,7 +86,7 @@ session_find_by_id(u_int id)
struct session *
session_create(const char *name, int argc, char **argv, const char *path,
int cwd, struct environ *env, struct termios *tio, int idx, u_int sx,
- u_int sy, char **cause)
+ u_int sy, struct wait_channel *wc, char **cause)
{
struct session *s;
struct winlink *wl;
@@ -133,7 +133,7 @@ session_create(const char *name, int argc, char **argv,
const char *path,
RB_INSERT(sessions, &sessions, s);
if (argc >= 0) {
- wl = session_new(s, NULL, argc, argv, path, cwd, idx, cause);
+ wl = session_new(s, NULL, argc, argv, path, cwd, idx, wc,
cause);
if (wl == NULL) {
session_destroy(s);
return (NULL);
@@ -229,7 +229,7 @@ session_previous_session(struct session *s)
/* Create a new window on a session. */
struct winlink *
session_new(struct session *s, const char *name, int argc, char **argv,
- const char *path, int cwd, int idx, char **cause)
+ const char *path, int cwd, int idx, struct wait_channel *wc, char **cause)
{
struct window *w;
struct winlink *wl;
@@ -253,7 +253,7 @@ session_new(struct session *s, const char *name, int argc,
char **argv,
hlimit = options_get_number(&s->options, "history-limit");
w = window_create(name, argc, argv, path, shell, cwd, &env, s->tio,
- s->sx, s->sy, hlimit, cause);
+ s->sx, s->sy, hlimit, wc, cause);
if (w == NULL) {
winlink_remove(&s->windows, wl);
environ_free(&env);
diff --git a/tmux.1 b/tmux.1
index 924157d..1b51cb9 100644
--- a/tmux.1
+++ b/tmux.1
@@ -709,6 +709,7 @@ Lock all clients attached to
.Op Fl t Ar target-session
.Op Fl x Ar width
.Op Fl y Ar height
+.Op Fl W Ar channel
.Op Ar shell-command
.Xc
.D1 (alias: Ic new )
@@ -776,6 +777,15 @@ By default, it uses the format
.Ql #{session_name}:
but a different format may be specified with
.Fl F .
+.Pp
+The
+.Fl W
+option specifies a channel name which will be signaled when the created pane
+is destroyed. Clients may use the
+.Ic wait-for
+command to suspend until this happens.
+.Ic new-session
+does not lock the channel.
.It Xo Ic refresh-client
.Op Fl S
.Op Fl t Ar target-client
@@ -1498,6 +1508,7 @@ option.
.Op Fl F Ar format
.Op Fl n Ar window-name
.Op Fl t Ar target-window
+.Op Fl W Ar channel
.Op Ar shell-command
.Xc
.D1 (alias: Ic neww )
@@ -1553,6 +1564,15 @@ By default, it uses the format
.Ql #{session_name}:#{window_index}
but a different format may be specified with
.Fl F .
+.Pp
+The
+.Fl W
+option specifies a channel name which will be signaled when the created pane
+is destroyed. Clients may use the
+.Ic wait-for
+command to suspend until this happens.
+.Ic new-window
+does not lock the channel.
.It Ic next-layout Op Fl t Ar target-window
.D1 (alias: Ic nextl )
Move a window to the next layout and rearrange the panes to fit.
@@ -1754,6 +1774,7 @@ the command behaves like
.Ar size |
.Fl p Ar percentage Oc
.Op Fl t Ar target-pane
+.Op Fl W Ar channel
.Op Ar shell-command
.Op Fl F Ar format
.Xc
diff --git a/tmux.h b/tmux.h
index c4c5236..2c51baa 100644
--- a/tmux.h
+++ b/tmux.h
@@ -954,6 +954,8 @@ struct window_pane {
TAILQ_ENTRY(window_pane) entry;
RB_ENTRY(window_pane) tree_entry;
+
+ struct wait_channel *signal_on_destroy;
};
TAILQ_HEAD(window_panes, window_pane);
RB_HEAD(window_pane_tree, window_pane);
@@ -1884,6 +1886,11 @@ void cmdq_flush(struct cmd_q *);
int cmd_string_parse(const char *, struct cmd_list **, const char *,
u_int, char **);
+/* cmd-wait-for.c */
+struct wait_channel *wait_channel_hold_by_name(const char *);
+void wait_channel_signal(struct wait_channel *);
+void wait_channel_unhold(struct wait_channel *);
+
/* client.c */
int client_main(int, char **, int);
@@ -2148,7 +2155,7 @@ struct window *window_find_by_id(u_int);
struct window *window_create1(u_int, u_int);
struct window *window_create(const char *, int, char **, const char *,
const char *, int, struct environ *, struct termios *,
- u_int, u_int, u_int, char **);
+ u_int, u_int, u_int, struct wait_channel *, char **);
void window_destroy(struct window *);
struct window_pane *window_get_active_at(struct window *, u_int, u_int);
void window_set_active_at(struct window *, u_int, u_int);
@@ -2312,14 +2319,14 @@ struct session *session_find(const char *);
struct session *session_find_by_id(u_int);
struct session *session_create(const char *, int, char **, const char *,
int, struct environ *, struct termios *, int, u_int,
- u_int, char **);
+ u_int, struct wait_channel *, char **);
void session_destroy(struct session *);
int session_check_name(const char *);
void session_update_activity(struct session *);
struct session *session_next_session(struct session *);
struct session *session_previous_session(struct session *);
struct winlink *session_new(struct session *, const char *, int, char **,
- const char *, int, int, char **);
+ const char *, int, int, struct wait_channel *, char **);
struct winlink *session_attach(struct session *, struct window *, int,
char **);
int session_detach(struct session *, struct winlink *);
diff --git a/window.c b/window.c
index 5b93f93..eecacd9 100644
--- a/window.c
+++ b/window.c
@@ -308,13 +308,14 @@ window_create1(u_int sx, u_int sy)
struct window *
window_create(const char *name, int argc, char **argv, const char *path,
const char *shell, int cwd, struct environ *env, struct termios *tio,
- u_int sx, u_int sy, u_int hlimit, char **cause)
+ u_int sx, u_int sy, u_int hlimit, struct wait_channel *wc, char **cause)
{
struct window *w;
struct window_pane *wp;
w = window_create1(sx, sy);
wp = window_add_pane(w, hlimit);
+ wp->signal_on_destroy = wc;
layout_init(w, wp);
if (window_pane_spawn(wp, argc, argv, path, shell, cwd, env, tio,
@@ -712,6 +713,12 @@ window_pane_create(struct window *w, u_int sx, u_int sy,
u_int hlimit)
void
window_pane_destroy(struct window_pane *wp)
{
+ if(wp->signal_on_destroy) {
+ wait_channel_signal(wp->signal_on_destroy);
+ wait_channel_unhold(wp->signal_on_destroy);
+ wp->signal_on_destroy = NULL;
+ }
+
window_pane_reset_mode(wp);
if (event_initialized(&wp->changes_timer))
pgphmPZRGTO4f.pgp
Description: PGP signature
------------------------------------------------------------------------------ Infragistics Professional Build stunning WinForms apps today! Reboot your WinForms applications with our WinForms controls. Build a bridge from your legacy apps to the future. http://pubads.g.doubleclick.net/gampad/clk?id=153845071&iu=/4140/ostg.clktrk
_______________________________________________ tmux-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/tmux-users
