mirror of
https://github.com/tmate-io/tmate.git
synced 2024-12-23 23:29:15 +01:00
Add wait-for -L and -U for lock and unlock, from Thiago Padilha.
This commit is contained in:
parent
410a3abbef
commit
748acdc77c
197
cmd-wait-for.c
Normal file
197
cmd-wait-for.c
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
/* $OpenBSD$ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||||
|
* Copyright (c) 2013 Thiago de Arruda <tpadilha84@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",
|
||||||
|
"LSU", 1, 1,
|
||||||
|
"[-LSU] channel",
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
cmd_wait_for_exec
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wait_channel {
|
||||||
|
const char *name;
|
||||||
|
int locked;
|
||||||
|
|
||||||
|
TAILQ_HEAD(, cmd_q) waiters;
|
||||||
|
TAILQ_HEAD(, cmd_q) lockers;
|
||||||
|
|
||||||
|
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_lock(struct cmd_q *, const char *,
|
||||||
|
struct wait_channel *);
|
||||||
|
enum cmd_retval cmd_wait_for_unlock(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));
|
||||||
|
if (args_has(args, 'L'))
|
||||||
|
return (cmd_wait_for_lock(cmdq, name, wc));
|
||||||
|
if (args_has(args, 'U'))
|
||||||
|
return (cmd_wait_for_unlock(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wc->locked) {
|
||||||
|
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);
|
||||||
|
wc->locked = 0;
|
||||||
|
TAILQ_INIT(&wc->waiters);
|
||||||
|
TAILQ_INIT(&wc->lockers);
|
||||||
|
RB_INSERT(wait_channels, &wait_channels, wc);
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
|
||||||
|
cmdq->references++;
|
||||||
|
|
||||||
|
return (CMD_RETURN_WAIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum cmd_retval
|
||||||
|
cmd_wait_for_lock(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 lock");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wc == NULL) {
|
||||||
|
wc = xmalloc(sizeof *wc);
|
||||||
|
wc->name = xstrdup(name);
|
||||||
|
wc->locked = 0;
|
||||||
|
TAILQ_INIT(&wc->waiters);
|
||||||
|
TAILQ_INIT(&wc->lockers);
|
||||||
|
RB_INSERT(wait_channels, &wait_channels, wc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wc->locked) {
|
||||||
|
TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry);
|
||||||
|
cmdq->references++;
|
||||||
|
return (CMD_RETURN_WAIT);
|
||||||
|
}
|
||||||
|
wc->locked = 1;
|
||||||
|
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum cmd_retval
|
||||||
|
cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
|
||||||
|
struct wait_channel *wc)
|
||||||
|
{
|
||||||
|
struct cmd_q *wq;
|
||||||
|
|
||||||
|
if (wc == NULL || !wc->locked) {
|
||||||
|
cmdq_error(cmdq, "channel %s not locked", name);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) {
|
||||||
|
TAILQ_REMOVE(&wc->lockers, wq, waitentry);
|
||||||
|
if (!cmdq_free(wq))
|
||||||
|
cmdq_continue(wq);
|
||||||
|
} else {
|
||||||
|
wc->locked = 0;
|
||||||
|
if (TAILQ_EMPTY(&wc->waiters)) {
|
||||||
|
RB_REMOVE(wait_channels, &wait_channels, wc);
|
||||||
|
free((void*) wc->name);
|
||||||
|
free(wc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
35
tmux.1
35
tmux.1
@ -1062,8 +1062,7 @@ By default, it uses the format
|
|||||||
but a different format may be specified with
|
but a different format may be specified with
|
||||||
.Fl F .
|
.Fl F .
|
||||||
.It Xo Ic capture-pane
|
.It Xo Ic capture-pane
|
||||||
.Op Fl e
|
.Op Fl aepq
|
||||||
.Op Fl p
|
|
||||||
.Op Fl b Ar buffer-index
|
.Op Fl b Ar buffer-index
|
||||||
.Op Fl E Ar end-line
|
.Op Fl E Ar end-line
|
||||||
.Op Fl S Ar start-line
|
.Op Fl S Ar start-line
|
||||||
@ -1077,13 +1076,19 @@ is given, the output goes to stdout, otherwise to the buffer specified with
|
|||||||
.Fl b
|
.Fl b
|
||||||
or a new buffer if omitted.
|
or a new buffer if omitted.
|
||||||
If
|
If
|
||||||
|
.Fl a
|
||||||
|
is given, the alternate screen is used, and the history is not accessible.
|
||||||
|
If no alternate screen exists, an error will be returned unless
|
||||||
|
.Fl q
|
||||||
|
is given.
|
||||||
|
If
|
||||||
.Fl e
|
.Fl e
|
||||||
is given, the output includes escape sequences for text and background
|
is given, the output includes escape sequences for text and background
|
||||||
attributes.
|
attributes.
|
||||||
.Fl C
|
.Fl C
|
||||||
also escapes non-printable characters as octal \exxx.
|
also escapes non-printable characters as octal \exxx.
|
||||||
.Fl J
|
.Fl J
|
||||||
joins wrapped lines.
|
joins wrapped lines and preserves trailing spaces at each line's end.
|
||||||
.Pp
|
.Pp
|
||||||
.Fl S
|
.Fl S
|
||||||
and
|
and
|
||||||
@ -2946,7 +2951,7 @@ If this option is set, searches will wrap around the end of the pane contents.
|
|||||||
The default is on.
|
The default is on.
|
||||||
.El
|
.El
|
||||||
.It Xo Ic show-options
|
.It Xo Ic show-options
|
||||||
.Op Fl gsvw
|
.Op Fl gqsvw
|
||||||
.Op Fl t Ar target-session | Ar target-window
|
.Op Fl t Ar target-session | Ar target-window
|
||||||
.Op Ar option
|
.Op Ar option
|
||||||
.Xc
|
.Xc
|
||||||
@ -2964,6 +2969,11 @@ Global session or window options are listed if
|
|||||||
is used.
|
is used.
|
||||||
.Fl v
|
.Fl v
|
||||||
shows only the option value, not the name.
|
shows only the option value, not the name.
|
||||||
|
If
|
||||||
|
.Fl q
|
||||||
|
is set, no error will be returned if
|
||||||
|
.Ar option
|
||||||
|
is unset.
|
||||||
.It Xo Ic show-window-options
|
.It Xo Ic show-window-options
|
||||||
.Op Fl gv
|
.Op Fl gv
|
||||||
.Op Fl t Ar target-window
|
.Op Fl t Ar target-window
|
||||||
@ -3539,6 +3549,23 @@ If the command doesn't return success, the exit status is also displayed.
|
|||||||
.It Ic server-info
|
.It Ic server-info
|
||||||
.D1 (alias: Ic info )
|
.D1 (alias: Ic info )
|
||||||
Show server information and terminal details.
|
Show server information and terminal details.
|
||||||
|
.It Xo Ic wait-for
|
||||||
|
.Fl LSU
|
||||||
|
.Ar channel
|
||||||
|
.Xc
|
||||||
|
.D1 (alias: Ic wait )
|
||||||
|
When used without options, prevents the client from exiting until woken using
|
||||||
|
.Ic wait-for
|
||||||
|
.Fl S
|
||||||
|
with the same channel.
|
||||||
|
When
|
||||||
|
.Fl L
|
||||||
|
is used, the channel is locked and any clients that try to lock the same
|
||||||
|
channel are made to wait until the channel is unlocked with
|
||||||
|
.Ic wait-for
|
||||||
|
.Fl U .
|
||||||
|
This command only works from outside
|
||||||
|
.Nm .
|
||||||
.El
|
.El
|
||||||
.Sh TERMINFO EXTENSIONS
|
.Sh TERMINFO EXTENSIONS
|
||||||
.Nm
|
.Nm
|
||||||
|
Loading…
Reference in New Issue
Block a user