From e0df94ecc789004c9d4186ecfb18fb53f8f1a99f Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Tue, 21 May 2024 09:48:50 -0700 Subject: [PATCH] perf: Use posix_spawn for executing compiler check command (#1451) --- cmake/GenerateConfigurationFile.cmake | 1 + cmake/config.h.in | 3 + src/ccache/hashutil.cpp | 87 ++++++++++++++++----------- 3 files changed, 57 insertions(+), 34 deletions(-) diff --git a/cmake/GenerateConfigurationFile.cmake b/cmake/GenerateConfigurationFile.cmake index a3d24cb7..bf2cd5a5 100644 --- a/cmake/GenerateConfigurationFile.cmake +++ b/cmake/GenerateConfigurationFile.cmake @@ -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 diff --git a/cmake/config.h.in b/cmake/config.h.in index 24f2038f..f39a18fc 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -81,6 +81,9 @@ // Define if you have the header file. #cmakedefine HAVE_PWD_H +// Define if you have the header file. +#cmakedefine HAVE_SPAWN_H + // Define if you have the header file. #cmakedefine HAVE_SYS_CLONEFILE_H diff --git a/src/ccache/hashutil.cpp b/src/ccache/hashutil.cpp index e5c9a248..c5a4d57b 100644 --- a/src/ccache/hashutil.cpp +++ b/src/ccache/hashutil.cpp @@ -37,6 +37,10 @@ # include "InodeCache.hpp" #endif +#ifdef HAVE_SPAWN_H +# include +#endif + #ifdef HAVE_UNISTD_H # include #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(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(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 } -- 2.47.2