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

Reply via email to