1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-17 07:11:52 +08:00

instrumentation: Add file lock for build daemon

Prevent starting instrumentation build daemon and related hooks if one is
already running, and when during `cmake --build`.
This commit is contained in:
Martin Duffy
2025-08-05 14:01:55 -04:00
parent 9b65be6da5
commit a249e820a8
7 changed files with 50 additions and 2 deletions

View File

@@ -197,7 +197,8 @@ key is required, but all other fields are optional.
* ``postTest``
``preBuild`` and ``postBuild`` are not supported with the
:generator:`MSYS Makefiles` generator.
:generator:`MSYS Makefiles` generator. Additionally, they will not be
triggered when the build tool is invoked by ``cmake --build``.
``options``
A list of strings used to enable certain optional behavior, including the

View File

@@ -19,6 +19,8 @@
#include "cmCryptoHash.h"
#include "cmExperimental.h"
#include "cmFileLock.h"
#include "cmFileLockResult.h"
#include "cmInstrumentationQuery.h"
#include "cmJSONState.h"
#include "cmStringAlgorithms.h"
@@ -626,7 +628,11 @@ int cmInstrumentation::SpawnBuildDaemon()
uv_disable_stdio_inheritance();
// preBuild Hook
this->CollectTimingData(cmInstrumentationQuery::Hook::PreBuild);
if (this->LockBuildDaemon()) {
// Release lock before spawning the build daemon, to prevent blocking it.
this->lock.Release();
this->CollectTimingData(cmInstrumentationQuery::Hook::PreBuild);
}
// postBuild Hook
if (this->HasHook(cmInstrumentationQuery::Hook::PostBuild)) {
@@ -645,6 +651,16 @@ int cmInstrumentation::SpawnBuildDaemon()
return 0;
}
// Prevent multiple build daemons from running simultaneously
bool cmInstrumentation::LockBuildDaemon()
{
std::string const lockFile = cmStrCat(this->timingDirv1, "/.build.lock");
if (!cmSystemTools::FileExists(lockFile)) {
cmSystemTools::Touch(lockFile, true);
}
return this->lock.Lock(lockFile, 0).IsOk();
}
/*
* Always called by ctest --wait-and-collect-instrumentation in a detached
* process. Waits for the given PID to end before running the postBuild hook.
@@ -653,6 +669,11 @@ int cmInstrumentation::SpawnBuildDaemon()
*/
int cmInstrumentation::CollectTimingAfterBuild(int ppid)
{
// Check if another process is already instrumenting the build.
// This lock will be released when the process exits at the end of the build.
if (!this->LockBuildDaemon()) {
return 0;
}
std::function<int()> waitForBuild = [ppid]() -> int {
while (0 == uv_kill(ppid, 0)) {
cmSystemTools::Delay(100);

View File

@@ -15,6 +15,8 @@
#include <cm/optional>
#include <cm3p/json/value.h>
#include "cmFileLock.h"
#ifndef CMAKE_BOOTSTRAP
# include <cmsys/SystemInformation.hxx>
#endif
@@ -61,6 +63,7 @@ public:
void ClearGeneratedQueries();
int CollectTimingData(cmInstrumentationQuery::Hook hook);
int SpawnBuildDaemon();
bool LockBuildDaemon();
int CollectTimingAfterBuild(int ppid);
void AddHook(cmInstrumentationQuery::Hook hook);
void AddOption(cmInstrumentationQuery::Option option);
@@ -103,4 +106,5 @@ private:
cmsys::SystemInformation& GetSystemInformation();
#endif
int writtenJsonQueries = 0;
cmFileLock lock;
};

View File

@@ -4041,6 +4041,9 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
};
#if !defined(CMAKE_BOOTSTRAP)
// Block the instrumentation build daemon from spawning during this build.
// This lock will be released when the process exits at the end of the build.
instrumentation.LockBuildDaemon();
int buildresult =
instrumentation.InstrumentCommand("cmakeBuild", args, doBuild);
instrumentation.CollectTimingData(

View File

@@ -67,6 +67,8 @@ function(instrument test)
endif()
if (ARGS_BUILD_MAKE_PROGRAM)
set(RunCMake_TEST_OUTPUT_MERGE 1)
# Force reconfigure to test for double preBuild & postBuild hooks
file(TOUCH ${RunCMake_TEST_BINARY_DIR}/CMakeCache.txt)
run_cmake_command(${test}-make-program ${RunCMake_MAKE_PROGRAM})
unset(RunCMake_TEST_OUTPUT_MERGE)
endif()
@@ -128,6 +130,10 @@ instrument(cmake-command-resets-generated NO_WARN
COPY_QUERIES_GENERATED
CHECK_SCRIPT check-data-dir.cmake
)
instrument(cmake-command-cmake-build NO_WARN
BUILD
CHECK_SCRIPT check-no-make-program-hooks.cmake
)
if(RunCMake_GENERATOR STREQUAL "MSYS Makefiles")
# FIXME(#27079): This does not work for MSYS Makefiles.

View File

@@ -0,0 +1,6 @@
if (EXISTS ${v1}/preBuild.hook OR EXISTS ${v1}/postBuild.hook)
set(RunCMake_TEST_FAILED "Got unexpected preBuild/postBuild hooks.")
endif()
if (NOT EXISTS ${v1}/postCMakeBuild.hook)
set(RunCMake_TEST_FAILED "Missing expected postCMakeBuild hook.")
endif()

View File

@@ -0,0 +1,7 @@
file(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}/../hook.cmake" hook_path)
cmake_instrumentation(
API_VERSION 1
DATA_VERSION 1
HOOKS preBuild postBuild postCMakeBuild
CALLBACK ${CMAKE_COMMAND} -P ${hook_path} 0
)