summaryrefslogtreecommitdiff
path: root/usr.bin/tmux/cmd-wait-for.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/tmux/cmd-wait-for.c')
-rw-r--r--usr.bin/tmux/cmd-wait-for.c107
1 files changed, 71 insertions, 36 deletions
diff --git a/usr.bin/tmux/cmd-wait-for.c b/usr.bin/tmux/cmd-wait-for.c
index 8358b5cdbbe..2bdbd594c14 100644
--- a/usr.bin/tmux/cmd-wait-for.c
+++ b/usr.bin/tmux/cmd-wait-for.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-wait-for.c,v 1.7 2014/10/20 22:29:25 nicm Exp $ */
+/* $OpenBSD: cmd-wait-for.c,v 1.8 2015/09/04 12:02:44 nicm Exp $ */
/*
* Copyright (c) 2013 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -41,6 +41,7 @@ const struct cmd_entry cmd_wait_for_entry = {
struct wait_channel {
const char *name;
int locked;
+ int woken;
TAILQ_HEAD(, cmd_q) waiters;
TAILQ_HEAD(, cmd_q) lockers;
@@ -69,8 +70,49 @@ enum cmd_retval cmd_wait_for_lock(struct cmd_q *, const char *,
enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *,
struct wait_channel *);
+struct wait_channel *cmd_wait_for_add(const char *);
+void cmd_wait_for_remove(struct wait_channel *wc);
+
+struct wait_channel *
+cmd_wait_for_add(const char *name)
+{
+ struct wait_channel *wc;
+
+ wc = xmalloc(sizeof *wc);
+ wc->name = xstrdup(name);
+
+ wc->locked = 0;
+ wc->woken = 0;
+
+ TAILQ_INIT(&wc->waiters);
+ TAILQ_INIT(&wc->lockers);
+
+ RB_INSERT(wait_channels, &wait_channels, wc);
+
+ log_debug("add wait channel %s", wc->name);
+
+ return (wc);
+}
+
+void
+cmd_wait_for_remove(struct wait_channel *wc)
+{
+
+ if (wc->locked)
+ return;
+ if (!TAILQ_EMPTY(&wc->waiters) || !wc->woken)
+ return;
+
+ log_debug("remove wait channel %s", wc->name);
+
+ RB_REMOVE(wait_channels, &wait_channels, wc);
+
+ free((void *)wc->name);
+ free(wc);
+}
+
enum cmd_retval
-cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
+cmd_wait_for_exec(struct cmd *self, unused struct cmd_q *cmdq)
{
struct args *args = self->args;
const char *name = args->argv[0];
@@ -89,15 +131,20 @@ cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
}
enum cmd_retval
-cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
+cmd_wait_for_signal(unused 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);
+ if (wc == NULL)
+ wc = cmd_wait_for_add(name);
+
+ if (TAILQ_EMPTY(&wc->waiters) && !wc->woken) {
+ log_debug("signal wait channel %s, no waiters", wc->name);
+ wc->woken = 1;
+ return (CMD_RETURN_NORMAL);
}
+ log_debug("signal wait channel %s, with waiters", wc->name);
TAILQ_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry);
@@ -105,12 +152,7 @@ cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
cmdq_continue(wq);
}
- if (!wc->locked) {
- RB_REMOVE(wait_channels, &wait_channels, wc);
- free((void *)wc->name);
- free(wc);
- }
-
+ cmd_wait_for_remove(wc);
return (CMD_RETURN_NORMAL);
}
@@ -118,19 +160,23 @@ 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) {
+ struct client *c = cmdq->client;
+
+ if (c == NULL || c->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);
+ if (wc == NULL)
+ wc = cmd_wait_for_add(name);
+
+ if (wc->woken) {
+ log_debug("wait channel %s already woken (client %d)", wc->name,
+ c->tty.fd);
+ cmd_wait_for_remove(wc);
+ return (CMD_RETURN_NORMAL);
}
+ log_debug("wait channel %s not woken (client %d)", wc->name, c->tty.fd);
TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
cmdq->references++;
@@ -147,14 +193,8 @@ cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
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 == NULL)
+ wc = cmd_wait_for_add(name);
if (wc->locked) {
TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry);
@@ -183,11 +223,7 @@ cmd_wait_for_unlock(struct cmd_q *cmdq, const char *name,
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);
- }
+ cmd_wait_for_remove(wc);
}
return (CMD_RETURN_NORMAL);
@@ -210,8 +246,7 @@ cmd_wait_for_flush(void)
if (!cmdq_free(wq))
cmdq_continue(wq);
}
- RB_REMOVE(wait_channels, &wait_channels, wc);
- free((void *)wc->name);
- free(wc);
+ wc->locked = 0;
+ cmd_wait_for_remove(wc);
}
}