No I don't think it is needed.

On Wed, Mar 06, 2013 at 07:31:29AM -0300, Thiago Padilha wrote:
> Do you want me to add the example script?
> 
> On Wed, Mar 6, 2013 at 7:09 AM, Thiago Padilha <tpadilh...@gmail.com> wrote:
> > Yes will do in a minute
> >
> > On Wed, Mar 6, 2013 at 6:58 AM, Nicholas Marriott
> > <nicholas.marri...@gmail.com> wrote:
> >> Committed, thanks. Do you want to tweak the lock bits to fit too?
> >>
> >>
> >> On Wed, Mar 06, 2013 at 06:53:12AM -0300, Thiago Padilha wrote:
> >>> This looks good to me
> >>>
> >>> On Wed, Mar 6, 2013 at 6:37 AM, Nicholas Marriott
> >>> <nicholas.marri...@gmail.com> wrote:
> >>> > Ok this looks pretty good. I've made a few changes but mainly 
> >>> > style/layout nits:
> >>> >
> >>> > - I don't think we need find and find_and_create functions, the find
> >>> >   will only be done once and the create twice (when there is lock too).
> >>> >
> >>> > - A single cmdq can only be waiting once so no need to have a wrapper
> >>> >   struct, just put the TAILQ_ENTRY in struct cmd_q itself.
> >>> >
> >>> > - channel_node -> wait_channel and similar renaming.
> >>> >
> >>> > - We always include sys/types.h, needed or not. Also errors always start
> >>> >   with lowercase.
> >>> >
> >>> > - Move things about to sort of vaguely fit where they go in other
> >>> >   commands.
> >>> >
> >>> > - Add to man page.
> >>> >
> >>> > I considered putting structs in tmux.h but I can't see how they would be
> >>> > needed outside this file so let's leave them local anyway. tmux.h is too
> >>> > big already.
> >>> >
> >>> > Please take a look and make sure there isn't anything stupid and then I
> >>> > will commit and we can modify to add locking.
> >>> >
> >>> >
> >>> > diff --git a/Makefile.am b/Makefile.am
> >>> > index 5caa498..19220d8 100644
> >>> > --- a/Makefile.am
> >>> > +++ b/Makefile.am
> >>> > @@ -135,6 +135,7 @@ dist_tmux_SOURCES = \
> >>> >         cmd-switch-client.c \
> >>> >         cmd-unbind-key.c \
> >>> >         cmd-unlink-window.c \
> >>> > +       cmd-wait-for.c \
> >>> >         cmd.c \
> >>> >         colour.c \
> >>> >         control.c \
> >>> > diff --git a/cmd-wait-for.c b/cmd-wait-for.c
> >>> > new file mode 100644
> >>> > index 0000000..6313358
> >>> > --- /dev/null
> >>> > +++ b/cmd-wait-for.c
> >>> > @@ -0,0 +1,124 @@
> >>> > +/* $Id$ */
> >>> > +
> >>> > +/*
> >>> > + * Copyright (c) 2013 Nicholas Marriott <n...@users.sourceforge.net>
> >>> > + * Copyright (c) 2013 Thiago de Arruda <tpadilh...@gmail.com>
> >>> > + *
> >>> > + * Permission to use, copy, modify, and distribute this software for 
> >>> > any
> >>> > + * purpose with or without fee is hereby granted, provided that the 
> >>> > above
> >>> > + * copyright notice and this permission notice appear in all copies.
> >>> > + *
> >>> > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 
> >>> > WARRANTIES
> >>> > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> >>> > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE 
> >>> > FOR
> >>> > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY 
> >>> > DAMAGES
> >>> > + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, 
> >>> > WHETHER
> >>> > + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 
> >>> > ARISING
> >>> > + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
> >>> > SOFTWARE.
> >>> > + */
> >>> > +
> >>> > +#include <sys/types.h>
> >>> > +
> >>> > +#include <stdlib.h>
> >>> > +#include <string.h>
> >>> > +
> >>> > +#include "tmux.h"
> >>> > +
> >>> > +/*
> >>> > + * Block or wake a client on a named wait channel.
> >>> > + */
> >>> > +
> >>> > +enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *);
> >>> > +
> >>> > +const struct cmd_entry cmd_wait_for_entry = {
> >>> > +       "wait-for", "wait",
> >>> > +       "S", 1, 1,
> >>> > +       "[-S] channel",
> >>> > +       0,
> >>> > +       NULL,
> >>> > +       NULL,
> >>> > +       cmd_wait_for_exec
> >>> > +};
> >>> > +
> >>> > +struct wait_channel {
> >>> > +       const char             *name;
> >>> > +       TAILQ_HEAD(, cmd_q)     waiters;
> >>> > +
> >>> > +       RB_ENTRY(wait_channel)  entry;
> >>> > +};
> >>> > +RB_HEAD(wait_channels, wait_channel);
> >>> > +struct wait_channels wait_channels = RB_INITIALIZER(wait_channels);
> >>> > +
> >>> > +int    wait_channel_cmp(struct wait_channel *, struct wait_channel *);
> >>> > +RB_PROTOTYPE(wait_channels, wait_channel, entry, wait_channel_cmp);
> >>> > +RB_GENERATE(wait_channels, wait_channel, entry, wait_channel_cmp);
> >>> > +
> >>> > +int
> >>> > +wait_channel_cmp(struct wait_channel *wc1, struct wait_channel *wc2)
> >>> > +{
> >>> > +       return (strcmp(wc1->name, wc2->name));
> >>> > +}
> >>> > +
> >>> > +enum cmd_retval        cmd_wait_for_signal(struct cmd_q *, const char 
> >>> > *,
> >>> > +                   struct wait_channel *);
> >>> > +enum cmd_retval        cmd_wait_for_wait(struct cmd_q *, const char *,
> >>> > +                   struct wait_channel *);
> >>> > +
> >>> > +enum cmd_retval
> >>> > +cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
> >>> > +{
> >>> > +       struct args             *args = self->args;
> >>> > +       const char              *name = args->argv[0];
> >>> > +       struct wait_channel     *wc, wc0;
> >>> > +
> >>> > +       wc0.name = name;
> >>> > +       wc = RB_FIND(wait_channels, &wait_channels, &wc0);
> >>> > +
> >>> > +       if (args_has(args, 'S'))
> >>> > +               return (cmd_wait_for_signal(cmdq, name, wc));
> >>> > +       return (cmd_wait_for_wait(cmdq, name, wc));
> >>> > +}
> >>> > +
> >>> > +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);
> >>> > +       }
> >>> > +       RB_REMOVE(wait_channels, &wait_channels, wc);
> >>> > +       free((void*) wc->name);
> >>> > +       free(wc);
> >>> > +
> >>> > +       return (CMD_RETURN_NORMAL);
> >>> > +}
> >>> > +
> >>> > +enum cmd_retval
> >>> > +cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
> >>> > +    struct wait_channel *wc)
> >>> > +{
> >>> > +       if (cmdq->client == NULL || cmdq->client->session != NULL) {
> >>> > +               cmdq_error(cmdq, "not able to wait");
> >>> > +               return (CMD_RETURN_ERROR);
> >>> > +       }
> >>> > +
> >>> > +       if (wc == NULL) {
> >>> > +               wc = xmalloc(sizeof *wc);
> >>> > +               wc->name = xstrdup(name);
> >>> > +               TAILQ_INIT(&wc->waiters);
> >>> > +               RB_INSERT(wait_channels, &wait_channels, wc);
> >>> > +       }
> >>> > +       TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
> >>> > +       cmdq->references++;
> >>> > +
> >>> > +       return (CMD_RETURN_WAIT);
> >>> > +}
> >>> > diff --git a/cmd.c b/cmd.c
> >>> > index 0d6a85f..20484ed 100644
> >>> > --- a/cmd.c
> >>> > +++ b/cmd.c
> >>> > @@ -112,6 +112,7 @@ const struct cmd_entry *cmd_table[] = {
> >>> >         &cmd_switch_client_entry,
> >>> >         &cmd_unbind_key_entry,
> >>> >         &cmd_unlink_window_entry,
> >>> > +       &cmd_wait_for_entry,
> >>> >         NULL
> >>> >  };
> >>> >
> >>> > diff --git a/tmux.1 b/tmux.1
> >>> > index 1a9c058..8df7975 100644
> >>> > --- a/tmux.1
> >>> > +++ b/tmux.1
> >>> > @@ -3553,6 +3553,19 @@ If the command doesn't return success, the exit 
> >>> > status is also displayed.
> >>> >  .It Ic server-info
> >>> >  .D1 (alias: Ic info )
> >>> >  Show server information and terminal details.
> >>> > +.It Xo Ic wait-for
> >>> > +.Fl S
> >>> > +.Ar channel
> >>> > +.Xc
> >>> > +.D1 (alias: Ic wait )
> >>> > +When used without
> >>> > +.Fl S ,
> >>> > +prevents the client from exiting until woken using
> >>> > +.Ic wait-for
> >>> > +.Fl S
> >>> > +with the same channel.
> >>> > +This command only works from outside
> >>> > +.Nm .
> >>> >  .El
> >>> >  .Sh TERMINFO EXTENSIONS
> >>> >  .Nm
> >>> > diff --git a/tmux.h b/tmux.h
> >>> > index c1ad662..e58c1de 100644
> >>> > --- a/tmux.h
> >>> > +++ b/tmux.h
> >>> > @@ -1416,6 +1416,8 @@ struct cmd_q {
> >>> >         void                    *data;
> >>> >
> >>> >         struct msg_command_data *msgdata;
> >>> > +
> >>> > +       TAILQ_ENTRY(cmd_q)       waitentry;
> >>> >  };
> >>> >
> >>> >  /* Command definition. */
> >>> > @@ -1835,6 +1837,7 @@ extern const struct cmd_entry 
> >>> > cmd_switch_client_entry;
> >>> >  extern const struct cmd_entry cmd_unbind_key_entry;
> >>> >  extern const struct cmd_entry cmd_unlink_window_entry;
> >>> >  extern const struct cmd_entry cmd_up_pane_entry;
> >>> > +extern const struct cmd_entry cmd_wait_for_entry;
> >>> >
> >>> >  /* cmd-attach-session.c */
> >>> >  enum cmd_retval         cmd_attach_session(struct cmd_q *, const 
> >>> > char*, int, int);
> >>> >
> >>> >
> >>> >
> >>> >
> >>> > On Tue, Mar 05, 2013 at 10:55:05PM -0300, Thiago Padilha wrote:
> >>> >> Here it goes:
> >>> >>
> >>> >> The first patch implements wait/signal, the second extends it with
> >>> >> lock/unlock. My goal this time was to make the code small and simple
> >>> >> as possible, let me know if you think anything needs to be refactored.
> >>> >> ---
> >>> >>  Makefile.am               |   1 +
> >>> >>  cmd-wait-for.c            | 145 
> >>> >> ++++++++++++++++++++++++++++++++++++++++++++++
> >>> >>  cmd.c                     |   1 +
> >>> >>  examples/tmux-wait-for.sh | 109 ++++++++++++++++++++++++++++++++++
> >>> >>  tmux.h                    |   1 +
> >>> >>  5 files changed, 257 insertions(+)
> >>> >>  create mode 100644 cmd-wait-for.c
> >>> >>  create mode 100755 examples/tmux-wait-for.sh
> >>> >
> >>> >> diff --git a/Makefile.am b/Makefile.am
> >>> >> index 5caa498..19220d8 100644
> >>> >> --- a/Makefile.am
> >>> >> +++ b/Makefile.am
> >>> >> @@ -135,6 +135,7 @@ dist_tmux_SOURCES = \
> >>> >>         cmd-switch-client.c \
> >>> >>         cmd-unbind-key.c \
> >>> >>         cmd-unlink-window.c \
> >>> >> +       cmd-wait-for.c \
> >>> >>         cmd.c \
> >>> >>         colour.c \
> >>> >>         control.c \
> >>> >> diff --git a/cmd-wait-for.c b/cmd-wait-for.c
> >>> >> new file mode 100644
> >>> >> index 0000000..658109b
> >>> >> --- /dev/null
> >>> >> +++ b/cmd-wait-for.c
> >>> >> @@ -0,0 +1,145 @@
> >>> >> +/* $Id$ */
> >>> >> +
> >>> >> +/*
> >>> >> + * Copyright (c) 2013 Thiago de Arruda<tpadilh...@gmail.com>
> >>> >> + *
> >>> >> + *
> >>> >> + * Permission to use, copy, modify, and distribute this software for 
> >>> >> any
> >>> >> + * purpose with or without fee is hereby granted, provided that the 
> >>> >> above
> >>> >> + * copyright notice and this permission notice appear in all copies.
> >>> >> + *
> >>> >> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 
> >>> >> WARRANTIES
> >>> >> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> >>> >> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE 
> >>> >> LIABLE FOR
> >>> >> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY 
> >>> >> DAMAGES
> >>> >> + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, 
> >>> >> WHETHER
> >>> >> + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 
> >>> >> ARISING
> >>> >> + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
> >>> >> SOFTWARE.
> >>> >> + */
> >>> >> +
> >>> >> +#include <stdlib.h>
> >>> >> +#include <string.h>
> >>> >> +
> >>> >> +#include "tmux.h"
> >>> >> +
> >>> >> +struct cmdq_node {
> >>> >> +       struct cmd_q *cmdq;
> >>> >> +       TAILQ_ENTRY(cmdq_node) node;
> >>> >> +};
> >>> >> +
> >>> >> +struct channel_node {
> >>> >> +       char *name;
> >>> >> +       TAILQ_HEAD(, cmdq_node) waiting_cmdqs;
> >>> >> +       RB_ENTRY(channel_node) node;
> >>> >> +};
> >>> >> +RB_HEAD(channels, channel_node) channels_head = 
> >>> >> RB_INITIALIZER(&channels_head);
> >>> >> +
> >>> >> +enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *);
> >>> >> +enum cmd_retval channel_wait(const char *, struct cmd_q *);
> >>> >> +enum cmd_retval channel_signal(const char *, struct cmd_q *);
> >>> >> +struct channel_node *channels_find(const char *);
> >>> >> +struct channel_node *channels_find_or_create(const char *);
> >>> >> +int channel_cmp(struct channel_node *, struct channel_node *);
> >>> >> +RB_PROTOTYPE(channels, channel_node, node, channel_cmp);
> >>> >> +
> >>> >> +const struct cmd_entry cmd_wait_for_entry = {
> >>> >> +       "wait-for", "wait",
> >>> >> +       "S", 1, 1,
> >>> >> +       "[-S] channel",
> >>> >> +       0,
> >>> >> +       NULL,
> >>> >> +       NULL,
> >>> >> +       cmd_wait_for_exec
> >>> >> +};
> >>> >> +
> >>> >> +enum cmd_retval
> >>> >> +cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
> >>> >> +{
> >>> >> +       struct args     *args = self->args;
> >>> >> +       const char *name = args->argv[0];
> >>> >> +
> >>> >> +       if (args_has(args, 'S'))
> >>> >> +               return channel_signal(name, cmdq);
> >>> >> +
> >>> >> +       return channel_wait(name, cmdq);
> >>> >> +}
> >>> >> +
> >>> >> +RB_GENERATE(channels, channel_node, node, channel_cmp);
> >>> >> +
> >>> >> +int
> >>> >> +channel_cmp(struct channel_node *c1, struct channel_node *c2)
> >>> >> +{
> >>> >> +       return (strcmp(c1->name, c2->name));
> >>> >> +}
> >>> >> +
> >>> >> +struct channel_node *
> >>> >> +channels_find(const char *name)
> >>> >> +{
> >>> >> +       struct channel_node c_name;
> >>> >> +       c_name.name = (char *)name;
> >>> >> +       return RB_FIND(channels, &channels_head, &c_name);
> >>> >> +}
> >>> >> +
> >>> >> +struct channel_node *
> >>> >> +channels_find_or_create(const char *name)
> >>> >> +{
> >>> >> +       struct channel_node *c;
> >>> >> +
> >>> >> +       c = channels_find(name);
> >>> >> +
> >>> >> +       if (c == NULL) {
> >>> >> +               c = xmalloc(sizeof *c);
> >>> >> +               c->name = xstrdup(name);
> >>> >> +               TAILQ_INIT(&c->waiting_cmdqs);
> >>> >> +               RB_INSERT(channels, &channels_head, c);
> >>> >> +       }
> >>> >> +
> >>> >> +       return c;
> >>> >> +}
> >>> >> +
> >>> >> +enum cmd_retval
> >>> >> +channel_wait(const char *name, struct cmd_q *cmdq)
> >>> >> +{
> >>> >> +       struct cmdq_node *wq;
> >>> >> +       struct channel_node *c;
> >>> >> +
> >>> >> +       if (cmdq->client == NULL || cmdq->client->session != NULL) {
> >>> >> +               cmdq_error(cmdq, "Not able to wait");
> >>> >> +               return (CMD_RETURN_ERROR);
> >>> >> +       }
> >>> >> +
> >>> >> +       c = channels_find_or_create(name);
> >>> >> +       wq = xmalloc(sizeof *wq);
> >>> >> +       wq->cmdq = cmdq;
> >>> >> +       TAILQ_INSERT_HEAD(&c->waiting_cmdqs, wq, node);
> >>> >> +       cmdq->references++;
> >>> >> +
> >>> >> +       return (CMD_RETURN_WAIT);
> >>> >> +}
> >>> >> +
> >>> >> +enum cmd_retval
> >>> >> +channel_signal(const char *name, struct cmd_q *cmdq)
> >>> >> +{
> >>> >> +       struct cmdq_node *wq;
> >>> >> +       struct channel_node *c;
> >>> >> +
> >>> >> +       c = channels_find(name);
> >>> >> +
> >>> >> +       if (c == NULL || TAILQ_EMPTY(&c->waiting_cmdqs)) {
> >>> >> +               cmdq_error(cmdq, "No waiting clients");
> >>> >> +               return (CMD_RETURN_ERROR);
> >>> >> +       }
> >>> >> +
> >>> >> +       while ((wq = TAILQ_FIRST(&c->waiting_cmdqs)) != NULL) {
> >>> >> +               TAILQ_REMOVE(&c->waiting_cmdqs, wq, node);
> >>> >> +               if (!cmdq_free(wq->cmdq))
> >>> >> +                       cmdq_continue(wq->cmdq);
> >>> >> +               free(wq);
> >>> >> +       }
> >>> >> +
> >>> >> +       RB_REMOVE(channels, &channels_head, c);
> >>> >> +       free(c->name);
> >>> >> +       free(c);
> >>> >> +
> >>> >> +       return (CMD_RETURN_NORMAL);
> >>> >> +}
> >>> >> diff --git a/cmd.c b/cmd.c
> >>> >> index 0d6a85f..20484ed 100644
> >>> >> --- a/cmd.c
> >>> >> +++ b/cmd.c
> >>> >> @@ -112,6 +112,7 @@ const struct cmd_entry *cmd_table[] = {
> >>> >>         &cmd_switch_client_entry,
> >>> >>         &cmd_unbind_key_entry,
> >>> >>         &cmd_unlink_window_entry,
> >>> >> +       &cmd_wait_for_entry,
> >>> >>         NULL
> >>> >>  };
> >>> >>
> >>> >> diff --git a/examples/tmux-wait-for.sh b/examples/tmux-wait-for.sh
> >>> >> new file mode 100755
> >>> >> index 0000000..94baa90
> >>> >> --- /dev/null
> >>> >> +++ b/examples/tmux-wait-for.sh
> >>> >> @@ -0,0 +1,109 @@
> >>> >> +#!/bin/bash
> >>> >> +
> >>> >> +# Shows how one can synchronize work using the 'wait' command
> >>> >> +
> >>> >> +if [ -z $TMUX ]; then
> >>> >> +       echo "Start tmux first" >&2
> >>> >> +       exit 1
> >>> >> +fi
> >>> >> +
> >>> >> +kill_child_panes() {
> >>> >> +       tmux kill-pane -t $pane1
> >>> >> +       tmux kill-pane -t $pane2
> >>> >> +       tmux kill-pane -t $pane3
> >>> >> +       exit
> >>> >> +}
> >>> >> +abspath=$(cd ${0%/*} && echo $PWD/${0##*/})
> >>> >> +
> >>> >> +case $1 in
> >>> >> +       pane1)
> >>> >> +               tmux setw -q @pane1id $TMUX_PANE
> >>> >> +               tmux wait -S pane1
> >>> >> +               tmux wait pane1
> >>> >> +               tmux split-window -d -h "$abspath pane3"
> >>> >> +               tmux split-window -d -h "$abspath pane2"
> >>> >> +               tmux wait pane1
> >>> >> +               columns=$(tput cols)
> >>> >> +               n=1
> >>> >> +               while true; do
> >>> >> +                       for i in $(seq 1 $columns); do
> >>> >> +                               sleep "0.1"
> >>> >> +                               echo -n $n
> >>> >> +                       done
> >>> >> +                       echo
> >>> >> +                       tmux wait -S pane2
> >>> >> +                       tmux wait pane1
> >>> >> +                       n=$(( ($n + 3) % 9 ))
> >>> >> +               done
> >>> >> +               ;;
> >>> >> +       pane2)
> >>> >> +               tmux setw -q @pane2id $TMUX_PANE
> >>> >> +               tmux wait -S pane2
> >>> >> +               tmux wait pane2
> >>> >> +               columns=$(tput cols)
> >>> >> +               n=2
> >>> >> +               while true; do
> >>> >> +                       for i in $(seq 1 $columns); do
> >>> >> +                               sleep "0.1"
> >>> >> +                               echo -n $n
> >>> >> +                       done
> >>> >> +                       echo
> >>> >> +                       tmux wait -S pane3
> >>> >> +                       tmux wait pane2
> >>> >> +                       n=$(( ($n + 3) % 9 ))
> >>> >> +               done
> >>> >> +               ;;
> >>> >> +       pane3)
> >>> >> +               tmux setw -q @pane3id $TMUX_PANE
> >>> >> +               tmux wait -S pane3
> >>> >> +               tmux wait pane3
> >>> >> +               columns=$(tput cols)
> >>> >> +               n=3
> >>> >> +               while true; do
> >>> >> +                       for i in $(seq 1 $columns); do
> >>> >> +                               sleep "0.1"
> >>> >> +                               echo -n $n
> >>> >> +                       done
> >>> >> +                       echo
> >>> >> +                       tmux wait -S pane1
> >>> >> +                       tmux wait pane3
> >>> >> +                       n=$(( ($n + 3) % 9 ))
> >>> >> +               done
> >>> >> +               ;;
> >>> >> +       *)
> >>> >> +               columns=$(tput cols)
> >>> >> +               trap kill_child_panes SIGINT SIGTERM
> >>> >> +               clear
> >>> >> +               echo "This is a simple script that shows how tmux can 
> >>> >> synchronize"
> >>> >> +         echo "code running in different panes."
> >>> >> +               echo
> >>> >> +               echo "Besides recursively spliting panes, it will run 
> >>> >> a simple animation"
> >>> >> +               echo "demonstrating the coordination between panes"
> >>> >> +               echo
> >>> >> +               sleep 1
> >>> >> +               echo "First split horizontally"
> >>> >> +               tmux split-window "$abspath pane1"
> >>> >> +               tmux wait pane1
> >>> >> +               pane1=`tmux showw -v @pane1id`
> >>> >> +               sleep 1
> >>> >> +               echo "Now we split the child pane 2 times"
> >>> >> +               tmux wait -S pane1
> >>> >> +               tmux wait pane3
> >>> >> +               tmux wait pane2
> >>> >> +               pane2=`tmux showw -v @pane2id`
> >>> >> +               pane3=`tmux showw -v @pane3id`
> >>> >> +               column_width=$(($columns / 3))
> >>> >> +               sleep 1
> >>> >> +               echo "Resize equally"
> >>> >> +               tmux resize-pane -t $pane1 -x $column_width
> >>> >> +               tmux resize-pane -t $pane2 -x $column_width
> >>> >> +               tmux resize-pane -t $pane3 -x $column_width
> >>> >> +               sleep 1
> >>> >> +               echo "Start animation"
> >>> >> +               tmux wait -S pane1
> >>> >> +               tmux select-pane -t $TMUX_PANE
> >>> >> +               while true; do
> >>> >> +                       sleep 1000
> >>> >> +               done
> >>> >> +               ;;
> >>> >> +esac
> >>> >> diff --git a/tmux.h b/tmux.h
> >>> >> index c1ad662..95dd97c 100644
> >>> >> --- a/tmux.h
> >>> >> +++ b/tmux.h
> >>> >> @@ -1835,6 +1835,7 @@ extern const struct cmd_entry 
> >>> >> cmd_switch_client_entry;
> >>> >>  extern const struct cmd_entry cmd_unbind_key_entry;
> >>> >>  extern const struct cmd_entry cmd_unlink_window_entry;
> >>> >>  extern const struct cmd_entry cmd_up_pane_entry;
> >>> >> +extern const struct cmd_entry cmd_wait_for_entry;
> >>> >>
> >>> >>  /* cmd-attach-session.c */
> >>> >>  enum cmd_retval         cmd_attach_session(struct cmd_q *, const 
> >>> >> char*, int, int);
> >>> >
> >>> >> diff --git a/cmd-wait-for.c b/cmd-wait-for.c
> >>> >> index 658109b..58e53c6 100644
> >>> >> --- a/cmd-wait-for.c
> >>> >> +++ b/cmd-wait-for.c
> >>> >> @@ -29,7 +29,9 @@ struct cmdq_node {
> >>> >>
> >>> >>  struct channel_node {
> >>> >>         char *name;
> >>> >> +       int locked;
> >>> >>         TAILQ_HEAD(, cmdq_node) waiting_cmdqs;
> >>> >> +       TAILQ_HEAD(, cmdq_node) locking_cmdqs;
> >>> >>         RB_ENTRY(channel_node) node;
> >>> >>  };
> >>> >>  RB_HEAD(channels, channel_node) channels_head = 
> >>> >> RB_INITIALIZER(&channels_head);
> >>> >> @@ -37,6 +39,8 @@ RB_HEAD(channels, channel_node) channels_head = 
> >>> >> RB_INITIALIZER(&channels_head);
> >>> >>  enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *);
> >>> >>  enum cmd_retval channel_wait(const char *, struct cmd_q *);
> >>> >>  enum cmd_retval channel_signal(const char *, struct cmd_q *);
> >>> >> +enum cmd_retval channel_lock(const char *, struct cmd_q *);
> >>> >> +enum cmd_retval channel_unlock(const char *, struct cmd_q *);
> >>> >>  struct channel_node *channels_find(const char *);
> >>> >>  struct channel_node *channels_find_or_create(const char *);
> >>> >>  int channel_cmp(struct channel_node *, struct channel_node *);
> >>> >> @@ -44,8 +48,8 @@ RB_PROTOTYPE(channels, channel_node, node, 
> >>> >> channel_cmp);
> >>> >>
> >>> >>  const struct cmd_entry cmd_wait_for_entry = {
> >>> >>         "wait-for", "wait",
> >>> >> -       "S", 1, 1,
> >>> >> -       "[-S] channel",
> >>> >> +       "LSU", 1, 1,
> >>> >> +       "[-L | -S | -U] channel",
> >>> >>         0,
> >>> >>         NULL,
> >>> >>         NULL,
> >>> >> @@ -61,6 +65,12 @@ cmd_wait_for_exec(struct cmd *self, struct cmd_q 
> >>> >> *cmdq)
> >>> >>         if (args_has(args, 'S'))
> >>> >>                 return channel_signal(name, cmdq);
> >>> >>
> >>> >> +       if (args_has(args, 'L'))
> >>> >> +               return channel_lock(name, cmdq);
> >>> >> +
> >>> >> +       if (args_has(args, 'U'))
> >>> >> +               return channel_unlock(name, cmdq);
> >>> >> +
> >>> >>         return channel_wait(name, cmdq);
> >>> >>  }
> >>> >>
> >>> >> @@ -90,7 +100,9 @@ channels_find_or_create(const char *name)
> >>> >>         if (c == NULL) {
> >>> >>                 c = xmalloc(sizeof *c);
> >>> >>                 c->name = xstrdup(name);
> >>> >> +               c->locked = 0;
> >>> >>                 TAILQ_INIT(&c->waiting_cmdqs);
> >>> >> +               TAILQ_INIT(&c->locking_cmdqs);
> >>> >>                 RB_INSERT(channels, &channels_head, c);
> >>> >>         }
> >>> >>
> >>> >> @@ -137,9 +149,67 @@ channel_signal(const char *name, struct cmd_q 
> >>> >> *cmdq)
> >>> >>                 free(wq);
> >>> >>         }
> >>> >>
> >>> >> -       RB_REMOVE(channels, &channels_head, c);
> >>> >> -       free(c->name);
> >>> >> -       free(c);
> >>> >> +       if (!c->locked) {
> >>> >> +               RB_REMOVE(channels, &channels_head, c);
> >>> >> +               free(c->name);
> >>> >> +               free(c);
> >>> >> +       }
> >>> >>
> >>> >>         return (CMD_RETURN_NORMAL);
> >>> >>  }
> >>> >> +
> >>> >> +enum cmd_retval
> >>> >> +channel_lock(const char *name, struct cmd_q *cmdq)
> >>> >> +{
> >>> >> +       struct cmdq_node *lq;
> >>> >> +       struct channel_node *c;
> >>> >> +
> >>> >> +       if (cmdq->client == NULL || cmdq->client->session != NULL) {
> >>> >> +               cmdq_error(cmdq, "Not able to lock");
> >>> >> +               return (CMD_RETURN_ERROR);
> >>> >> +       }
> >>> >> +
> >>> >> +       c = channels_find_or_create(name);
> >>> >> +
> >>> >> +       if (c->locked) {
> >>> >> +               lq = xmalloc(sizeof *lq);
> >>> >> +               lq->cmdq = cmdq;
> >>> >> +               TAILQ_INSERT_TAIL(&c->locking_cmdqs, lq, node);
> >>> >> +               cmdq->references++;
> >>> >> +               return (CMD_RETURN_WAIT);
> >>> >> +       }
> >>> >> +
> >>> >> +       c->locked = 1;
> >>> >> +       return (CMD_RETURN_NORMAL);
> >>> >> +}
> >>> >> +
> >>> >> +enum cmd_retval
> >>> >> +channel_unlock(const char *name, struct cmd_q *cmdq)
> >>> >> +{
> >>> >> +       struct cmdq_node *lq;
> >>> >> +       struct channel_node *c;
> >>> >> +
> >>> >> +       c = channels_find(name);
> >>> >> +
> >>> >> +       if (c == NULL || !c->locked) {
> >>> >> +               cmdq_error(cmdq, "Channel not locked");
> >>> >> +               return (CMD_RETURN_ERROR);
> >>> >> +       }
> >>> >> +
> >>> >> +       if ((lq = TAILQ_FIRST(&c->locking_cmdqs)) != NULL) {
> >>> >> +               TAILQ_REMOVE(&c->locking_cmdqs, lq, node);
> >>> >> +               if (!cmdq_free(lq->cmdq))
> >>> >> +                       cmdq_continue(lq->cmdq);
> >>> >> +               free(lq);
> >>> >> +       } else {
> >>> >> +               c->locked = 0;
> >>> >> +               if (TAILQ_EMPTY(&c->waiting_cmdqs)) {
> >>> >> +                       RB_REMOVE(channels, &channels_head, c);
> >>> >> +                       free(c->name);
> >>> >> +                       free(c);
> >>> >> +               }
> >>> >> +       }
> >>> >> +
> >>> >> +       return (CMD_RETURN_NORMAL);
> >>> >> +}
> >>> >> +
> >>> >
> >>> >> ------------------------------------------------------------------------------
> >>> >> Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester
> >>> >> Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the
> >>> >> endpoint security space. For insight on selecting the right partner to
> >>> >> tackle endpoint security challenges, access the full report.
> >>> >> http://p.sf.net/sfu/symantec-dev2dev
> >>> >
> >>> >> _______________________________________________
> >>> >> tmux-users mailing list
> >>> >> tmux-users@lists.sourceforge.net
> >>> >> https://lists.sourceforge.net/lists/listinfo/tmux-users
> >>> >

------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester  
Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the  
endpoint security space. For insight on selecting the right partner to 
tackle endpoint security challenges, access the full report. 
http://p.sf.net/sfu/symantec-dev2dev
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to