Hi Can't you just run "mycommand; tmux wait -S foo" in the pane?
On Thu, Aug 07, 2014 at 04:15:15PM -0400, Nathaniel W Filardo wrote: > On Thu, Aug 07, 2014 at 09:05:01PM +0100, Nicholas Marriott wrote: > > Hi > > > > What is this useful for? > > My use case is that I want to run half a dozen or so jobs via runit and I > wanted them to share a tmux session for easy administrative access rather > than each spawning their own. But I need some way to wait for the > individual task running on a given pane to exit. > > > This seems like a job for hooks if they are ever finished. > > What are "hooks" in this context? > > Thanks, > --nwf; > > > On Mon, Aug 04, 2014 at 01:59:26PM -0400, Nathaniel W Filardo wrote: > > > 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)) > > > > > > > > > > > ------------------------------------------------------------------------------ > > > 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 > > > tmux-users@lists.sourceforge.net > > > https://lists.sourceforge.net/lists/listinfo/tmux-users ------------------------------------------------------------------------------ _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users