tools subcmd: Add check_if_command_finished()

Add non-blocking function to check if a 'struct child_process' has
completed. If the process has completed the exit code is stored in the
'struct child_process' so that finish_command() returns it.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20240405070931.1231245-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Ian Rogers 2024-04-05 00:09:30 -07:00 committed by Arnaldo Carvalho de Melo
parent 8c004c7a60
commit 705c09bb3c
2 changed files with 49 additions and 24 deletions

View file

@ -165,43 +165,65 @@ int start_command(struct child_process *cmd)
return 0;
}
static int wait_or_whine(pid_t pid)
static int wait_or_whine(struct child_process *cmd, bool block)
{
char sbuf[STRERR_BUFSIZE];
bool finished = cmd->finished;
int result = cmd->finish_result;
for (;;) {
while (!finished) {
int status, code;
pid_t waiting = waitpid(pid, &status, 0);
pid_t waiting = waitpid(cmd->pid, &status, block ? 0 : WNOHANG);
if (!block && waiting == 0)
break;
if (waiting < 0 && errno == EINTR)
continue;
finished = true;
if (waiting < 0) {
if (errno == EINTR)
continue;
char sbuf[STRERR_BUFSIZE];
fprintf(stderr, " Error: waitpid failed (%s)",
str_error_r(errno, sbuf, sizeof(sbuf)));
return -ERR_RUN_COMMAND_WAITPID;
}
if (waiting != pid)
return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
if (WIFSIGNALED(status))
return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
if (!WIFEXITED(status))
return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
code = WEXITSTATUS(status);
switch (code) {
case 127:
return -ERR_RUN_COMMAND_EXEC;
case 0:
return 0;
default:
return -code;
result = -ERR_RUN_COMMAND_WAITPID;
} else if (waiting != cmd->pid) {
result = -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
} else if (WIFSIGNALED(status)) {
result = -ERR_RUN_COMMAND_WAITPID_SIGNAL;
} else if (!WIFEXITED(status)) {
result = -ERR_RUN_COMMAND_WAITPID_NOEXIT;
} else {
code = WEXITSTATUS(status);
switch (code) {
case 127:
result = -ERR_RUN_COMMAND_EXEC;
break;
case 0:
result = 0;
break;
default:
result = -code;
break;
}
}
}
if (finished) {
cmd->finished = 1;
cmd->finish_result = result;
}
return result;
}
int check_if_command_finished(struct child_process *cmd)
{
wait_or_whine(cmd, /*block=*/false);
return cmd->finished;
}
int finish_command(struct child_process *cmd)
{
return wait_or_whine(cmd->pid);
return wait_or_whine(cmd, /*block=*/true);
}
int run_command(struct child_process *cmd)

View file

@ -41,17 +41,20 @@ struct child_process {
int err;
const char *dir;
const char *const *env;
int finish_result;
unsigned no_stdin:1;
unsigned no_stdout:1;
unsigned no_stderr:1;
unsigned exec_cmd:1; /* if this is to be external sub-command */
unsigned stdout_to_stderr:1;
unsigned finished:1;
void (*preexec_cb)(void);
/* If set, call function in child rather than doing an exec. */
int (*no_exec_cmd)(struct child_process *process);
};
int start_command(struct child_process *);
int check_if_command_finished(struct child_process *);
int finish_command(struct child_process *);
int run_command(struct child_process *);