Search code examples
c++boostsignalsboost-process

boost::process::v2 subprocess does not get a signal when calling request_exit


I have a setup where my integration test is calling up a subprocess (the actual process that should be tested).

I also want to test the de-init behaviour, so I want to gracefully close the subprocess in that test.

I spawn the subprocess with:

auto process(ctx, "process.exe", {"-f", "config.ini"});

Later on I call:

process.request_exit();
process.wait();

However, the subprocess never closes.

For simple testing I added the following signal handler for my main process:

void signal_handler(int signal_num)
{
std::exit(signal_num);
}

int main()
{
std::signal(SIGTERM, signal_handler);

...
}

I am working on a windows machine. Am I missing something?


Solution

  • First, I installed windows. Then Boost 1.86. Then I went into libs\process\test\v2 and did ..\..\..\..\b2.exe to check that the test run. They do.

    In fact the request_exit test case works as well:

    enter image description here

    So what's different about their setup?

    BOOST_AUTO_TEST_CASE(request_exit)
    {
      asio::io_context ctx;
    
      using boost::unit_test::framework::master_test_suite;
      const auto pth =  master_test_suite().argv[1];
    
    
      bpv::process proc(ctx, pth, {"sigterm"}
    #if defined(BOOST_PROCESS_V2_WINDOWS)
        , bpv::windows::show_window_minimized_not_active
        , bpv::windows::create_new_console
    #endif
        );
      BOOST_CHECK(proc.running());
      std::this_thread::sleep_for(std::chrono::milliseconds(250));
      proc.request_exit();
      proc.wait();
      BOOST_CHECK_EQUAL(proc.exit_code() & ~SIGTERM, 0);
    }
    

    Noteworthy: the process creation flags. Let's add those:

    #define _WIN32_WINNT 0x0601
    #include <boost/process/v2/process.hpp>
    #include <iostream>
    #include <thread>
    
    #if defined(BOOST_PROCESS_V2_WINDOWS)
    #include <boost/process/v2/windows/creation_flags.hpp>
    #include <boost/process/v2/windows/show_window.hpp>
    #endif
    
    using namespace std::chrono_literals;
    namespace bp = boost::process::v2;
    namespace asio = boost::asio;
    
    int main(int, char** argv) {
        static auto debug = [=](auto const&... m) {
            ((std::clog << std::setw(14) << std::quoted(argv[0]) << ": ") << ... << m) << std::endl;
        };
        debug("Working directory: ", boost::filesystem::current_path().string());
    
        debug("Starting");
        auto process = bp::process(asio::system_executor{}, "process.exe", {"-f", "config.ini"}
    #if defined(BOOST_PROCESS_V2_WINDOWS)
        , bp::windows::show_window_minimized_not_active
        , bp::windows::create_new_console
    #endif
     );
    
        debug("Started");
        std::this_thread::sleep_for(3s);
    
        debug("Requesting exit");
        process.request_exit();
    
        debug("Waiting for exit");
        process.wait();
    
        debug("Child exit: ", process.exit_code());
    }
    

    With the Process.exe vain.cpp:

    #define _WIN32_WINNT 0x0601
    #include <iostream>
    #include <iomanip>
    #include <boost/asio.hpp>
    namespace asio = boost::asio;
    
    int main(int, char** argv) {
        asio::io_context ioc(1);
        static auto debug = [=](auto const&... m) {
            ((std::clog << std::setw(14) << std::quoted(argv[0]) << ": ") << ... << m) << std::endl;
        };
        debug("Process.exe started");
    
        asio::signal_set ss(ioc, SIGTERM);
        ss.async_wait([](boost::system::error_code ec, int num) {
            debug("signal ", num, " (", ec.message(), ")");
        });
    
        ioc.run();
        debug("Process.exe exit");
    }
    

    Now it works: