summaryrefslogtreecommitdiff
path: root/run-command.h
diff options
context:
space:
mode:
Diffstat (limited to 'run-command.h')
-rw-r--r--run-command.h276
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