Skip to content

Commit dc1664a

Browse files
added process support.
1 parent e674fc6 commit dc1664a

File tree

8 files changed

+422
-6
lines changed

8 files changed

+422
-6
lines changed

Diff for: CMakeLists.txt

+8-4
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ endif()
5757

5858
if (NOT BOOST_ASYNC_BUILD_INLINE)
5959
find_package(Threads REQUIRED)
60-
find_package(Boost REQUIRED container system json url)
60+
find_package(Boost REQUIRED container system json filesystem)
6161
include_directories(include)
6262
endif()
6363

@@ -97,16 +97,20 @@ add_library(boost_async
9797
src/io/read.cpp
9898
src/io/read_at.cpp
9999
src/io/read_until.cpp
100+
src/io/popen.cpp
101+
src/io/process.cpp
100102
src/io/buffers/register.cpp
101103
src/io/write.cpp
102104
src/io/write_at.cpp
103-
src/io/detail/random_access_device.cpp src/io/copy.cpp)
105+
src/io/detail/random_access_device.cpp
106+
src/io/copy.cpp)
104107

105108
target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
106109
target_link_libraries(boost_async PUBLIC
107-
Boost::container Boost::system Boost::url
110+
Boost::container Boost::system
108111
Threads::Threads)
109-
target_compile_definitions(boost_async PRIVATE -DBOOST_ASYNC_SOURCE)
112+
target_compile_definitions(boost_async PRIVATE BOOST_ASYNC_SOURCE=1)
113+
target_compile_definitions(boost_async PUBLIC BOOST_PROCESS_USE_STD_FS=1)
110114

111115
add_library(Boost::async ALIAS boost_async)
112116

Diff for: include/boost/async/io/popen.hpp

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// Copyright (c) 2023 Klemens Morgenstern ([email protected])
3+
//
4+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
8+
#ifndef BOOST_ASYNC_IO_POPEN_HPP
9+
#define BOOST_ASYNC_IO_POPEN_HPP
10+
11+
#include <boost/async/config.hpp>
12+
#include <boost/async/io/process.hpp>
13+
#include <boost/process/v2/popen.hpp>
14+
#include <boost/async/io/stream.hpp>
15+
16+
namespace boost::async::io
17+
{
18+
19+
struct popen : stream
20+
{
21+
using wait_result = system::result<int>;
22+
using handle_type = typename boost::process::v2::basic_process<executor>::handle_type;
23+
using native_handle_type = typename boost::process::v2::basic_process<executor>::native_handle_type;
24+
25+
BOOST_ASYNC_DECL popen(boost::process::v2::filesystem::path executable,
26+
std::initializer_list<core::string_view> args,
27+
process_initializer initializer = {});
28+
29+
30+
BOOST_ASYNC_DECL popen(boost::process::v2::filesystem::path executable,
31+
std::span<core::string_view> args,
32+
process_initializer initializer = {});
33+
34+
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> interrupt();
35+
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> request_exit();
36+
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> suspend();
37+
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> resume();
38+
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> terminate();
39+
[[nodiscard]] BOOST_ASYNC_DECL handle_type detach();
40+
[[nodiscard]] BOOST_ASYNC_DECL system::result<bool> running();
41+
42+
43+
[[nodiscard]] pid_type id() const;
44+
45+
[[nodiscard]] system::result<void> close() override;
46+
[[nodiscard]] system::result<void> cancel() override;
47+
[[nodiscard]] bool is_open() const override;
48+
49+
private:
50+
void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler<system::error_code, std::size_t> h)override;
51+
void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler<system::error_code, std::size_t> h) override;
52+
public:
53+
[[nodiscard]] process::wait_op_ wait() { return process::wait_op_{popen_}; }
54+
process::wait_op_ operator co_await () { return wait(); }
55+
private:
56+
boost::process::v2::basic_popen<executor> popen_;
57+
};
58+
59+
60+
}
61+
62+
#endif //BOOST_ASYNC_IO_POPEN_HPP

Diff for: include/boost/async/io/process.hpp

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//
2+
// Copyright (c) 2023 Klemens Morgenstern ([email protected])
3+
//
4+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
8+
#ifndef BOOST_ASYNC_IO_PROCESS_HPP
9+
#define BOOST_ASYNC_IO_PROCESS_HPP
10+
11+
#include <boost/async/config.hpp>
12+
#include <boost/async/op.hpp>
13+
14+
#include <boost/process/v2/process.hpp>
15+
#include <boost/process/v2/stdio.hpp>
16+
#include <boost/process/v2/start_dir.hpp>
17+
#include <boost/process/v2/environment.hpp>
18+
#include <boost/core/detail/string_view.hpp>
19+
#include <boost/system/result.hpp>
20+
21+
#include <initializer_list>
22+
23+
namespace boost::async::io
24+
{
25+
26+
using boost::process::v2::pid_type;
27+
28+
struct process_initializer
29+
{
30+
process::v2::process_stdio stdio;
31+
process::v2::process_start_dir start_dir{process::v2::filesystem::current_path()};
32+
process::v2::process_environment env{process::v2::environment::current()};
33+
};
34+
35+
struct process
36+
{
37+
using wait_result = system::result<int>;
38+
using handle_type = typename boost::process::v2::basic_process<executor>::handle_type;
39+
using native_handle_type = typename boost::process::v2::basic_process<executor>::native_handle_type;
40+
41+
BOOST_ASYNC_DECL process(boost::process::v2::filesystem::path executable,
42+
std::initializer_list<core::string_view> args,
43+
process_initializer initializer = {});
44+
45+
46+
BOOST_ASYNC_DECL process(boost::process::v2::filesystem::path executable,
47+
std::span<core::string_view> args,
48+
process_initializer initializer = {});
49+
50+
BOOST_ASYNC_DECL process(pid_type pid);
51+
BOOST_ASYNC_DECL process(pid_type pid, native_handle_type native_handle);
52+
53+
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> interrupt();
54+
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> request_exit();
55+
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> suspend();
56+
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> resume();
57+
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> terminate();
58+
[[nodiscard]] BOOST_ASYNC_DECL handle_type detach();
59+
[[nodiscard]] BOOST_ASYNC_DECL system::result<bool> running();
60+
61+
62+
[[nodiscard]] pid_type id() const;
63+
64+
private:
65+
struct wait_op_ : detail::deferred_op_resource_base
66+
{
67+
constexpr static bool await_ready() { return false; }
68+
69+
BOOST_ASYNC_DECL void init_op(completion_handler<system::error_code, int> handler);
70+
71+
template<typename Promise>
72+
bool await_suspend(std::coroutine_handle<Promise> h)
73+
{
74+
try
75+
{
76+
init_op(completion_handler<system::error_code, int>{h, result_, get_resource(h)});
77+
return true;
78+
}
79+
catch(...)
80+
{
81+
error = std::current_exception();
82+
return false;
83+
}
84+
}
85+
86+
[[nodiscard]] wait_result await_resume()
87+
{
88+
if (error)
89+
std::rethrow_exception(std::exchange(error, nullptr));
90+
auto [ec, sig] = result_.value_or(std::make_tuple(system::error_code{}, 0));
91+
if (ec)
92+
return ec;
93+
else
94+
return sig;
95+
}
96+
wait_op_(boost::process::v2::basic_process<executor> & process) : process_(process) {}
97+
private:
98+
boost::process::v2::basic_process<executor> & process_;
99+
std::exception_ptr error;
100+
std::optional<std::tuple<system::error_code, int>> result_;
101+
char buffer[256];
102+
std::optional<container::pmr::monotonic_buffer_resource> resource;
103+
};
104+
public:
105+
[[nodiscard]] wait_op_ wait() { return wait_op_{process_}; }
106+
wait_op_ operator co_await () { return wait(); }
107+
private:
108+
boost::process::v2::basic_process<executor> process_;
109+
friend struct popen;
110+
};
111+
112+
113+
}
114+
115+
#endif //BOOST_ASYNC_IO_PROCESS_HPP

Diff for: include/boost/async/io/resolver.hpp

-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ struct resolver
7979
asio::ip::basic_resolver<protocol_type, executor> resolver_;
8080
};
8181

82-
// NOTE: Doesn't need to be a promise, can be optimized.
8382
struct lookup
8483
{
8584
lookup(core::string_view host, core::string_view service)

Diff for: src/io/popen.cpp

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//
2+
// Copyright (c) 2023 Klemens Morgenstern ([email protected])
3+
//
4+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
8+
#include <boost/async/io/popen.hpp>
9+
10+
namespace boost::async::io
11+
{
12+
13+
popen::popen(boost::process::v2::filesystem::path executable,
14+
std::initializer_list<core::string_view> args,
15+
process_initializer initializer)
16+
: popen_(this_thread::get_executor(),
17+
executable,
18+
args,
19+
initializer.stdio,
20+
initializer.start_dir,
21+
initializer.env) {}
22+
23+
24+
popen::popen(boost::process::v2::filesystem::path executable,
25+
std::span<core::string_view> args,
26+
process_initializer initializer)
27+
: popen_(this_thread::get_executor(),
28+
executable,
29+
args,
30+
initializer.stdio,
31+
initializer.start_dir,
32+
initializer.env) {}
33+
34+
pid_type popen::id() const {return popen_.id();}
35+
36+
system::result<void> popen::interrupt()
37+
{
38+
system::error_code ec;
39+
popen_.interrupt(ec);
40+
return ec ? ec : system::result<void>();
41+
}
42+
system::result<void> popen::request_exit()
43+
{
44+
system::error_code ec;
45+
popen_.request_exit(ec);
46+
return ec ? ec : system::result<void>();
47+
}
48+
system::result<void> popen::suspend()
49+
{
50+
system::error_code ec;
51+
popen_.suspend(ec);
52+
return ec ? ec : system::result<void>();
53+
}
54+
system::result<void> popen::resume()
55+
{
56+
system::error_code ec;
57+
popen_.resume(ec);
58+
return ec ? ec : system::result<void>();
59+
}
60+
system::result<void> popen::terminate()
61+
{
62+
system::error_code ec;
63+
popen_.terminate(ec);
64+
return ec ? ec : system::result<void>();
65+
}
66+
popen::handle_type popen::detach()
67+
{
68+
return popen_.detach();
69+
}
70+
system::result<bool> popen::running()
71+
{
72+
system::error_code ec;
73+
auto res = popen_.running(ec);
74+
return ec ? ec : system::result<bool>(res);
75+
}
76+
77+
system::result<void> popen::close()
78+
{
79+
return this->terminate();
80+
}
81+
82+
system::result<void> popen::cancel()
83+
{
84+
system::error_code ec;
85+
popen_.get_stdin().cancel(ec);
86+
if (ec)
87+
return ec;
88+
popen_.get_stdout().cancel(ec);
89+
if (ec)
90+
return ec;
91+
return {};
92+
}
93+
94+
bool popen::is_open() const
95+
{
96+
return this->popen_.is_open();
97+
}
98+
99+
void popen::async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler<system::error_code, std::size_t> h)
100+
{
101+
popen_.async_read_some(buffer, std::move(h));
102+
}
103+
void popen::async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler<system::error_code, std::size_t> h)
104+
{
105+
popen_.async_write_some(buffer, std::move(h));
106+
}
107+
108+
109+
}

0 commit comments

Comments
 (0)