public inbox for git@vger.kernel.org 
 help / color / mirror / Atom feed
From: Johannes Sixt <johannes.sixt@telecom•at>
To: gitster@pobox•com
Cc: git@vger•kernel.org
Subject: [PATCH amend 08/14] Add infrastructure to run a function asynchronously.
Date: Sun, 14 Oct 2007 19:08:45 +0200	[thread overview]
Message-ID: <200710141908.45779.johannes.sixt@telecom.at> (raw)
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

  parent reply	other threads:[~2007-10-14 17:09 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-10-13 20:06 [PATCH 0/14] fork/exec removal series Johannes Sixt
2007-10-13 20:06 ` [PATCH 01/14] Change git_connect() to return a struct child_process instead of a pid_t Johannes Sixt
2007-10-13 20:06   ` [PATCH 02/14] Use start_command() in git_connect() instead of explicit fork/exec Johannes Sixt
2007-10-13 20:06     ` [PATCH 03/14] Use start_command() to run content filters " Johannes Sixt
2007-10-13 20:06       ` [PATCH 04/14] Use run_command() to spawn external diff programs instead of fork/exec Johannes Sixt
2007-10-13 20:06         ` [PATCH 05/14] Use start_comand() in builtin-fetch-pack.c instead of explicit fork/exec Johannes Sixt
2007-10-13 20:06           ` [PATCH 06/14] Have start_command() create a pipe to read the stderr of the child Johannes Sixt
2007-10-13 20:06             ` [PATCH 07/14] upload-pack: Use start_command() to run pack-objects in create_pack_file() Johannes Sixt
2007-10-13 20:06               ` [PATCH 08/14] Add infrastructure to run a function asynchronously Johannes Sixt
2007-10-13 20:06                 ` [PATCH 09/14] Use the asyncronous function infrastructure in builtin-fetch-pack.c Johannes Sixt
2007-10-13 20:06                   ` [PATCH 10/14] upload-pack: Move the revision walker into a separate function Johannes Sixt
2007-10-13 20:06                     ` [PATCH 11/14] upload-pack: Run rev-list in an asynchronous function Johannes Sixt
2007-10-13 20:06                       ` [PATCH 12/14] t0021-conversion.sh: Test that the clean filter really cleans content Johannes Sixt
2007-10-13 20:06                         ` [PATCH 13/14] Avoid a dup2(2) in apply_filter() - start_command() can do it for us Johannes Sixt
2007-10-13 20:06                           ` [PATCH 14/14] Use the asyncronous function infrastructure to run the content filter Johannes Sixt
2007-10-14  3:07                             ` Johannes Schindelin
2007-10-14  9:39                               ` Johannes Sixt
2007-10-14 17:14                               ` [PATCH amend " Johannes Sixt
2007-10-14 17:08                 ` Johannes Sixt [this message]
2007-10-14  0:57   ` [PATCH 01/14] Change git_connect() to return a struct child_process instead of a pid_t Johannes Schindelin
2007-10-14  9:40     ` Johannes Sixt
2007-10-14 17:10       ` Johannes Schindelin
2007-10-14  2:11 ` [PATCH 0/14] fork/exec removal series Shawn O. Pearce
2007-10-14  2:50   ` Johannes Schindelin
2007-10-14  2:58     ` Shawn O. Pearce
2007-10-14  7:12       ` Pierre Habouzit
2007-10-14  7:17         ` Pierre Habouzit
2007-10-14  7:28           ` Pierre Habouzit
2007-10-14  9:10             ` Andreas Ericsson
2007-10-14 17:09         ` Johannes Schindelin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200710141908.45779.johannes.sixt@telecom.at \
    --to=johannes.sixt@telecom$(echo .)at \
    --cc=git@vger$(echo .)kernel.org \
    --cc=gitster@pobox$(echo .)com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox