boost::process::async_system in composed asio operations
- Dominant language
- C++
- Stars
- 145
- Forks
- 151
- PR merge metrics
- No merged PRs in 30d
Description
Boost version: 1.72.0
I would like to use boost::process::async_system() within a composed operation (example taken from [composed_6.cpp](https://www.boost.org/doc/libs/1_72_0/doc/html/boost_asio/example/cpp14/operations/composed_6.cpp)).
The helper boost::asio::async_compose() creates a temporary object (boost::asio::detail::composed_op<>) which contains all necessary variables/states during the whole composed operation. Unfortunately my program (below) doesn't compile. The (lengthy) compiler message looks like boost::process::async_system() tries to make another copy of the completion object (self). But boost::asio::detail::composed_op<> is not copyable.
Is it possible to avoid making an extra copy of the completion object in boost::process::async_system() (like the other boost::asio::async_xxx functions behave)?
regards
Christian
```C++
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static constexpr char const *gpsdExecutable = "/usr/sbin/gpsd"; // always absolute, also on host
static constexpr char const *gpsdControlSocket = "/run/gpsd.sock"; // always absolute, also on host
static void prepareGpsdSockets(
boost::asio::local::stream_protocol::acceptor &controlSocket,
boost::asio::ip::tcp::acceptor &exportSocket,
boost::asio::ip::tcp::resolver::results_type const &endpoints,
boost::system::error_code &ec)
{
/* control socket */
boost::filesystem::remove(gpsdControlSocket, ec); // ignore errors
boost::asio::local::stream_protocol::endpoint controlSocketEp(gpsdControlSocket);
controlSocket.open(controlSocketEp.protocol(), ec);
if (ec)
return;
controlSocket.bind(controlSocketEp, ec);
if (ec)
return;
controlSocket.listen(boost::asio::socket_base::max_listen_connections, ec);
if (ec)
return;
/* export socket TCPv4 */
boost::asio::ip::tcp::endpoint const &exportSocketEp = *endpoints.begin();
exportSocket.open(exportSocketEp.protocol(), ec);
if (ec)
return;
exportSocket.set_option(boost::asio::socket_base::reuse_address(true), ec);
if (ec)
return;
exportSocket.bind(exportSocketEp, ec);
if (ec)
return;
exportSocket.listen(boost::asio::socket_base::max_listen_connections, ec);
if (ec)
return;
}
template
inline auto async_startGpsd(boost::asio::io_context &ioContext, CompletionToken &&token)
{
enum class State { starting, resolving, forking };
return boost::asio::async_compose(
[
state = State::starting,
&ioContext,
/* Note: std::make_shared() doesn't help here. */
controlSocket = std::make_unique(ioContext),
resolver = std::make_unique(ioContext),
exportSocket = std::make_unique(ioContext)
]
(
auto &self, // reference to intermediate completion handle (provided by async_compose)
boost::system::error_code ec = {},
boost::asio::ip::tcp::resolver::results_type endpoints = {},
int exitCode = {}
) mutable
{
if (ec)
{
self.complete(ec);
return;
}
switch (state)
{
case State::starting:
{
state = State::resolving;
/* lookup gpsd port number from /etc/services */
resolver->async_resolve(boost::asio::ip::tcp::v4(), "", "gpsd", boost::asio::ip::resolver_base::flags::passive, std::move(self));
return; // Composed operation not yet complete.
}
case State::resolving:
{
state = State::forking;
prepareGpsdSockets(*controlSocket, *exportSocket, endpoints, ec);
if (ec)
break;
auto controlHandle = controlSocket->native_handle();
auto exportHandle = exportSocket->native_handle();
boost::process::async_system(
ioContext,
[self=std::move(self)]
(boost::system::error_code ec, int exitCode)
mutable
{
self(ec, boost::asio::ip::tcp::resolver::results_type(), exitCode);
},
boost::process::exe = gpsdExecutable,
boost::process::args = {
"--listenany",
},
/* the order of bind() and close() is important */
boost::process::std_in < stdin, // don't close std handles
boost::process::std_out > stdout,
boost::process::std_err > stderr,
boost::process::posix::fd.bind(3, controlHandle),
boost::process::posix::fd.bind(4, exportHandle),
boost::process::posix::fd.close(controlHandle),
boost::process::posix::fd.close(exportHandle),
boost::process::limit_handles,
boost::process::extend::on_exec_setup = [](auto &executor)
{
auto env = boost::this_process::environment();
env["LISTEN_PID"] = std::to_string(boost::this_process::native_handle());
env["LISTEN_FDS"] = "2"; // number of sockets
/* use latest ::environ for ::execve() */
executor.env = env.native_handle();
}
);
return; // Composed operation not yet complete.
}
case State::forking:
if (exitCode) // error code from gpsd
{
ec.assign(ESRCH /* No such process */, boost::system::system_category());
}
break; // Composed operation complete, continue below.
}
// Call the user-supplied handler with the result of the operation.
self.complete(ec);
},
token, ioContext);
}
int main(void)
{
boost::asio::io_context ioContext;
async_startGpsd(ioContext,
[](boost::system::error_code const &ec)
{
std::cout << "async_startGpsd() finished with ec = \n" << ec;
});
}
```
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.