version 1.1, 2013/03/25 10:09:05 |
version 1.2, 2013/03/25 10:09:35 |
|
|
|
|
const struct cmd_entry cmd_wait_for_entry = { |
const struct cmd_entry cmd_wait_for_entry = { |
"wait-for", "wait", |
"wait-for", "wait", |
"S", 1, 1, |
"LSU", 1, 1, |
"[-S] channel", |
"[-LSU] channel", |
0, |
0, |
NULL, |
NULL, |
NULL, |
NULL, |
|
|
|
|
struct wait_channel { |
struct wait_channel { |
const char *name; |
const char *name; |
|
int locked; |
|
|
TAILQ_HEAD(, cmd_q) waiters; |
TAILQ_HEAD(, cmd_q) waiters; |
|
TAILQ_HEAD(, cmd_q) lockers; |
|
|
RB_ENTRY(wait_channel) entry; |
RB_ENTRY(wait_channel) entry; |
}; |
}; |
|
|
struct wait_channel *); |
struct wait_channel *); |
enum cmd_retval cmd_wait_for_wait(struct cmd_q *, const char *, |
enum cmd_retval cmd_wait_for_wait(struct cmd_q *, const char *, |
struct wait_channel *); |
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 |
enum cmd_retval |
cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq) |
cmd_wait_for_exec(struct cmd *self, struct cmd_q *cmdq) |
|
|
|
|
if (args_has(args, 'S')) |
if (args_has(args, 'S')) |
return (cmd_wait_for_signal(cmdq, name, wc)); |
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)); |
return (cmd_wait_for_wait(cmdq, name, wc)); |
} |
} |
|
|
|
|
if (!cmdq_free(wq)) |
if (!cmdq_free(wq)) |
cmdq_continue(wq); |
cmdq_continue(wq); |
} |
} |
RB_REMOVE(wait_channels, &wait_channels, wc); |
|
free((void*) wc->name); |
|
free(wc); |
|
|
|
|
if (!wc->locked) { |
|
RB_REMOVE(wait_channels, &wait_channels, wc); |
|
free((void*) wc->name); |
|
free(wc); |
|
} |
|
|
return (CMD_RETURN_NORMAL); |
return (CMD_RETURN_NORMAL); |
} |
} |
|
|
|
|
if (wc == NULL) { |
if (wc == NULL) { |
wc = xmalloc(sizeof *wc); |
wc = xmalloc(sizeof *wc); |
wc->name = xstrdup(name); |
wc->name = xstrdup(name); |
|
wc->locked = 0; |
TAILQ_INIT(&wc->waiters); |
TAILQ_INIT(&wc->waiters); |
|
TAILQ_INIT(&wc->lockers); |
RB_INSERT(wait_channels, &wait_channels, wc); |
RB_INSERT(wait_channels, &wait_channels, wc); |
} |
} |
|
|
TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry); |
TAILQ_INSERT_TAIL(&wc->waiters, cmdq, waitentry); |
cmdq->references++; |
cmdq->references++; |
|
|
return (CMD_RETURN_WAIT); |
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); |
|
} |
|
|