mirror of
https://github.com/microsoft/vcpkg.git
synced 2025-06-07 01:23:35 +08:00
Merge pull request #10372 from ras0219-msft/dev/roschuma/jobs
[vcpkg] Introduce Job Objects to improve ctrl-c performance on Windows
This commit is contained in:
commit
8b201cb43c
@ -61,4 +61,9 @@ namespace vcpkg::System
|
|||||||
std::function<void(StringView)> data_cb,
|
std::function<void(StringView)> data_cb,
|
||||||
const Environment& env = {});
|
const Environment& env = {});
|
||||||
void register_console_ctrl_handler();
|
void register_console_ctrl_handler();
|
||||||
|
#if defined(_WIN32)
|
||||||
|
void initialize_global_job_object();
|
||||||
|
void enter_interactive_subprocess();
|
||||||
|
void exit_interactive_subprocess();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -269,7 +269,7 @@ int wmain(int, const wchar_t* const* const);
|
|||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
int main(int argc, const char* const* const /*argv*/)
|
int main(int argc, const char* const* const /*argv*/)
|
||||||
{
|
{
|
||||||
wchar_t **wargv;
|
wchar_t** wargv;
|
||||||
wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||||
return wmain(argc, wargv);
|
return wmain(argc, wargv);
|
||||||
}
|
}
|
||||||
@ -292,6 +292,7 @@ int main(const int argc, const char* const* const argv)
|
|||||||
SetConsoleCP(CP_UTF8);
|
SetConsoleCP(CP_UTF8);
|
||||||
SetConsoleOutputCP(CP_UTF8);
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
|
|
||||||
|
System::initialize_global_job_object();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Checks::register_global_shutdown_handler([]() {
|
Checks::register_global_shutdown_handler([]() {
|
||||||
|
@ -30,7 +30,7 @@ namespace vcpkg
|
|||||||
{
|
{
|
||||||
struct CtrlCStateMachine
|
struct CtrlCStateMachine
|
||||||
{
|
{
|
||||||
CtrlCStateMachine() : m_number_of_external_processes(0) {}
|
CtrlCStateMachine() : m_number_of_external_processes(0), m_global_job(NULL), m_in_interactive(0) {}
|
||||||
|
|
||||||
void transition_to_spawn_process() noexcept
|
void transition_to_spawn_process() noexcept
|
||||||
{
|
{
|
||||||
@ -91,17 +91,47 @@ namespace vcpkg
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We are currently blocked on a child process. Upon return, transition_from_spawn_process()
|
// We are currently blocked on a child process.
|
||||||
// will be called and exit.
|
// If none of the child processes are interactive, use the Job Object to terminate the tree.
|
||||||
|
if (m_in_interactive.load() == 0)
|
||||||
|
{
|
||||||
|
auto job = m_global_job.exchange(NULL);
|
||||||
|
if (job != NULL)
|
||||||
|
{
|
||||||
|
::CloseHandle(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initialize_job()
|
||||||
|
{
|
||||||
|
m_global_job = CreateJobObjectW(NULL, NULL);
|
||||||
|
if (m_global_job != NULL)
|
||||||
|
{
|
||||||
|
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info = {};
|
||||||
|
info.BasicLimitInformation.LimitFlags =
|
||||||
|
JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||||
|
::SetInformationJobObject(m_global_job, JobObjectExtendedLimitInformation, &info, sizeof(info));
|
||||||
|
::AssignProcessToJobObject(m_global_job, ::GetCurrentProcess());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enter_interactive() { ++m_in_interactive; }
|
||||||
|
void exit_interactive() { --m_in_interactive; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<int> m_number_of_external_processes;
|
std::atomic<int> m_number_of_external_processes;
|
||||||
|
std::atomic<HANDLE> m_global_job;
|
||||||
|
std::atomic<int> m_in_interactive;
|
||||||
};
|
};
|
||||||
|
|
||||||
static CtrlCStateMachine g_ctrl_c_state;
|
static CtrlCStateMachine g_ctrl_c_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::initialize_global_job_object() { g_ctrl_c_state.initialize_job(); }
|
||||||
|
void System::enter_interactive_subprocess() { g_ctrl_c_state.enter_interactive(); }
|
||||||
|
void System::exit_interactive_subprocess() { g_ctrl_c_state.exit_interactive(); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fs::path System::get_exe_path_of_current_process()
|
fs::path System::get_exe_path_of_current_process()
|
||||||
@ -428,7 +458,7 @@ namespace vcpkg
|
|||||||
{
|
{
|
||||||
auto timer = Chrono::ElapsedTimer::create_started();
|
auto timer = Chrono::ElapsedTimer::create_started();
|
||||||
|
|
||||||
auto process_info = windows_create_process(cmd_line, {}, DETACHED_PROCESS);
|
auto process_info = windows_create_process(cmd_line, {}, DETACHED_PROCESS | CREATE_BREAKAWAY_FROM_JOB);
|
||||||
if (auto p = process_info.get())
|
if (auto p = process_info.get())
|
||||||
{
|
{
|
||||||
p->close_handles();
|
p->close_handles();
|
||||||
|
@ -48,7 +48,7 @@ namespace vcpkg::Commands::Env
|
|||||||
const Build::PreBuildInfo pre_build_info(
|
const Build::PreBuildInfo pre_build_info(
|
||||||
paths, triplet, var_provider.get_generic_triplet_vars(triplet).value_or_exit(VCPKG_LINE_INFO));
|
paths, triplet, var_provider.get_generic_triplet_vars(triplet).value_or_exit(VCPKG_LINE_INFO));
|
||||||
const Toolset& toolset = paths.get_toolset(pre_build_info);
|
const Toolset& toolset = paths.get_toolset(pre_build_info);
|
||||||
auto env_cmd = Build::make_build_env_cmd(pre_build_info, toolset);
|
auto build_env_cmd = Build::make_build_env_cmd(pre_build_info, toolset);
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> extra_env = {};
|
std::unordered_map<std::string, std::string> extra_env = {};
|
||||||
const bool add_bin = Util::Sets::contains(options.switches, OPTION_BIN);
|
const bool add_bin = Util::Sets::contains(options.switches, OPTION_BIN);
|
||||||
@ -74,12 +74,29 @@ namespace vcpkg::Commands::Env
|
|||||||
if (add_python) extra_env.emplace("PYTHONPATH", (paths.installed / triplet.to_string() / "python").u8string());
|
if (add_python) extra_env.emplace("PYTHONPATH", (paths.installed / triplet.to_string() / "python").u8string());
|
||||||
if (path_vars.size() > 0) extra_env.emplace("PATH", Strings::join(";", path_vars));
|
if (path_vars.size() > 0) extra_env.emplace("PATH", Strings::join(";", path_vars));
|
||||||
|
|
||||||
std::string env_cmd_prefix = env_cmd.empty() ? "" : Strings::format("%s && ", env_cmd);
|
auto env = [&] {
|
||||||
std::string env_cmd_suffix =
|
auto clean_env = System::get_modified_clean_environment(extra_env);
|
||||||
args.command_arguments.empty() ? "cmd" : Strings::format("cmd /c %s", args.command_arguments.at(0));
|
if (build_env_cmd.empty())
|
||||||
|
return clean_env;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return System::cmd_execute_modify_env(build_env_cmd, clean_env);
|
||||||
|
#else
|
||||||
|
Checks::exit_with_message(VCPKG_LINE_INFO,
|
||||||
|
"Build environment commands are not supported on this platform");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
const std::string cmd = Strings::format("%s%s", env_cmd_prefix, env_cmd_suffix);
|
std::string cmd = args.command_arguments.empty() ? "cmd" : ("cmd /c " + args.command_arguments.at(0));
|
||||||
System::cmd_execute(cmd, System::get_modified_clean_environment(extra_env));
|
#ifdef _WIN32
|
||||||
Checks::exit_success(VCPKG_LINE_INFO);
|
System::enter_interactive_subprocess();
|
||||||
|
#endif
|
||||||
|
auto rc = System::cmd_execute(cmd, env);
|
||||||
|
#ifdef _WIN32
|
||||||
|
System::exit_interactive_subprocess();
|
||||||
|
#endif
|
||||||
|
Checks::exit_with_code(VCPKG_LINE_INFO, rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user