// Copyright (c) 2006, 2007 Julio M. Merino Vidal // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling // Copyright (c) 2009 Boris Schaeling // Copyright (c) 2010 Felipe Tanus, Boris Schaeling // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling // Copyright (c) 2016 Klemens D. Morgenstern // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) /** * \file boost/process/async_system.hpp * * Defines the asynchronous version of the system function. */ #ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP #define BOOST_PROCESS_ASYNC_SYSTEM_HPP #include #include #include #include #include #include #include #include #include #include #include #if defined(BOOST_POSIX_API) #include #endif namespace boost { namespace process { namespace detail { template struct async_system_handler : ::boost::process::detail::api::async_handler { boost::asio::io_context & ios; Handler handler; #if defined(BOOST_POSIX_API) bool errored = false; #endif template async_system_handler( boost::asio::io_context & ios, ExitHandler_ && exit_handler) : ios(ios), handler(std::forward(exit_handler)) { } template void on_error(Exec&, const std::error_code & ec) { #if defined(BOOST_POSIX_API) errored = true; #endif auto h = std::make_shared(std::move(handler)); boost::asio::post( ios.get_executor(), [h, ec]() mutable { (*h)(boost::system::error_code(ec.value(), boost::system::system_category()), -1); }); } template std::function on_exit_handler(Executor&) { #if defined(BOOST_POSIX_API) if (errored) return [](int , const std::error_code &){}; #endif auto h = std::make_shared(std::move(handler)); return [h](int exit_code, const std::error_code & ec) mutable { (*h)(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code); }; } }; template struct is_error_handler> : std::true_type {}; } /** This function provides an asynchronous interface to process launching. It uses the same properties and parameters as the other launching function, but is similar to the asynchronous functions in [boost.asio](http://www.boost.org/doc/libs/release/doc/html/boost_asio.html) It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine the return value (from the second parameter, `exit_handler`). \param ios A reference to an [io_context](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html) \param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)` \note This function does not allow custom error handling, since those are done through the `exit_handler`. */ #if defined(BOOST_PROCESS_DOXYGEN) template inline boost::process::detail::dummy async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args); #endif namespace detail { struct async_system_init_op { template void operator()(Handler && handler, asio::io_context & ios, Args && ... args) { detail::async_system_handler::type> async_h{ios, std::forward(handler)}; child(ios, std::forward(args)..., async_h ).detach(); } }; } template inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int)) async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args) { typedef typename ::boost::process::detail::has_error_handler>::type has_err_handling; static_assert(!has_err_handling::value, "async_system cannot have custom error handling"); return boost::asio::async_initiate( detail::async_system_init_op{}, exit_handler, ios, std::forward(args)... ); } }} #endif