diff options
Diffstat (limited to 'run-command.h')
-rw-r--r-- | run-command.h | 276 |
1 files changed, 166 insertions, 110 deletions
diff --git a/run-command.h b/run-command.h index b9aff74..55f6631 100644 --- a/run-command.h +++ b/run-command.h @@ -44,23 +44,36 @@ struct child_process { /** - * The .argv member is set up as an array of string pointers (NULL - * terminated), of which .argv[0] is the program name to run (usually - * without a path). If the command to run is a git command, set argv[0] to - * the command name without the 'git-' prefix and set .git_cmd = 1. + * The .args is a `struct strvec', use that API to manipulate + * it, e.g. strvec_pushv() to add an existing "const char **" + * vector. * - * Note that the ownership of the memory pointed to by .argv stays with the - * caller, but it should survive until `finish_command` completes. If the - * .argv member is NULL, `start_command` will point it at the .args - * `strvec` (so you may use one or the other, but you must use exactly - * one). The memory in .args will be cleaned up automatically during - * `finish_command` (or during `start_command` when it is unsuccessful). + * If the command to run is a git command, set the first + * element in the strvec to the command name without the + * 'git-' prefix and set .git_cmd = 1. * + * The memory in .args will be cleaned up automatically during + * `finish_command` (or during `start_command` when it is unsuccessful). */ - const char **argv; - struct strvec args; - struct strvec env_array; + + /** + * Like .args the .env is a `struct strvec'. + * + * To modify the environment of the sub-process, specify an array of + * environment settings. Each string in the array manipulates the + * environment. + * + * - If the string is of the form "VAR=value", i.e. it contains '=' + * the variable is added to the child process's environment. + * + * - If the string does not contain '=', it names an environment + * variable that will be removed from the child process's environment. + * + * The memory in .env will be cleaned up automatically during + * `finish_command` (or during `start_command` when it is unsuccessful). + */ + struct strvec env; pid_t pid; int trace2_child_id; @@ -96,23 +109,6 @@ struct child_process { */ const char *dir; - /** - * To modify the environment of the sub-process, specify an array of - * string pointers (NULL terminated) in .env: - * - * - If the string is of the form "VAR=value", i.e. it contains '=' - * the variable is added to the child process's environment. - * - * - If the string does not contain '=', it names an environment - * variable that will be removed from the child process's environment. - * - * If the .env member is NULL, `start_command` will point it at the - * .env_array `strvec` (so you may use one or the other, but not both). - * The memory in .env_array will be cleaned up automatically during - * `finish_command` (or during `start_command` when it is unsuccessful). - */ - const char *const *env; - unsigned no_stdin:1; unsigned no_stdout:1; unsigned no_stderr:1; @@ -146,18 +142,15 @@ struct child_process { unsigned clean_on_exit:1; unsigned wait_after_clean:1; void (*clean_on_exit_handler)(struct child_process *process); - void *clean_on_exit_handler_cbdata; }; #define CHILD_PROCESS_INIT { \ .args = STRVEC_INIT, \ - .env_array = STRVEC_INIT, \ + .env = STRVEC_INIT, \ } /** - * The functions: child_process_init, start_command, finish_command, - * run_command, run_command_v_opt, run_command_v_opt_cd_env, child_process_clear - * do the following: + * The functions: start_command, finish_command, run_command do the following: * * - If a system call failed, errno is set and -1 is returned. A diagnostic * is printed. @@ -225,64 +218,17 @@ int finish_command_in_signal(struct child_process *); int run_command(struct child_process *); /* - * Returns the path to the hook file, or NULL if the hook is missing - * or disabled. Note that this points to static storage that will be - * overwritten by further calls to find_hook and run_hook_*. + * Prepare a `struct child_process` to run auto-maintenance. Returns 1 if the + * process has been prepared and is ready to run, or 0 in case auto-maintenance + * should be skipped. */ -const char *find_hook(const char *name); - -/** - * Run a hook. - * The first argument is a pathname to an index file, or NULL - * if the hook uses the default index file or no index is needed. - * The second argument is the name of the hook. - * The further arguments correspond to the hook arguments. - * The last argument has to be NULL to terminate the arguments list. - * If the hook does not exist or is not executable, the return - * value will be zero. - * If it is executable, the hook will be executed and the exit - * status of the hook is returned. - * On execution, .stdout_to_stderr and .no_stdin will be set. - */ -LAST_ARG_MUST_BE_NULL -int run_hook_le(const char *const *env, const char *name, ...); -int run_hook_ve(const char *const *env, const char *name, va_list args); +int prepare_auto_maintenance(int quiet, struct child_process *maint); /* * Trigger an auto-gc */ int run_auto_maintenance(int quiet); -#define RUN_COMMAND_NO_STDIN (1<<0) -#define RUN_GIT_CMD (1<<1) -#define RUN_COMMAND_STDOUT_TO_STDERR (1<<2) -#define RUN_SILENT_EXEC_FAILURE (1<<3) -#define RUN_USING_SHELL (1<<4) -#define RUN_CLEAN_ON_EXIT (1<<5) -#define RUN_WAIT_AFTER_CLEAN (1<<6) -#define RUN_CLOSE_OBJECT_STORE (1<<7) - -/** - * Convenience functions that encapsulate a sequence of - * start_command() followed by finish_command(). The argument argv - * specifies the program and its arguments. The argument opt is zero - * or more of the flags `RUN_COMMAND_NO_STDIN`, `RUN_GIT_CMD`, - * `RUN_COMMAND_STDOUT_TO_STDERR`, or `RUN_SILENT_EXEC_FAILURE` - * that correspond to the members .no_stdin, .git_cmd, - * .stdout_to_stderr, .silent_exec_failure of `struct child_process`. - * The argument dir corresponds the member .dir. The argument env - * corresponds to the member .env. - */ -int run_command_v_opt(const char **argv, int opt); -int run_command_v_opt_tr2(const char **argv, int opt, const char *tr2_class); -/* - * env (the environment) is to be formatted like environ: "VAR=VALUE". - * To unset an environment variable use just "VAR". - */ -int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env); -int run_command_v_opt_cd_env_tr2(const char **argv, int opt, const char *dir, - const char *const *env, const char *tr2_class); - /** * Execute the given command, sending "in" to its stdin, and capturing its * stdout and stderr in the "out" and "err" strbufs. Any of the three may @@ -434,6 +380,9 @@ void check_pipe(int err); * pp_cb is the callback cookie as passed to run_processes_parallel. * You can store a child process specific callback cookie in pp_task_cb. * + * See run_processes_parallel() below for a discussion of the "struct + * strbuf *out" parameter. + * * Even after returning 0 to indicate that there are no more processes, * this function will be called again until there are no more running * child processes. @@ -452,9 +401,8 @@ typedef int (*get_next_task_fn)(struct child_process *cp, * This callback is called whenever there are problems starting * a new process. * - * You must not write to stdout or stderr in this function. Add your - * message to the strbuf out instead, which will be printed without - * messing up the output of the other parallel processes. + * See run_processes_parallel() below for a discussion of the "struct + * strbuf *out" parameter. * * pp_cb is the callback cookie as passed into run_processes_parallel, * pp_task_cb is the callback cookie as passed into get_next_task_fn. @@ -470,9 +418,8 @@ typedef int (*start_failure_fn)(struct strbuf *out, /** * This callback is called on every child process that finished processing. * - * You must not write to stdout or stderr in this function. Add your - * message to the strbuf out instead, which will be printed without - * messing up the output of the other parallel processes. + * See run_processes_parallel() below for a discussion of the "struct + * strbuf *out" parameter. * * pp_cb is the callback cookie as passed into run_processes_parallel, * pp_task_cb is the callback cookie as passed into get_next_task_fn. @@ -487,34 +434,143 @@ typedef int (*task_finished_fn)(int result, void *pp_task_cb); /** - * Runs up to n processes at the same time. Whenever a process can be - * started, the callback get_next_task_fn is called to obtain the data + * Option used by run_processes_parallel(), { 0 }-initialized means no + * options. + */ +struct run_process_parallel_opts +{ + /** + * tr2_category & tr2_label: sets the trace2 category and label for + * logging. These must either be unset, or both of them must be set. + */ + const char *tr2_category; + const char *tr2_label; + + /** + * processes: see 'processes' in run_processes_parallel() below. + */ + size_t processes; + + /** + * ungroup: see 'ungroup' in run_processes_parallel() below. + */ + unsigned int ungroup:1; + + /** + * get_next_task: See get_next_task_fn() above. This must be + * specified. + */ + get_next_task_fn get_next_task; + + /** + * start_failure: See start_failure_fn() above. This can be + * NULL to omit any special handling. + */ + start_failure_fn start_failure; + + /** + * task_finished: See task_finished_fn() above. This can be + * NULL to omit any special handling. + */ + task_finished_fn task_finished; + + /** + * data: user data, will be passed as "pp_cb" to the callback + * parameters. + */ + void *data; +}; + +/** + * Options are passed via the "struct run_process_parallel_opts" above. + * + * Runs N 'processes' at the same time. Whenever a process can be + * started, the callback opts.get_next_task is called to obtain the data * required to start another child process. * * The children started via this function run in parallel. Their output * (both stdout and stderr) is routed to stderr in a manner that output - * from different tasks does not interleave. - * - * start_failure_fn and task_finished_fn can be NULL to omit any - * special handling. + * from different tasks does not interleave (but see "ungroup" below). + * + * If the "ungroup" option isn't specified, the API will set the + * "stdout_to_stderr" parameter in "struct child_process" and provide + * the callbacks with a "struct strbuf *out" parameter to write output + * to. In this case the callbacks must not write to stdout or + * stderr as such output will mess up the output of the other parallel + * processes. If "ungroup" option is specified callbacks will get a + * NULL "struct strbuf *out" parameter, and are responsible for + * emitting their own output, including dealing with any race + * conditions due to writing in parallel to stdout and stderr. */ -int run_processes_parallel(int n, - get_next_task_fn, - start_failure_fn, - task_finished_fn, - void *pp_cb); -int run_processes_parallel_tr2(int n, get_next_task_fn, start_failure_fn, - task_finished_fn, void *pp_cb, - const char *tr2_category, const char *tr2_label); +void run_processes_parallel(const struct run_process_parallel_opts *opts); /** - * Convenience function which prepares env_array for a command to be run in a - * new repo. This adds all GIT_* environment variables to env_array with the + * Convenience function which prepares env for a command to be run in a + * new repo. This adds all GIT_* environment variables to env with the * exception of GIT_CONFIG_PARAMETERS and GIT_CONFIG_COUNT (which cause the * corresponding environment variables to be unset in the subprocess) and adds * an environment variable pointing to new_git_dir. See local_repo_env in - * cache.h for more information. + * environment.h for more information. */ -void prepare_other_repo_env(struct strvec *env_array, const char *new_git_dir); +void prepare_other_repo_env(struct strvec *env, const char *new_git_dir); + +/** + * Possible return values for start_bg_command(). + */ +enum start_bg_result { + /* child process is "ready" */ + SBGR_READY = 0, + + /* child process could not be started */ + SBGR_ERROR, + + /* callback error when testing for "ready" */ + SBGR_CB_ERROR, + + /* timeout expired waiting for child to become "ready" */ + SBGR_TIMEOUT, + + /* child process exited or was signalled before becomming "ready" */ + SBGR_DIED, +}; + +/** + * Callback used by start_bg_command() to ask whether the + * child process is ready or needs more time to become "ready". + * + * The callback will receive the cmd and cb_data arguments given to + * start_bg_command(). + * + * Returns 1 is child needs more time (subject to the requested timeout). + * Returns 0 if child is "ready". + * Returns -1 on any error and cause start_bg_command() to also error out. + */ +typedef int(start_bg_wait_cb)(const struct child_process *cmd, void *cb_data); + +/** + * Start a command in the background. Wait long enough for the child + * to become "ready" (as defined by the provided callback). Capture + * immediate errors (like failure to start) and any immediate exit + * status (such as a shutdown/signal before the child became "ready") + * and return this like start_command(). + * + * We run a custom wait loop using the provided callback to wait for + * the child to start and become "ready". This is limited by the given + * timeout value. + * + * If the child does successfully start and become "ready", we orphan + * it into the background. + * + * The caller must not call finish_command(). + * + * The opaque cb_data argument will be forwarded to the callback for + * any instance data that it might require. This may be NULL. + */ +enum start_bg_result start_bg_command(struct child_process *cmd, + start_bg_wait_cb *wait_cb, + void *cb_data, + unsigned int timeout_sec); + +int sane_execvp(const char *file, char *const argv[]); #endif |