git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH amend 08/14] Add infrastructure to run a function asynchronously.

From
Johannes Sixt <johannes.sixt@telecom.at>
Date
Oct 14, 2007, 17:08 UTC
Message-ID
<200710141908.45779.johannes.sixt@telecom.at>
In-Reply-To
<1192305984-22594-9-git-send-email-johannes.sixt@telecom.at>

This adds start_async() and finish_async(), which runs a function asynchronously. Communication with the caller happens only via pipes. For this reason, this implementation forks off a child process that runs the function.

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>
---

This is the same as submitted previously except it uses close_pair() to close the pipe in an error patch and improves the comments in run-command.h.

-- Hannes
 run-command.c |   52 ++++++++++++++++++++++++++++++++++++++++++++--------
 run-command.h |   22 ++++++++++++++++++++++
 2 files changed, 66 insertions(+), 8 deletions(-)
diff --git a/run-command.c b/run-command.c
index d00c03b..db02f75 100644
--- a/run-command.c
+++ b/run-command.c
@@ -127,16 +127,11 @@ int start_command(struct child_process *cmd)
 	return 0;
 }
 
-int finish_command(struct child_process *cmd)
+static int wait_or_whine(pid_t pid)
 {
-	if (cmd->close_in)
-		close(cmd->in);
-	if (cmd->close_out)
-		close(cmd->out);
-
 	for (;;) {
 		int status, code;
-		pid_t waiting = waitpid(cmd->pid, &status, 0);
+		pid_t waiting = waitpid(pid, &status, 0);
 
 		if (waiting < 0) {
 			if (errno == EINTR)
@@ -144,7 +139,7 @@ int finish_command(struct child_process *cmd)
 			error("waitpid failed (%s)", strerror(errno));
 			return -ERR_RUN_COMMAND_WAITPID;
 		}
-		if (waiting != cmd->pid)
+		if (waiting != pid)
 			return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
 		if (WIFSIGNALED(status))
 			return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
@@ -158,6 +153,15 @@ int finish_command(struct child_process *cmd)
 	}
 }
 
+int finish_command(struct child_process *cmd)
+{
+	if (cmd->close_in)
+		close(cmd->in);
+	if (cmd->close_out)
+		close(cmd->out);
+	return wait_or_whine(cmd->pid);
+}
+
 int run_command(struct child_process *cmd)
 {
 	int code = start_command(cmd);
@@ -200,3 +204,35 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
 	cmd.env = env;
 	return run_command(&cmd);
 }
+
+int start_async(struct async *async)
+{
+	int pipe_out[2];
+
+	if (pipe(pipe_out) < 0) {
+		return error("cannot create pipe: %s", strerror(errno));
+	}
+
+	async->pid = fork();
+	if (async->pid < 0) {
+		error("fork (async) failed: %s", strerror(errno));
+		close_pair(pipe_out);
+		return -1;
+	}
+	if (!async->pid) {
+		close(pipe_out[0]);
+		exit(!!async->proc(pipe_out[1], async->data));
+	}
+	async->out = pipe_out[0];
+	close(pipe_out[1]);
+	return 0;
+}
+
+int finish_async(struct async *async)
+{
+	int ret = 0;
+
+	if (wait_or_whine(async->pid))
+		ret = error("waitpid (async) failed");
+	return ret;
+}
diff --git a/run-command.h b/run-command.h
index 35b9fb6..94e1e9d 100644
--- a/run-command.h
+++ b/run-command.h
@@ -43,4 +43,26 @@ int run_command_v_opt_cd(const char **argv, int opt, const char *dir);
  */
 int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env);
 
+/*
+ * The purpose of the following functions is to feed a pipe by running
+ * a function asynchronously and providing output that the caller reads.
+ *
+ * It is expected that no synchronization and mutual exclusion between
+ * the caller and the feed function is necessary so that the function
+ * can run in a thread without interfering with the caller.
+ */
+struct async {
+	/*
+	 * proc writes to fd and closes it;
+	 * returns 0 on success, non-zero on failure
+	 */
+	int (*proc)(int fd, void *data);
+	void *data;
+	int out;	/* caller reads from here and closes it */
+	pid_t pid;
+};
+
+int start_async(struct async *async);
+int finish_async(struct async *async);
+
 #endif
-- 
1.5.3.2.141.g48f10
Previous: Johannes SixtNext: Johannes Schindelin
Message 19 of 30 in “fork/exec removal series”
  1. 0/14 fork/exec removal seriesJohannes Sixt, Oct 13, 2007
  2. 01/14 Change git_connect() to return a struct child_process instead of a pid_t.Johannes Sixt, Oct 13, 2007
  3. 02/14 Use start_command() in git_connect() instead of explicit fork/exec.Johannes Sixt, Oct 13, 2007
  4. 03/14 Use start_command() to run content filters instead of explicit fork/exec.Johannes Sixt, Oct 13, 2007
  5. 04/14 Use run_command() to spawn external diff programs instead of fork/exec.Johannes Sixt, Oct 13, 2007
  6. 05/14 Use start_comand() in builtin-fetch-pack.c instead of explicit fork/exec.Johannes Sixt, Oct 13, 2007
  7. 06/14 Have start_command() create a pipe to read the stderr of the child.Johannes Sixt, Oct 13, 2007
  8. 07/14 upload-pack: Use start_command() to run pack-objects in create_pack_file().Johannes Sixt, Oct 13, 2007
  9. 08/14 Add infrastructure to run a function asynchronously.Johannes Sixt, Oct 13, 2007
  10. 09/14 Use the asyncronous function infrastructure in builtin-fetch-pack.c.Johannes Sixt, Oct 13, 2007
  11. 10/14 upload-pack: Move the revision walker into a separate function.Johannes Sixt, Oct 13, 2007
  12. 11/14 upload-pack: Run rev-list in an asynchronous function.Johannes Sixt, Oct 13, 2007
  13. 12/14 t0021-conversion.sh: Test that the clean filter really cleans content.Johannes Sixt, Oct 13, 2007
  14. 13/14 Avoid a dup2(2) in apply_filter() - start_command() can do it for us.Johannes Sixt, Oct 13, 2007
  15. 14/14 Use the asyncronous function infrastructure to run the content filter.Johannes Sixt, Oct 13, 2007
  16. Johannes SchindelinOct 14, 2007
  17. Johannes SixtOct 14, 2007
  18. 14/14 Use the asyncronous function infrastructure to run the content filter.Johannes Sixt, Oct 14, 2007
  19. 08/14 Add infrastructure to run a function asynchronously.Johannes Sixt, Oct 14, 2007
  20. Johannes SchindelinOct 14, 2007
  21. Johannes SixtOct 14, 2007
  22. Johannes SchindelinOct 14, 2007
  23. Shawn O. PearceOct 14, 2007
  24. Johannes SchindelinOct 14, 2007
  25. Shawn O. PearceOct 14, 2007
  26. Pierre HabouzitOct 14, 2007
  27. Pierre HabouzitOct 14, 2007
  28. Pierre HabouzitOct 14, 2007
  29. Andreas EricssonOct 14, 2007
  30. Johannes SchindelinOct 14, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.