File indexing completed on 2025-01-18 09:50:05
0001
0002
0003
0004
0005
0006 #ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
0007 #define BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
0008
0009
0010 #include <boost/process/detail/posix/basic_pipe.hpp>
0011 #include <boost/asio/posix/stream_descriptor.hpp>
0012 #include <boost/asio/post.hpp>
0013 #include <system_error>
0014 #include <string>
0015 #include <utility>
0016
0017 namespace boost { namespace process { namespace detail { namespace posix {
0018
0019 class async_pipe
0020 {
0021 ::boost::asio::posix::stream_descriptor _source;
0022 ::boost::asio::posix::stream_descriptor _sink ;
0023 public:
0024 typedef int native_handle_type;
0025 typedef ::boost::asio::posix::stream_descriptor handle_type;
0026 typedef typename handle_type::executor_type executor_type;
0027
0028 executor_type get_executor()
0029 {
0030 return _source.get_executor();
0031 }
0032
0033 inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {}
0034
0035 inline async_pipe(boost::asio::io_context & ios_source,
0036 boost::asio::io_context & ios_sink) : _source(ios_source), _sink(ios_sink)
0037 {
0038 int fds[2];
0039 if (::pipe(fds) == -1)
0040 boost::process::detail::throw_last_error("pipe(2) failed");
0041
0042 _source.assign(fds[0]);
0043 _sink .assign(fds[1]);
0044 };
0045 inline async_pipe(boost::asio::io_context & ios, const std::string & name)
0046 : async_pipe(ios, ios, name) {}
0047
0048 inline async_pipe(boost::asio::io_context & ios_source,
0049 boost::asio::io_context & io_sink, const std::string & name);
0050 inline async_pipe(const async_pipe& lhs);
0051 async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink))
0052 {
0053 lhs._source = ::boost::asio::posix::stream_descriptor{lhs._source.get_executor()};
0054 lhs._sink = ::boost::asio::posix::stream_descriptor{lhs._sink. get_executor()};
0055 }
0056
0057 template<class CharT, class Traits = std::char_traits<CharT>>
0058 explicit async_pipe(::boost::asio::io_context & ios_source,
0059 ::boost::asio::io_context & ios_sink,
0060 const basic_pipe<CharT, Traits> & p)
0061 : _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
0062 {
0063 }
0064
0065 template<class CharT, class Traits = std::char_traits<CharT>>
0066 explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
0067 : async_pipe(ios, ios, p)
0068 {
0069 }
0070
0071 template<class CharT, class Traits = std::char_traits<CharT>>
0072 inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
0073 inline async_pipe& operator=(const async_pipe& rhs);
0074
0075 inline async_pipe& operator=(async_pipe&& lhs);
0076
0077 ~async_pipe()
0078 {
0079 boost::system::error_code ec;
0080 close(ec);
0081 }
0082
0083 template<class CharT, class Traits = std::char_traits<CharT>>
0084 inline explicit operator basic_pipe<CharT, Traits>() const;
0085
0086 void cancel()
0087 {
0088 if (_sink.is_open())
0089 _sink.cancel();
0090 if (_source.is_open())
0091 _source.cancel();
0092 }
0093
0094 void close()
0095 {
0096 if (_sink.is_open())
0097 _sink.close();
0098 if (_source.is_open())
0099 _source.close();
0100 }
0101 void close(boost::system::error_code & ec)
0102 {
0103 if (_sink.is_open())
0104 _sink.close(ec);
0105 if (_source.is_open())
0106 _source.close(ec);
0107 }
0108
0109
0110 bool is_open() const
0111 {
0112 return _sink.is_open() || _source.is_open();
0113 }
0114 void async_close()
0115 {
0116 if (_sink.is_open())
0117 boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
0118 if (_source.is_open())
0119 boost::asio::post(_source.get_executor(), [this]{_source.close();});
0120 }
0121
0122 template<typename MutableBufferSequence>
0123 std::size_t read_some(const MutableBufferSequence & buffers)
0124 {
0125 return _source.read_some(buffers);
0126 }
0127 template<typename MutableBufferSequence>
0128 std::size_t write_some(const MutableBufferSequence & buffers)
0129 {
0130 return _sink.write_some(buffers);
0131 }
0132
0133 template<typename MutableBufferSequence>
0134 std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
0135 {
0136 return _source.read_some(buffers, ec);
0137 }
0138 template<typename MutableBufferSequence>
0139 std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
0140 {
0141 return _sink.write_some(buffers, ec);
0142 }
0143
0144
0145 native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native_handle();}
0146 native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native_handle();}
0147
0148 template<typename MutableBufferSequence,
0149 typename ReadHandler>
0150 BOOST_ASIO_INITFN_RESULT_TYPE(
0151 ReadHandler, void(boost::system::error_code, std::size_t))
0152 async_read_some(
0153 const MutableBufferSequence & buffers,
0154 ReadHandler &&handler)
0155 {
0156 return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
0157 }
0158
0159 template<typename ConstBufferSequence,
0160 typename WriteHandler>
0161 BOOST_ASIO_INITFN_RESULT_TYPE(
0162 WriteHandler, void(boost::system::error_code, std::size_t))
0163 async_write_some(
0164 const ConstBufferSequence & buffers,
0165 WriteHandler&& handler)
0166 {
0167 return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
0168 }
0169
0170
0171 const handle_type & sink () const & {return _sink;}
0172 const handle_type & source() const & {return _source;}
0173
0174 handle_type && sink() && { return std::move(_sink); }
0175 handle_type && source()&& { return std::move(_source); }
0176
0177 handle_type source(::boost::asio::io_context& ios) &&
0178 {
0179 ::boost::asio::posix::stream_descriptor stolen(ios, _source.release());
0180 return stolen;
0181 }
0182 handle_type sink (::boost::asio::io_context& ios) &&
0183 {
0184 ::boost::asio::posix::stream_descriptor stolen(ios, _sink.release());
0185 return stolen;
0186 }
0187
0188 handle_type source(::boost::asio::io_context& ios) const &
0189 {
0190 auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
0191 return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in));
0192 }
0193 handle_type sink (::boost::asio::io_context& ios) const &
0194 {
0195 auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
0196 return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in));
0197 }
0198 };
0199
0200
0201 async_pipe::async_pipe(boost::asio::io_context & ios_source,
0202 boost::asio::io_context & ios_sink,
0203 const std::string & name) : _source(ios_source), _sink(ios_sink)
0204 {
0205 auto fifo = mkfifo(name.c_str(), 0666 );
0206
0207 if (fifo != 0)
0208 boost::process::detail::throw_last_error("mkfifo() failed");
0209
0210
0211 int read_fd = open(name.c_str(), O_RDWR);
0212
0213 if (read_fd == -1)
0214 boost::process::detail::throw_last_error();
0215
0216 int write_fd = dup(read_fd);
0217
0218 if (write_fd == -1)
0219 boost::process::detail::throw_last_error();
0220
0221 _source.assign(read_fd);
0222 _sink .assign(write_fd);
0223 }
0224
0225 async_pipe::async_pipe(const async_pipe & p) :
0226 _source(const_cast<async_pipe&>(p)._source.get_executor()),
0227 _sink( const_cast<async_pipe&>(p)._sink.get_executor())
0228 {
0229
0230
0231 auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
0232 auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
0233 if (source_in == -1)
0234 _source.assign(-1);
0235 else
0236 {
0237 _source.assign(::dup(source_in));
0238 if (_source.native_handle()== -1)
0239 ::boost::process::detail::throw_last_error("dup()");
0240 }
0241
0242 if (sink_in == -1)
0243 _sink.assign(-1);
0244 else
0245 {
0246 _sink.assign(::dup(sink_in));
0247 if (_sink.native_handle() == -1)
0248 ::boost::process::detail::throw_last_error("dup()");
0249 }
0250 }
0251
0252 async_pipe& async_pipe::operator=(const async_pipe & p)
0253 {
0254 int source;
0255 int sink;
0256
0257
0258 auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._source).native_handle();
0259 auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._sink).native_handle();
0260 if (source_in == -1)
0261 source = -1;
0262 else
0263 {
0264 source = ::dup(source_in);
0265 if (source == -1)
0266 ::boost::process::detail::throw_last_error("dup()");
0267 }
0268
0269 if (sink_in == -1)
0270 sink = -1;
0271 else
0272 {
0273 sink = ::dup(sink_in);
0274 if (sink == -1)
0275 ::boost::process::detail::throw_last_error("dup()");
0276 }
0277 _source.assign(source);
0278 _sink. assign(sink);
0279
0280 return *this;
0281 }
0282
0283 async_pipe& async_pipe::operator=(async_pipe && lhs)
0284 {
0285 std::swap(_source, lhs._source);
0286 std::swap(_sink, lhs._sink);
0287 return *this;
0288 }
0289
0290 template<class CharT, class Traits>
0291 async_pipe::operator basic_pipe<CharT, Traits>() const
0292 {
0293 int source;
0294 int sink;
0295
0296
0297 auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
0298 auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
0299
0300
0301 if (source_in == -1)
0302 source = -1;
0303 else
0304 {
0305 source = ::dup(source_in);
0306 if (source == -1)
0307 ::boost::process::detail::throw_last_error("dup()");
0308 }
0309
0310 if (sink_in == -1)
0311 sink = -1;
0312 else
0313 {
0314 sink = ::dup(sink_in);
0315 if (sink == -1)
0316 ::boost::process::detail::throw_last_error("dup()");
0317 }
0318
0319 return basic_pipe<CharT, Traits>{source, sink};
0320 }
0321
0322
0323 inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
0324 {
0325 return compare_handles(lhs.native_source(), rhs.native_source()) &&
0326 compare_handles(lhs.native_sink(), rhs.native_sink());
0327 }
0328
0329 inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
0330 {
0331 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
0332 !compare_handles(lhs.native_sink(), rhs.native_sink());
0333 }
0334
0335 template<class Char, class Traits>
0336 inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
0337 {
0338 return compare_handles(lhs.native_source(), rhs.native_source()) &&
0339 compare_handles(lhs.native_sink(), rhs.native_sink());
0340 }
0341
0342 template<class Char, class Traits>
0343 inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
0344 {
0345 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
0346 !compare_handles(lhs.native_sink(), rhs.native_sink());
0347 }
0348
0349 template<class Char, class Traits>
0350 inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
0351 {
0352 return compare_handles(lhs.native_source(), rhs.native_source()) &&
0353 compare_handles(lhs.native_sink(), rhs.native_sink());
0354 }
0355
0356 template<class Char, class Traits>
0357 inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
0358 {
0359 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
0360 !compare_handles(lhs.native_sink(), rhs.native_sink());
0361 }
0362
0363 }}}}
0364
0365 #endif