tools subcmd: Add check_if_command_finished()
authorIan Rogers <irogers@google.com>
Fri, 5 Apr 2024 07:09:30 +0000 (00:09 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 8 Apr 2024 20:43:20 +0000 (17:43 -0300)
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>
tools/lib/subcmd/run-command.c
tools/lib/subcmd/run-command.h

index d435eb42354bfe263e57cdce0fa8ecc4b9a7729b..4e3a557a2f3741229450b5249f9be623333352ca 100644 (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)
index d794138a797f4aec5929a967c1526cded56fc665..b2d39de6e690b5e2d81a9a6501d9bbd263a1691d 100644 (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 *);