Skip to content

Commit

Permalink
added process support.
Browse files Browse the repository at this point in the history
  • Loading branch information
klemens-morgenstern committed Jul 1, 2023
1 parent e674fc6 commit dc1664a
Show file tree
Hide file tree
Showing 8 changed files with 422 additions and 6 deletions.
12 changes: 8 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ endif()

if (NOT BOOST_ASYNC_BUILD_INLINE)
find_package(Threads REQUIRED)
find_package(Boost REQUIRED container system json url)
find_package(Boost REQUIRED container system json filesystem)
include_directories(include)
endif()

Expand Down Expand Up @@ -97,16 +97,20 @@ add_library(boost_async
src/io/read.cpp
src/io/read_at.cpp
src/io/read_until.cpp
src/io/popen.cpp
src/io/process.cpp
src/io/buffers/register.cpp
src/io/write.cpp
src/io/write_at.cpp
src/io/detail/random_access_device.cpp src/io/copy.cpp)
src/io/detail/random_access_device.cpp
src/io/copy.cpp)

target_include_directories(boost_async PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(boost_async PUBLIC
Boost::container Boost::system Boost::url
Boost::container Boost::system
Threads::Threads)
target_compile_definitions(boost_async PRIVATE -DBOOST_ASYNC_SOURCE)
target_compile_definitions(boost_async PRIVATE BOOST_ASYNC_SOURCE=1)
target_compile_definitions(boost_async PUBLIC BOOST_PROCESS_USE_STD_FS=1)

add_library(Boost::async ALIAS boost_async)

Expand Down
62 changes: 62 additions & 0 deletions include/boost/async/io/popen.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// Copyright (c) 2023 Klemens Morgenstern ([email protected])
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_ASYNC_IO_POPEN_HPP
#define BOOST_ASYNC_IO_POPEN_HPP

#include <boost/async/config.hpp>
#include <boost/async/io/process.hpp>
#include <boost/process/v2/popen.hpp>
#include <boost/async/io/stream.hpp>

namespace boost::async::io
{

struct popen : stream
{
using wait_result = system::result<int>;
using handle_type = typename boost::process::v2::basic_process<executor>::handle_type;
using native_handle_type = typename boost::process::v2::basic_process<executor>::native_handle_type;

BOOST_ASYNC_DECL popen(boost::process::v2::filesystem::path executable,
std::initializer_list<core::string_view> args,
process_initializer initializer = {});


BOOST_ASYNC_DECL popen(boost::process::v2::filesystem::path executable,
std::span<core::string_view> args,
process_initializer initializer = {});

[[nodiscard]] BOOST_ASYNC_DECL system::result<void> interrupt();
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> request_exit();
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> suspend();
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> resume();
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> terminate();
[[nodiscard]] BOOST_ASYNC_DECL handle_type detach();
[[nodiscard]] BOOST_ASYNC_DECL system::result<bool> running();


[[nodiscard]] pid_type id() const;

[[nodiscard]] system::result<void> close() override;
[[nodiscard]] system::result<void> cancel() override;
[[nodiscard]] bool is_open() const override;

private:
void async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler<system::error_code, std::size_t> h)override;
void async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler<system::error_code, std::size_t> h) override;
public:
[[nodiscard]] process::wait_op_ wait() { return process::wait_op_{popen_}; }
process::wait_op_ operator co_await () { return wait(); }
private:
boost::process::v2::basic_popen<executor> popen_;
};


}

#endif //BOOST_ASYNC_IO_POPEN_HPP
115 changes: 115 additions & 0 deletions include/boost/async/io/process.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//
// Copyright (c) 2023 Klemens Morgenstern ([email protected])
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_ASYNC_IO_PROCESS_HPP
#define BOOST_ASYNC_IO_PROCESS_HPP

#include <boost/async/config.hpp>
#include <boost/async/op.hpp>

#include <boost/process/v2/process.hpp>
#include <boost/process/v2/stdio.hpp>
#include <boost/process/v2/start_dir.hpp>
#include <boost/process/v2/environment.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/system/result.hpp>

#include <initializer_list>

namespace boost::async::io
{

using boost::process::v2::pid_type;

struct process_initializer
{
process::v2::process_stdio stdio;
process::v2::process_start_dir start_dir{process::v2::filesystem::current_path()};
process::v2::process_environment env{process::v2::environment::current()};
};

struct process
{
using wait_result = system::result<int>;
using handle_type = typename boost::process::v2::basic_process<executor>::handle_type;
using native_handle_type = typename boost::process::v2::basic_process<executor>::native_handle_type;

BOOST_ASYNC_DECL process(boost::process::v2::filesystem::path executable,
std::initializer_list<core::string_view> args,
process_initializer initializer = {});


BOOST_ASYNC_DECL process(boost::process::v2::filesystem::path executable,
std::span<core::string_view> args,
process_initializer initializer = {});

BOOST_ASYNC_DECL process(pid_type pid);
BOOST_ASYNC_DECL process(pid_type pid, native_handle_type native_handle);

[[nodiscard]] BOOST_ASYNC_DECL system::result<void> interrupt();
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> request_exit();
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> suspend();
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> resume();
[[nodiscard]] BOOST_ASYNC_DECL system::result<void> terminate();
[[nodiscard]] BOOST_ASYNC_DECL handle_type detach();
[[nodiscard]] BOOST_ASYNC_DECL system::result<bool> running();


[[nodiscard]] pid_type id() const;

private:
struct wait_op_ : detail::deferred_op_resource_base
{
constexpr static bool await_ready() { return false; }

BOOST_ASYNC_DECL void init_op(completion_handler<system::error_code, int> handler);

template<typename Promise>
bool await_suspend(std::coroutine_handle<Promise> h)
{
try
{
init_op(completion_handler<system::error_code, int>{h, result_, get_resource(h)});
return true;
}
catch(...)
{
error = std::current_exception();
return false;
}
}

[[nodiscard]] wait_result await_resume()
{
if (error)
std::rethrow_exception(std::exchange(error, nullptr));
auto [ec, sig] = result_.value_or(std::make_tuple(system::error_code{}, 0));
if (ec)
return ec;
else
return sig;
}
wait_op_(boost::process::v2::basic_process<executor> & process) : process_(process) {}
private:
boost::process::v2::basic_process<executor> & process_;
std::exception_ptr error;
std::optional<std::tuple<system::error_code, int>> result_;
char buffer[256];
std::optional<container::pmr::monotonic_buffer_resource> resource;
};
public:
[[nodiscard]] wait_op_ wait() { return wait_op_{process_}; }
wait_op_ operator co_await () { return wait(); }
private:
boost::process::v2::basic_process<executor> process_;
friend struct popen;
};


}

#endif //BOOST_ASYNC_IO_PROCESS_HPP
1 change: 0 additions & 1 deletion include/boost/async/io/resolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ struct resolver
asio::ip::basic_resolver<protocol_type, executor> resolver_;
};

// NOTE: Doesn't need to be a promise, can be optimized.
struct lookup
{
lookup(core::string_view host, core::string_view service)
Expand Down
109 changes: 109 additions & 0 deletions src/io/popen.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//
// Copyright (c) 2023 Klemens Morgenstern ([email protected])
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <boost/async/io/popen.hpp>

namespace boost::async::io
{

popen::popen(boost::process::v2::filesystem::path executable,
std::initializer_list<core::string_view> args,
process_initializer initializer)
: popen_(this_thread::get_executor(),
executable,
args,
initializer.stdio,
initializer.start_dir,
initializer.env) {}


popen::popen(boost::process::v2::filesystem::path executable,
std::span<core::string_view> args,
process_initializer initializer)
: popen_(this_thread::get_executor(),
executable,
args,
initializer.stdio,
initializer.start_dir,
initializer.env) {}

pid_type popen::id() const {return popen_.id();}

system::result<void> popen::interrupt()
{
system::error_code ec;
popen_.interrupt(ec);
return ec ? ec : system::result<void>();
}
system::result<void> popen::request_exit()
{
system::error_code ec;
popen_.request_exit(ec);
return ec ? ec : system::result<void>();
}
system::result<void> popen::suspend()
{
system::error_code ec;
popen_.suspend(ec);
return ec ? ec : system::result<void>();
}
system::result<void> popen::resume()
{
system::error_code ec;
popen_.resume(ec);
return ec ? ec : system::result<void>();
}
system::result<void> popen::terminate()
{
system::error_code ec;
popen_.terminate(ec);
return ec ? ec : system::result<void>();
}
popen::handle_type popen::detach()
{
return popen_.detach();
}
system::result<bool> popen::running()
{
system::error_code ec;
auto res = popen_.running(ec);
return ec ? ec : system::result<bool>(res);
}

system::result<void> popen::close()
{
return this->terminate();
}

system::result<void> popen::cancel()
{
system::error_code ec;
popen_.get_stdin().cancel(ec);
if (ec)
return ec;
popen_.get_stdout().cancel(ec);
if (ec)
return ec;
return {};
}

bool popen::is_open() const
{
return this->popen_.is_open();
}

void popen::async_read_some_impl_(buffers::mutable_buffer_subspan buffer, async::completion_handler<system::error_code, std::size_t> h)
{
popen_.async_read_some(buffer, std::move(h));
}
void popen::async_write_some_impl_(buffers::const_buffer_subspan buffer, async::completion_handler<system::error_code, std::size_t> h)
{
popen_.async_write_some(buffer, std::move(h));
}


}
Loading

0 comments on commit dc1664a

Please sign in to comment.