1 // Copyright (c) 2016 Klemens D. Morgenstern 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #ifndef BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_ 7 #define BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_ 8 9 #include <boost/process/detail/posix/handler.hpp> 10 #include <boost/process/detail/posix/async_handler.hpp> 11 #include <boost/asio/io_context.hpp> 12 13 #include <boost/fusion/algorithm/iteration/for_each.hpp> 14 #include <boost/fusion/algorithm/transformation/filter_if.hpp> 15 #include <boost/fusion/algorithm/transformation/transform.hpp> 16 #include <boost/fusion/view/transform_view.hpp> 17 #include <boost/fusion/container/vector/convert.hpp> 18 19 20 #include <boost/process/detail/posix/sigchld_service.hpp> 21 #include <boost/process/detail/posix/is_running.hpp> 22 23 #include <functional> 24 #include <type_traits> 25 #include <memory> 26 #include <vector> 27 #include <sys/wait.h> 28 29 namespace boost { namespace process { namespace detail { namespace posix { 30 31 template<typename Executor> 32 struct on_exit_handler_transformer 33 { 34 Executor & exec; on_exit_handler_transformerboost::process::detail::posix::on_exit_handler_transformer35 on_exit_handler_transformer(Executor & exec) : exec(exec) {} 36 template<typename Sig> 37 struct result; 38 39 template<typename T> 40 struct result<on_exit_handler_transformer<Executor>(T&)> 41 { 42 typedef typename T::on_exit_handler_t type; 43 }; 44 45 template<typename T> operator ()boost::process::detail::posix::on_exit_handler_transformer46 auto operator()(T& t) const -> typename T::on_exit_handler_t 47 { 48 return t.on_exit_handler(exec); 49 } 50 }; 51 52 template<typename Executor> 53 struct async_handler_collector 54 { 55 Executor & exec; 56 std::vector<std::function<void(int, const std::error_code & ec)>> &handlers; 57 58 async_handler_collectorboost::process::detail::posix::async_handler_collector59 async_handler_collector(Executor & exec, 60 std::vector<std::function<void(int, const std::error_code & ec)>> &handlers) 61 : exec(exec), handlers(handlers) {} 62 63 template<typename T> operator ()boost::process::detail::posix::async_handler_collector64 void operator()(T & t) const 65 { 66 handlers.push_back(t.on_exit_handler(exec)); 67 } 68 }; 69 70 //Also set's up waiting for the exit, so it can close async stuff. 71 struct io_context_ref : handler_base_ext 72 { io_context_refboost::process::detail::posix::io_context_ref73 io_context_ref(boost::asio::io_context & ios) : ios(ios) 74 { 75 76 } getboost::process::detail::posix::io_context_ref77 boost::asio::io_context &get() {return ios;}; 78 79 template <class Executor> on_successboost::process::detail::posix::io_context_ref80 void on_success(Executor& exec) 81 { 82 ios.notify_fork(boost::asio::io_context::fork_parent); 83 //must be on the heap so I can move it into the lambda. 84 auto asyncs = boost::fusion::filter_if< 85 is_async_handler< 86 typename std::remove_reference< boost::mpl::_ > ::type 87 >>(exec.seq); 88 89 //ok, check if there are actually any. 90 if (boost::fusion::empty(asyncs)) 91 return; 92 93 std::vector<std::function<void(int, const std::error_code & ec)>> funcs; 94 funcs.reserve(boost::fusion::size(asyncs)); 95 boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs)); 96 97 auto & es = exec.exit_status; 98 99 auto wh = [funcs, es](int val, const std::error_code & ec) 100 { 101 es->store(val); 102 for (auto & func : funcs) 103 func(::boost::process::detail::posix::eval_exit_status(val), ec); 104 }; 105 106 sigchld_service.async_wait(exec.pid, std::move(wh)); 107 } 108 109 template<typename Executor> on_setupboost::process::detail::posix::io_context_ref110 void on_setup (Executor &) const {/*ios.notify_fork(boost::asio::io_context::fork_prepare);*/} 111 112 template<typename Executor> on_exec_setupboost::process::detail::posix::io_context_ref113 void on_exec_setup (Executor &) const {/*ios.notify_fork(boost::asio::io_context::fork_child);*/} 114 115 template <class Executor> on_errorboost::process::detail::posix::io_context_ref116 void on_error(Executor&, const std::error_code &) const {/*ios.notify_fork(boost::asio::io_context::fork_parent);*/} 117 118 private: 119 boost::asio::io_context &ios; 120 boost::process::detail::posix::sigchld_service &sigchld_service = boost::asio::use_service<boost::process::detail::posix::sigchld_service>(ios); 121 }; 122 123 }}}} 124 125 #endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */ 126