version 1.7, 2014/10/20 22:29:25 |
version 1.8, 2015/09/04 12:02:44 |
|
|
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; |
|
|
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]; |
|
|
} |
} |
|
|
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); |
|
|
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); |
} |
} |
|
|
|
|
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++; |
|
|
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); |
|
|
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); |
|
|
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); |
|
} |
} |
} |
} |