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