On Mon, Aug 04, 2014 at 10:59:21PM +0100, Thomas Adam wrote:
>[useful feedback]

Here's take 2; it should (unless I goofed) incorporate all your feedback.
Thanks!
--nwf;
diff --git a/cmd-new-session.c b/cmd-new-session.c
index b36de70..d23fea1 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -35,10 +35,10 @@ enum cmd_retval      cmd_new_session_exec(struct cmd *, 
struct cmd_q *);
 
 const struct cmd_entry cmd_new_session_entry = {
        "new-session", "new",
-       "Ac:dDF:n:Ps:t:x:y:", 0, -1,
+       "Ac:dDF:n:Ps:t:W: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..ec7ddc7 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -35,8 +35,9 @@ enum cmd_retval        cmd_split_window_exec(struct cmd *, 
struct cmd_q *);
 
 const struct cmd_entry cmd_split_window_entry = {
        "split-window", "splitw",
-       "c:dF:l:hp:Pt:v", 0, -1,
+       "c:dF:l:hp:Pt:vW:", 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..01c6208 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,69 @@ 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 = (char *) name;
+       return RB_FIND(wait_channels, &wait_channels, &wc0);
+}
+
+static struct wait_channel *
+wait_channel_new(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)) {
+               return;
+       }
+
+       /* All references to this wait_channel are gone */
+       RB_REMOVE(wait_channels, &wait_channels, wc);
+       free(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 != NULL)
+               wc = wait_channel_new(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 +153,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 +189,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 +243,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..e04f697 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,16 @@ 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 +1509,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 +1565,16 @@ 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 +1776,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))

Attachment: pgpBlKoTs2xYu.pgp
Description: PGP signature

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to