1
0
mirror of https://github.com/tmate-io/tmate-ssh-server.git synced 2020-11-18 19:53:51 -08:00

Change wait-for to work when the signal comes before the wait, also use

some helper functions and add some logging.
This commit is contained in:
nicm 2015-09-04 12:02:44 +00:00
parent 82326dcbe2
commit aceae73b9a

View File

@ -41,6 +41,7 @@ const struct cmd_entry cmd_wait_for_entry = {
struct wait_channel { struct wait_channel {
const char *name; const char *name;
int locked; int locked;
int woken;
TAILQ_HEAD(, cmd_q) waiters; TAILQ_HEAD(, cmd_q) waiters;
TAILQ_HEAD(, cmd_q) lockers; 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 *, enum cmd_retval cmd_wait_for_unlock(struct cmd_q *, const char *,
struct wait_channel *); 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 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; struct args *args = self->args;
const char *name = args->argv[0]; const char *name = args->argv[0];
@ -89,15 +131,20 @@ cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq)
} }
enum cmd_retval 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 wait_channel *wc)
{ {
struct cmd_q *wq, *wq1; struct cmd_q *wq, *wq1;
if (wc == NULL || TAILQ_EMPTY(&wc->waiters)) { if (wc == NULL)
cmdq_error(cmdq, "no waiting clients on %s", name); wc = cmd_wait_for_add(name);
return (CMD_RETURN_ERROR);
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_FOREACH_SAFE(wq, &wc->waiters, waitentry, wq1) {
TAILQ_REMOVE(&wc->waiters, wq, waitentry); TAILQ_REMOVE(&wc->waiters, wq, waitentry);
@ -105,12 +152,7 @@ cmd_wait_for_signal(struct cmd_q *cmdq, const char *name,
cmdq_continue(wq); cmdq_continue(wq);
} }
if (!wc->locked) { cmd_wait_for_remove(wc);
RB_REMOVE(wait_channels, &wait_channels, wc);
free((void *)wc->name);
free(wc);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@ -118,19 +160,23 @@ enum cmd_retval
cmd_wait_for_wait(struct cmd_q *cmdq, const char *name, cmd_wait_for_wait(struct cmd_q *cmdq, const char *name,
struct wait_channel *wc) 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"); cmdq_error(cmdq, "not able to wait");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (wc == NULL) { if (wc == NULL)
wc = xmalloc(sizeof *wc); wc = cmd_wait_for_add(name);
wc->name = xstrdup(name);
wc->locked = 0; if (wc->woken) {
TAILQ_INIT(&wc->waiters); log_debug("wait channel %s already woken (client %d)", wc->name,
TAILQ_INIT(&wc->lockers); c->tty.fd);
RB_INSERT(wait_channels, &wait_channels, wc); 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); TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry);
cmdq->references++; cmdq->references++;
@ -147,14 +193,8 @@ cmd_wait_for_lock(struct cmd_q *cmdq, const char *name,
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (wc == NULL) { if (wc == NULL)
wc = xmalloc(sizeof *wc); wc = cmd_wait_for_add(name);
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) { if (wc->locked) {
TAILQ_INSERT_TAIL(&wc->lockers, cmdq, waitentry); 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); cmdq_continue(wq);
} else { } else {
wc->locked = 0; wc->locked = 0;
if (TAILQ_EMPTY(&wc->waiters)) { cmd_wait_for_remove(wc);
RB_REMOVE(wait_channels, &wait_channels, wc);
free((void *)wc->name);
free(wc);
}
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@ -210,8 +246,7 @@ cmd_wait_for_flush(void)
if (!cmdq_free(wq)) if (!cmdq_free(wq))
cmdq_continue(wq); cmdq_continue(wq);
} }
RB_REMOVE(wait_channels, &wait_channels, wc); wc->locked = 0;
free((void *)wc->name); cmd_wait_for_remove(wc);
free(wc);
} }
} }