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