Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
process.cpp
Go to the documentation of this file.
2#include <fc/io/iostream.hpp>
4#include <fc/asio.hpp>
5#include <fc/filesystem.hpp>
6#include <fc/log/logger.hpp>
7#include <boost/process/all.hpp>
8#include <boost/iostreams/stream.hpp>
9#include <cstdlib>
10
11namespace fc {
12 namespace bp = boost::process;
13 namespace io = boost::iostreams;
14
16 try {
17 return fc::string(bp::find_executable_in_path( std::string(name), "" ));
18 } catch (...) {
19 const char* p = std::getenv("PATH");
20 FC_THROW( "Unable to find executable ${exe} in path.",
21 ("exe", name)
22 ("inner", fc::except_str() )
23 ("PATH", fc::string(p!=nullptr?p:"") ) );
24 }
25 return fc::path();
26}
27
28
30{
31 public:
33 :stat( fc::asio::default_io_service() ){}
34
36 {
37 try
38 {
39 if( _in )
40 {
41 _in->close();
42 }
43 if( _exited.valid() && !_exited.ready())
44 {
45 //child->terminate();
46 _exited.wait();
47 }
48 }
49 catch(...)
50 {
51 wlog( "caught exception cleaning up process: ${except_str}", ("except_str",fc::except_str()) );
52 }
53 }
54
55 std::shared_ptr<bp::child> child;
56
57 std::shared_ptr<bp::pipe> _inp;
58 std::shared_ptr<bp::pipe> _outp;
59 std::shared_ptr<bp::pipe> _errp;
60
64
65 bp::status stat;
66 bp::context pctx;
67
68 fc::future<int> _exited;
69};
70
72:my( new process::impl() ){}
74
76 std::vector<std::string> args,
77 const fc::path& work_dir, int opt )
78{
79
80 my->pctx.work_dir = work_dir.string();
81 my->pctx.suppress_console = (opt & suppress_console) != 0;
82
83 if( opt&open_stdout)
84 my->pctx.streams[boost::process::stdout_id] = bp::behavior::async_pipe();
85 else
86 my->pctx.streams[boost::process::stdout_id] = bp::behavior::null();
87
88
89 if( opt& open_stderr )
90 my->pctx.streams[boost::process::stderr_id] = bp::behavior::async_pipe();
91 else
92 my->pctx.streams[boost::process::stderr_id] = bp::behavior::null();
93
94 if( opt& open_stdin )
95 my->pctx.streams[boost::process::stdin_id] = bp::behavior::async_pipe();
96 else
97 my->pctx.streams[boost::process::stdin_id] = bp::behavior::close();
98
99 /*
100 std::vector<std::string> a;
101 a.reserve(size_t(args.size()));
102 for( uint32_t i = 0; i < args.size(); ++i ) {
103 a.push_back( fc::move(args[i]) );
104 }
105 */
106 my->child.reset( new bp::child( bp::create_child( exe.string(), fc::move(args), my->pctx ) ) );
107
108 if( opt & open_stdout ) {
109 bp::handle outh = my->child->get_handle( bp::stdout_id );
110 my->_outp.reset( new bp::pipe( fc::asio::default_io_service(), outh.release() ) );
111 }
112 if( opt & open_stderr ) {
113 bp::handle errh = my->child->get_handle( bp::stderr_id );
114 my->_errp.reset( new bp::pipe( fc::asio::default_io_service(), errh.release() ) );
115 }
116 if( opt & open_stdin ) {
117 bp::handle inh = my->child->get_handle( bp::stdin_id );
118 my->_inp.reset( new bp::pipe( fc::asio::default_io_service(), inh.release() ) );
119 }
120
121
122 promise<int>::ptr p(new promise<int>("process"));
123 my->stat.async_wait( my->child->get_id(), [=]( const boost::system::error_code& ec, int exit_code )
124 {
125 //slog( "process::result %d", exit_code );
126 if( !ec ) {
127 #ifdef BOOST_POSIX_API
128 if( WIFEXITED(exit_code) ) p->set_value( WEXITSTATUS(exit_code) );
129 else
130 {
131 p->set_exception(
132 fc::exception_ptr( new fc::exception(
133 FC_LOG_MESSAGE( error, "process exited with: ${message} ",
134 ("message", strsignal(WTERMSIG(exit_code))) ) ) ) );
135 }
136 #else
137 p->set_value(exit_code);
138 #endif
139 }
140 else
141 {
142 p->set_exception(
143 fc::exception_ptr( new fc::exception(
144 FC_LOG_MESSAGE( error, "process exited with: ${message} ",
145 ("message", boost::system::system_error(ec).what())) ) ) );
146 }
147 });
148 if( opt & open_stdin )
149 my->_in = std::make_shared<buffered_ostream>(std::make_shared<fc::asio::ostream<bp::pipe>>(my->_inp));
150 if( opt & open_stdout )
151 my->_out = std::make_shared<buffered_istream>(std::make_shared<fc::asio::istream<bp::pipe>>(my->_outp));
152 if( opt & open_stderr )
153 my->_err = std::make_shared<buffered_istream>(std::make_shared<fc::asio::istream<bp::pipe>>(my->_errp));
154 my->_exited = p;
155 return *this;
156}
157
161void process::kill() {
162 my->child->terminate();
163}
164
168fc::buffered_ostream_ptr process::in_stream() {
169 return my->_in;
170}
171
175fc::buffered_istream_ptr process::out_stream() {
176 return my->_out;
177}
181fc::buffered_istream_ptr process::err_stream() {
182 return my->_err;
183}
184
185int process::result(const microseconds& timeout /* = microseconds::maximum() */)
186{
187 return my->_exited.wait(timeout);
188}
189
190}
const mie::Vuint & p
Definition bn.cpp:27
std::string name
abstract interface for interacting with external processes
Definition iprocess.hpp:17
wraps boost::filesystem::path to provide platform independent path manipulation.
std::string string() const
buffered_istream_ptr _out
Definition process.cpp:61
bp::context pctx
Definition process.cpp:66
std::shared_ptr< bp::pipe > _outp
Definition process.cpp:58
fc::future< int > _exited
Definition process.cpp:68
std::shared_ptr< bp::pipe > _inp
Definition process.cpp:57
std::shared_ptr< bp::pipe > _errp
Definition process.cpp:59
bp::status stat
Definition process.cpp:65
buffered_istream_ptr _err
Definition process.cpp:62
buffered_ostream_ptr _in
Definition process.cpp:63
std::shared_ptr< bp::child > child
Definition process.cpp:55
start and manage an local process
Definition process.hpp:13
virtual iprocess & exec(const fc::path &exe, std::vector< std::string > args, const fc::path &work_dir=fc::path(), int opts=open_all)
Definition process.cpp:75
#define FC_THROW( ...)
#define wlog(FORMAT,...)
Definition logger.hpp:124
static const Reg16 bp(Operand::BP)
namespace sysio::chain
Definition authority.cpp:3
std::string string
Definition string.hpp:10
std::shared_ptr< buffered_istream > buffered_istream_ptr
std::string except_str()
std::shared_ptr< buffered_ostream > buffered_ostream_ptr
fc::path find_executable_in_path(const fc::string name)
Definition process.cpp:15