The branch, hooks has been updated via 0ef7ad4d824b1dd039ac10a2513deda7d9356c85 (commit) from 91b245e42e4393193f13566bb09d8bcb31f1005b (commit)
- Log ----------------------------------------------------------------- commit 0ef7ad4d824b1dd039ac10a2513deda7d9356c85 Author: Thomas Adam <tho...@xteddy.org> Commit: Thomas Adam <tho...@xteddy.org> Make hooked commands use cmdq_continue() Certain commands (such as if-shell and run-shell) return CMD_RETURN_WAIT, which is designed to block tmux until they complete. Rather than side-lining the logic in cmdq_continue(), make all hooked commands go through cmdq_continue() to benefit from its logic. This change therefore uses up to three cmdqs; one for the before hooks, the hooked command itself, and the after hooks. When a command is found to have before hooks, the cmdq is swapped out, and the hooked command added to the emptyfn() callback so that it can continue processing where it left off. After hooks just run once the hooked command has completed. --- cmd-queue.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++---------- hooks.c | 19 +++++++---------- tmux.h | 8 +++++- 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/cmd-queue.c b/cmd-queue.c index d364ba8..8d4f50f 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -25,9 +25,11 @@ #include "tmux.h" -void cmdq_run_hook(struct hooks *, const char *, struct cmd *, +int cmdq_run_hook(struct hooks *, const char *, struct cmd *, struct cmd_q *); +int running_hooks = 0; + /* Create new command queue. */ struct cmd_q * cmdq_new(struct client *c) @@ -150,17 +152,33 @@ cmdq_run(struct cmd_q *cmdq, struct cmd_list *cmdlist) } /* Run hooks based on the hooks prefix (before/after). */ -void +int cmdq_run_hook(struct hooks *hooks, const char *prefix, struct cmd *cmd, struct cmd_q *cmdq) { struct hook *hook; + struct cmd_q *hooks_cmdq; char *s; + int retval; xasprintf(&s, "%s-%s", prefix, cmd->entry->name); - if ((hook = hooks_find(hooks, s)) != NULL) - hooks_run(hook, cmdq); + if ((hook = hooks_find(hooks, s)) == NULL) { + cmdq->hooks_ran = 0; + retval = 0; + goto done; + } + + hooks_cmdq = cmdq_new(cmdq->client); + hooks_cmdq->orig_cmdq = cmdq; + hooks_cmdq->emptyfn = hooks_emptyfn; + hooks_cmdq->hooks_ran = 1; + cmdq->references++; + cmdq_run(hooks_cmdq, hook->cmdlist); + retval = 1; + +done: free(s); + return (retval); } /* Add command list to queue. */ @@ -192,11 +210,17 @@ cmdq_continue(struct cmd_q *cmdq) if (empty) goto empty; - if (cmdq->item == NULL) { - cmdq->item = TAILQ_FIRST(&cmdq->queue); - cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list); - } else - cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry); + /* If the command isn't in the middle of running hooks (due to + * CMD_RETURN_WAIT), move onto the next command; otherwise, leave the + * state of the queue as is; we're already in the correct place. + */ + if (cmdq->during == 0) { + if (cmdq->item == NULL) { + cmdq->item = TAILQ_FIRST(&cmdq->queue); + cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list); + } else + cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry); + } do { while (cmdq->cmd != NULL) { @@ -210,6 +234,14 @@ cmdq_continue(struct cmd_q *cmdq) cmdq->number++; flags = !!(cmd->flags & CMD_CONTROL); + + /* + * If we've come here because of running hooks, just + * run the command. + */ + if (cmdq->during == 1) + goto runme; + guard = cmdq_guard(cmdq, "begin", flags); if (cmd_prepare_state(cmd, cmdq) != 0) { @@ -224,13 +256,21 @@ cmdq_continue(struct cmd_q *cmdq) hooks = &cmdq->state.sflag.s->hooks; else hooks = &global_hooks; - cmdq_run_hook(hooks, "before", cmd, cmdq); + + if (cmdq->hooks_ran == 0) { + if (cmdq_run_hook(hooks, "before", cmd, + cmdq) == 1) { + cmdq->during = 1; + goto out; + } + } /* * hooks_run will change the state before each hook, so * it needs to be restored afterwards. XXX not very * obvious how this works from here... */ +runme: if (cmd_prepare_state(cmd, cmdq) != 0) retval = CMD_RETURN_ERROR; else @@ -240,7 +280,8 @@ cmdq_continue(struct cmd_q *cmdq) cmdq_guard(cmdq, "error", flags); break; } - cmdq_run_hook(hooks, "after", cmd, cmdq); + if (cmdq_run_hook(hooks, "after", cmd, cmdq) == 1) + goto out; if (guard) cmdq_guard(cmdq, "end", flags); diff --git a/hooks.c b/hooks.c index d485ae0..80e1c89 100644 --- a/hooks.c +++ b/hooks.c @@ -61,7 +61,6 @@ hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist) hook->name = xstrdup(name); hook->cmdlist = cmdlist; hook->cmdlist->references++; - RB_INSERT(hooks_tree, &hooks->tree, hook); } @@ -100,19 +99,17 @@ hooks_find(struct hooks *hooks, const char *name) } void -hooks_run(struct hook *hook, struct cmd_q *cmdq) +hooks_emptyfn(struct cmd_q *cmdq1) { - struct cmd *cmd; - char tmp[BUFSIZ]; + struct cmd_q *cmdq = cmdq1->orig_cmdq; - cmd_list_print(hook->cmdlist, tmp, sizeof tmp); - log_debug("entering hook %s: %s", hook->name, tmp); + if (cmdq1->client_exit >= 0) + cmdq->client_exit = cmdq1->client_exit; - TAILQ_FOREACH(cmd, &hook->cmdlist->list, qentry) { - /* TA: FIXME: How do we handle errors here, if at all??? */ - if (cmd_prepare_state(cmd, cmdq) == 0) - cmd->entry->exec(cmd, cmdq); + if (!cmdq_free(cmdq)) { + cmdq->hooks_ran = 1; + cmdq_continue(cmdq); } - log_debug("exiting hook %s", hook->name); + cmdq_free(cmdq1); } diff --git a/tmux.h b/tmux.h index af82efc..387fe3f 100644 --- a/tmux.h +++ b/tmux.h @@ -1030,6 +1030,7 @@ RB_HEAD(environ, environ_entry); /* Hooks. */ struct hook { const char *name; + struct cmd_q *cmdq; struct cmd_list *cmdlist; RB_ENTRY(hook) entry; }; @@ -1433,6 +1434,9 @@ struct cmd_q { void *data; TAILQ_ENTRY(cmd_q) waitentry; + struct cmd_q *orig_cmdq; + int hooks_ran; + int during; }; /* Command definition. */ @@ -1535,6 +1539,7 @@ extern time_t start_time; extern char socket_path[PATH_MAX]; extern int login_shell; extern char *environ_path; +extern int running_hooks; void logfile(const char *); const char *getshell(void); int checkshell(const char *); @@ -1579,9 +1584,8 @@ void hooks_free(struct hooks *); void hooks_add(struct hooks *, const char *, struct cmd_list *); void hooks_copy(struct hooks *, struct hooks *); void hooks_remove(struct hooks *, struct hook *); -void hooks_run(struct hook *, struct cmd_q *); struct hook *hooks_find(struct hooks *, const char *); - +void hooks_emptyfn(struct cmd_q *cmdq); /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; extern struct mode_key_tree mode_key_tree_vi_edit; ----------------------------------------------------------------------- Summary of changes: cmd-queue.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++---------- hooks.c | 19 +++++++---------- tmux.h | 8 +++++- 3 files changed, 66 insertions(+), 24 deletions(-) hooks/post-receive -- tmux ------------------------------------------------------------------------------ Dive into the World of Parallel Programming. The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ _______________________________________________ tmux-cvs mailing list tmux-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-cvs