Add infrastructure to run a function asynchronously.
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. [sp: Style nit fixed by removing unnecessary block on if condition inside of start_async()] Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
parent
cc41fa8da9
commit
2d22c20830
@ -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,34 @@ 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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user