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