]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
perf: Use posix_spawn for executing compiler check command (#1451)
authorBrendan Shanks <mrpippy@gmail.com>
Tue, 21 May 2024 16:48:50 +0000 (09:48 -0700)
committerGitHub <noreply@github.com>
Tue, 21 May 2024 16:48:50 +0000 (18:48 +0200)
cmake/GenerateConfigurationFile.cmake
cmake/config.h.in
src/ccache/hashutil.cpp

index a3d24cb7fd71d6a0be4a5f08fa343e899ebb835b..bf2cd5a5555b10e6108539198866db95187536b2 100644 (file)
@@ -4,6 +4,7 @@ set(include_files
     dirent.h
     linux/fs.h
     pwd.h
+    spawn.h
     sys/clonefile.h
     sys/file.h
     sys/ioctl.h
index 24f2038f21072c3421f475b52babad52a97ef8cd..f39a18fc1b42dd095336da037ad751b741a5aae8 100644 (file)
@@ -81,6 +81,9 @@
 // Define if you have the <pwd.h> header file.
 #cmakedefine HAVE_PWD_H
 
+// Define if you have the <spawn.h> header file.
+#cmakedefine HAVE_SPAWN_H
+
 // Define if you have the <sys/clonefile.h> header file.
 #cmakedefine HAVE_SYS_CLONEFILE_H
 
index e5c9a2489a8c6d2a9a6eb90c3efbd35753c693f4..c5a4d57b9aa848263570c5f4c1fa92f73be3d8c7 100644 (file)
 #  include "InodeCache.hpp"
 #endif
 
+#ifdef HAVE_SPAWN_H
+#  include <spawn.h>
+#endif
+
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
@@ -440,44 +444,59 @@ hash_command_output(Hash& hash,
     throw core::Fatal(FMT("pipe failed: {}", strerror(errno)));
   }
 
-  pid_t pid = fork();
-  if (pid == -1) {
-    throw core::Fatal(FMT("fork failed: {}", strerror(errno)));
+  int result;
+  posix_spawn_file_actions_t file_actions;
+  if ((result = posix_spawn_file_actions_init(&file_actions))) {
+    throw core::Fatal(
+      FMT("posix_spawn_file_actions_init failed: {}", strerror(result)));
   }
 
-  if (pid == 0) {
-    // Child.
-    close(pipefd[0]);
-    close(0);
-    dup2(pipefd[1], 1);
-    dup2(pipefd[1], 2);
-    _exit(execvp(argv[0], const_cast<char* const*>(argv.data())));
-    // Never reached.
-  } else {
-    // Parent.
-    close(pipefd[1]);
-    const auto hash_result = hash.hash_fd(pipefd[0]);
-    if (!hash_result) {
-      LOG("Error hashing compiler check command output: {}",
-          hash_result.error());
-    }
-    close(pipefd[0]);
-
-    int status;
-    int result;
-    while ((result = waitpid(pid, &status, 0)) != pid) {
-      if (result == -1 && errno == EINTR) {
-        continue;
-      }
-      LOG("waitpid failed: {}", strerror(errno));
-      return false;
-    }
-    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-      LOG("Compiler check command returned {}", WEXITSTATUS(status));
-      return false;
+  if ((result = posix_spawn_file_actions_addclose(&file_actions, pipefd[0]))
+      || (result = posix_spawn_file_actions_addclose(&file_actions, 0))
+      || (result =
+            posix_spawn_file_actions_adddup2(&file_actions, pipefd[1], 1))
+      || (result =
+            posix_spawn_file_actions_adddup2(&file_actions, pipefd[1], 2))) {
+    throw core::Fatal(FMT("posix_spawn_file_actions_addclose/dup2 failed: {}",
+                          strerror(result)));
+  }
+
+  pid_t pid;
+  extern char** environ;
+  result = posix_spawnp(&pid,
+                        argv[0],
+                        &file_actions,
+                        nullptr,
+                        const_cast<char* const*>(argv.data()),
+                        environ);
+
+  posix_spawn_file_actions_destroy(&file_actions);
+  close(pipefd[1]);
+
+  const auto hash_result = hash.hash_fd(pipefd[0]);
+  if (!hash_result) {
+    LOG("Error hashing compiler check command output: {}", hash_result.error());
+  }
+  close(pipefd[0]);
+
+  if (result) {
+    LOG("posix_spawnp failed: {}", strerror(errno));
+    return false;
+  }
+
+  int status;
+  while ((result = waitpid(pid, &status, 0)) != pid) {
+    if (result == -1 && errno == EINTR) {
+      continue;
     }
-    return bool(hash_result);
+    LOG("waitpid failed: {}", strerror(errno));
+    return false;
+  }
+  if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+    LOG("Compiler check command returned {}", WEXITSTATUS(status));
+    return false;
   }
+  return bool(hash_result);
 #endif
 }