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