2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-21 17:12:19 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Klemens Morgenstern
0ca663c826 Set ENOTSUP when PROC_PPID_ONLY is undefined
closes #452
2025-01-26 21:49:25 +08:00
129 changed files with 384 additions and 1109 deletions

View File

@@ -23,19 +23,19 @@ jobs:
include: include:
- { toolset: gcc-5, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: g++-5 } - { toolset: gcc-5, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: g++-5 }
- { toolset: gcc-6, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: g++-6 } - { toolset: gcc-6, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: g++-6 }
- { toolset: gcc-7, cxxstd: "11,14,17", os: ubuntu-latest, container: 'ubuntu:20.04', install: g++-7 } - { toolset: gcc-7, cxxstd: "11,14,17", os: ubuntu-20.04, install: g++-7 }
- { toolset: gcc-10, cxxstd: "11,14,17,2a", os: ubuntu-22.04, install: g++-10 } - { toolset: gcc-10, cxxstd: "11,14,17,2a", os: ubuntu-22.04, install: g++-10 }
- { toolset: gcc-12, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: g++-12 } - { toolset: gcc-12, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: g++-12 }
- { toolset: clang, compiler: clang++-3.9, cxxstd: "11,14", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-3.9 } - { toolset: clang, compiler: clang++-3.9, cxxstd: "11,14", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-3.9 }
- { toolset: clang, compiler: clang++-4.0, cxxstd: "11,14", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-4.0 } - { toolset: clang, compiler: clang++-4.0, cxxstd: "11,14", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-4.0 }
- { toolset: clang, compiler: clang++-5.0, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-5.0 } - { toolset: clang, compiler: clang++-5.0, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-5.0 }
- { toolset: clang, compiler: clang++-6.0, cxxstd: "11,14,17", os: ubuntu-latest, container: 'ubuntu:20.04', install: clang-6.0 } - { toolset: clang, compiler: clang++-6.0, cxxstd: "11,14,17", os: ubuntu-20.04, install: clang-6.0 }
- { toolset: clang, compiler: clang++-7, cxxstd: "11,14,17", os: ubuntu-latest, container: 'ubuntu:20.04', install: clang-7 } - { toolset: clang, compiler: clang++-7, cxxstd: "11,14,17", os: ubuntu-20.04, install: clang-7 }
- { toolset: clang, compiler: clang++-8, cxxstd: "11,14,17", os: ubuntu-latest, container: 'ubuntu:20.04', install: clang-8 } - { toolset: clang, compiler: clang++-8, cxxstd: "11,14,17", os: ubuntu-20.04, install: clang-8 }
- { toolset: clang, compiler: clang++-9, cxxstd: "11,14,17,2a", os: ubuntu-latest, container: 'ubuntu:20.04', install: clang-9 } - { toolset: clang, compiler: clang++-9, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-9 }
- { toolset: clang, compiler: clang++-10, cxxstd: "11,14,17,2a", os: ubuntu-latest, container: 'ubuntu:20.04', install: clang-10 } - { toolset: clang, compiler: clang++-10, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-10 }
- { toolset: clang, compiler: clang++-11, cxxstd: "11,14,17,2a", os: ubuntu-22.04, install: clang-11 } - { toolset: clang, compiler: clang++-11, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-11 }
- { toolset: clang, compiler: clang++-12, cxxstd: "11,14,17,2a", os: ubuntu-22.04, install: clang-12 } - { toolset: clang, compiler: clang++-12, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-12 }
- { toolset: clang, compiler: clang++-13, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: clang-13 } - { toolset: clang, compiler: clang++-13, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: clang-13 }
- { toolset: clang, compiler: clang++-14, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: clang-14 } - { toolset: clang, compiler: clang++-14, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: clang-14 }
- { toolset: clang, cxxstd: "11,14,17,2a", os: macos-13 } - { toolset: clang, cxxstd: "11,14,17,2a", os: macos-13 }

View File

@@ -3,12 +3,10 @@
# Distributed under the Boost Software License, Version 1.0. # Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt # https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.8...3.31) cmake_minimum_required(VERSION 3.5...3.16)
project(boost_process VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) project(boost_process VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
option(BOOST_PROCESS_USE_STD_FS "Use std::filesystem instead of Boost.Filesystem" OFF)
add_library(boost_process add_library(boost_process
src/detail/environment_posix.cpp src/detail/environment_posix.cpp
src/detail/environment_win.cpp src/detail/environment_win.cpp
@@ -37,6 +35,7 @@ target_link_libraries(boost_process
Boost::asio Boost::asio
Boost::config Boost::config
Boost::core Boost::core
Boost::filesystem
Boost::fusion Boost::fusion
Boost::iterator Boost::iterator
Boost::move Boost::move
@@ -51,14 +50,13 @@ target_compile_definitions(boost_process
PRIVATE BOOST_PROCESS_SOURCE=1 PRIVATE BOOST_PROCESS_SOURCE=1
) )
if(BOOST_PROCESS_USE_STD_FS) if (BOOST_PROCESS_USE_STD_FS)
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_USE_STD_FS) target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_USE_STD_FS=1 )
target_compile_features(boost_process PUBLIC cxx_std_17)
else() else()
target_link_libraries(boost_process PUBLIC Boost::filesystem) target_link_libraries(boost_process PUBLIC Boost::filesystem)
endif() endif()
if(WIN32) if (WIN32)
target_link_libraries(boost_process PUBLIC ntdll shell32 advapi32 user32 ws2_32) target_link_libraries(boost_process PUBLIC ntdll shell32 advapi32 user32 ws2_32)
endif() endif()

View File

@@ -6,8 +6,8 @@ Boost.process is a library for comfortable management of processes, released wit
| Branches | Linux / Windows | Code coverage | Matrix | | Branches | Linux / Windows | Code coverage | Matrix |
|----------|----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------| |----------|----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| Develop: | [![Build Status](https://drone.cpp.al/api/badges/boostorg/process/status.svg)](https://drone.cpp.al/boostorg/process) | [![codecov](https://codecov.io/gh/boostorg/process/branch/develop/graph/badge.svg?token=AhunMqTSpA)](https://codecov.io/gh/boostorg/process) | [![Matrix](https://img.shields.io/badge/matrix-develop-lightgray.svg)](https://regression.boost.io/develop/developer/process.html) | | Develop: | [![Build Status](https://drone.cpp.al/api/badges/boostorg/process/status.svg)](https://drone.cpp.al/boostorg/process) | [![codecov](https://codecov.io/gh/boostorg/process/branch/develop/graph/badge.svg?token=AhunMqTSpA)](https://codecov.io/gh/boostorg/process) | [![Matrix](https://img.shields.io/badge/matrix-develop-lightgray.svg)](http://www.boost.org/development/tests/develop/developer/process.html) |
| Master: | [![Build Status](https://drone.cpp.al/api/badges/boostorg/process/status.svg?ref=refs/heads/develop)](https://drone.cpp.al/boostorg/process) | [![codecov](https://codecov.io/gh/boostorg/process/branch/master/graph/badge.svg?token=AhunMqTSpA)](https://codecov.io/gh/boostorg/process) | [![Matrix](https://img.shields.io/badge/matrix-master-lightgray.svg)](https://regression.boost.io/master/developer/process.html) | | Master: | [![Build Status](https://drone.cpp.al/api/badges/boostorg/process/status.svg?ref=refs/heads/develop)](https://drone.cpp.al/boostorg/process) | [![codecov](https://codecov.io/gh/boostorg/process/branch/master/graph/badge.svg?token=AhunMqTSpA)](https://codecov.io/gh/boostorg/process) | [![Matrix](https://img.shields.io/badge/matrix-master-lightgray.svg)](http://www.boost.org/development/tests/master/developer/process.html) |

View File

@@ -8,6 +8,6 @@ A special thank you goes to [http://www.intra2net.com/(Intra2net AG) (especially
Great thanks also goes to Boris Schaeling, who despite having boost.process rejected, went on to work on it and maintained it up until this day and participated in the development of the current version. Great thanks also goes to Boris Schaeling, who despite having boost.process rejected, went on to work on it and maintained it up until this day and participated in the development of the current version.
Many Thanks, to [https://github.com/samuelvenable](Samuel Venable) for contributing the <<v2::ext>> functionality and all the research that went into it. Many Thanks, to [https://github.com/time-killer-games](Samuel Venable) for contributing the <<v2::ext>> functionality and all the research that went into it.

View File

@@ -7,5 +7,5 @@ Boost process v2 can be configured in the following ways:
| Macro | Description | Macro | Description
| `BOOST_PROCESS_V2_STANDALONE` | Build boost.process for standalone asio | `BOOST_PROCESS_V2_STANDALONE` | Build boost.process for standalone asio
| `BOOST_PROCESS_USE_STD_FS` | Use std::filesystem instead of boost::filesystem | `BOOST_PROCESS_USE_STD_FS` | Use std::filesystem instead of boost::filsystem
| `BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE` | Disable usage of `close_range`. | `BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE` | Disable usage of `close_range`.

View File

@@ -25,28 +25,7 @@ include::../example/env.cpp[tag=current_env]
The subprocess environment assignment follows the same constraints: The subprocess environment assignment follows the same constraints:
.example/env.cpp:34-42 .example/env.cpp:34-42
[source,cpp,indent=0] [source,cpp,ident=0]
---- ----
include::../example/env.cpp[tag=subprocess_env] include::../example/env.cpp[tag=subprocess_env]
---- ----
== Inheriting an environment
The current environment can be obtained by calling `environment::current` which returns
a forward range of `environment::key_value_pair_view`.
.example/env.cpp:48-54
[source,cpp,indent=0]
----
include::../example/env.cpp[tag=vector_env]
----
Alternatively you can use a map container for the environment.
.example/env.cpp:61-68
[source,cpp,indent=0]
----
include::../example/env.cpp[tag=map_env]
----

View File

@@ -118,7 +118,7 @@ struct custom_initializer
}; };
---- ----
NOTE: All the additional launchers for windows inherit `default_launcher`. NTOE: All the additional launchers for windows inherit `default_launcher`.
The call sequence is as follows: The call sequence is as follows:

View File

@@ -1,6 +1,6 @@
== `bind_launcher.hpp` == `bind_launcher.hpp`
The `bind_launcher` utilities allow on the fly construction of a launcher with bound initializers. The `bind_launcher` utlitities allow on the fly construction of a launcher with bound initializers.
[source,cpp] [source,cpp]
---- ----
@@ -9,7 +9,7 @@ template<typename Launcher, typename ... Init>
auto bind_launcher(Launcher && launcher, Init && ... init); auto bind_launcher(Launcher && launcher, Init && ... init);
// Calls bind_launcher with the default_launcher as the first parameter. // Calls bind_launcher with the default_launcher as the first parameter.
// The new launcher with bound parameters // The new launcher with bound paramaters
template<typename ... Init> template<typename ... Init>
auto bind_default_launcher(Init && ... init); auto bind_default_launcher(Init && ... init);
---- ----

View File

@@ -8,7 +8,7 @@ The `default_launcher` is the standard way of creating a process.
asio::io_context ctx; asio::io_context ctx;
process proc(ctx.get_executor(), "test", {}); process proc(ctx.get_executor(), "test", {});
// equivalent to // equivalent to
process proc = default_launcher()(ctx.get_executor(), "test", {}); process prod = default_launcher()(ctx.get_executor(), "test", {});
---- ----
It has four overloads: It has four overloads:

View File

@@ -3,7 +3,7 @@
=== `environment` === `environment`
The `environment` header provides facilities to manipulate the current environment and set it for new processes. The `environment` header provides facilities to maniuplate the current environment and set it for new processes.
An environment is a a `range` of `T` fulfilling these requirements: An environment is a a `range` of `T` fulfilling these requirements:
@@ -22,16 +22,16 @@ namespace environment
// A char traits type that reflects the OS rules for string representing environment keys. // A char traits type that reflects the OS rules for string representing environment keys.
/* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`. /* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`.
* *
* Windows treats keys as case-insensitive yet preserving. The char traits are made to reflect * Windows treats keys as case-insensitive yet perserving. The char traits are made to reflect
* that behaviour. * that behaviour.
*/ */
template<typename Char> tempalte<typename Char>
using key_char_traits = implementation_defined ; using key_char_traits = implementation_defined ;
// A char traits type that reflects the OS rules for string representing environment values. // A char traits type that reflects the OS rules for string representing environment values.
/* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`. /* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`.
*/ */
template<typename Char> tempalte<typename Char>
using value_char_traits = implementation_defined ; using value_char_traits = implementation_defined ;
// The character type used by the environment. Either `char` or `wchar_t`. // The character type used by the environment. Either `char` or `wchar_t`.

View File

@@ -1,7 +1,7 @@
== `popen.hpp` == `popen.hpp`
[#popen] [#popen]
`popen` is a class that launches a process and connect stdin & stdout to pipes. `popen` is a class that launches a process and connect stdin & stderr to pipes.
[source,cpp] [source,cpp]
---- ----

View File

@@ -41,7 +41,7 @@ struct bind_fd
process p{"test", {}, posix::bind_fd(42, 24)}; process p{"test", {}, posix::bind_fd(42, 24)};
*/ */
bind_fd(int target, int fd); bind_fd(int target, int fd):
// Inherit a null device as a set descriptor. // Inherit a null device as a set descriptor.
/* This will a null device as 42 to the child process: /* This will a null device as 42 to the child process:

View File

@@ -78,7 +78,7 @@ struct basic_process
template<typename ExecutionContext, typename Args, typename ... Inits> template<typename ExecutionContext, typename Args, typename ... Inits>
explicit basic_process( explicit basic_process(
ExecutionContext & context, ExecutionContext & context,
const filesystem::path& exe, const filesystem::path&>::type exe,
Args&& args, Inits&&... inits); Args&& args, Inits&&... inits);
// Attach to an existing process // Attach to an existing process
@@ -142,7 +142,7 @@ struct basic_process
native_handle_type native_handle() {return process_handle_.native_handle(); } native_handle_type native_handle() {return process_handle_.native_handle(); }
// Return the evaluated exit_code. // Return the evaluated exit_code.
int exit_code() const; int exit_code() cons;
// Get the id of the process; // Get the id of the process;
pid_type id() const; pid_type id() const;

View File

@@ -2,7 +2,7 @@
[#process_handle] [#process_handle]
A process handle is an unmanaged version of a process. A process handle is an unmanaged version of a process.
This means it does not terminate the process on destruction and This means it does not terminate the proces on destruction and
will not keep track of the exit-code. will not keep track of the exit-code.
NOTE: that the exit code might be discovered early, during a call to `running`. NOTE: that the exit code might be discovered early, during a call to `running`.
@@ -100,10 +100,9 @@ struct basic_process_handle
// Check if the process handle is referring to an existing process. // Check if the process handle is referring to an existing process.
bool is_open() const; bool is_open() const;
// Asynchronously wait for the process to exit and assign the native exit-code to the reference. // Asynchronously wait for the process to exit and deliver the native exit-code in the completion handler.
// The exit_status can indicate that a process has already be waited for, e.g. when terminate is called. template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
WaitHandler = net::default_completion_token_t<executor_type>> WaitHandler = net::default_completion_token_t<executor_type>>
auto async_wait(native_exit_code_type &exit_status, WaitHandler &&handler = net::default_completion_token_t<executor_type>()); auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>());
}; };
---- ----

View File

@@ -26,7 +26,7 @@ in later version of C++.
asio::io_context ctx; asio::io_context ctx;
/// C++17 /// C++17
v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{.err=nullptr}); v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{.stderr=nullptr});
/// C++11 & C++14 /// C++11 & C++14
v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{ {}, {}, nullptr}); v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{ {}, {}, nullptr});
---- ----
@@ -35,57 +35,12 @@ Valid initializers for any stdio are:
- `std::nullptr_t` assigning a null-device - `std::nullptr_t` assigning a null-device
- `FILE*` any open file, including `stdin`, `stdout` and `stderr` - `FILE*` any open file, including `stdin`, `stdout` and `stderr`
- `native_handle` any native file handle (`HANDLE` on windows) or file descriptor (`int` on posix)
- any io-object with a `.native_handle()` function that is compatible with the above. E.g. a `asio::ip::tcp::socket`, or a pipe object.
- a filesystem::path, which will open a readable or writable depending on the direction of the stream - a filesystem::path, which will open a readable or writable depending on the direction of the stream
- an `asio::basic_writeable_pipe` for stdin or `asio::basic_readable_pipe` for stderr/stdout. - `native_handle` any native file handle (`HANDLE` on windows) or file descriptor (`int` on posix)
- any io-object with a .native_handle() function that is compatible with the above. E.g. a asio::ip::tcp::socket
- an asio::basic_writeable_pipe for stdin or asio::basic_readable_pipe for stderr/stdout.
When passing a `FILE*`, a `native_handle` or an io-object with a `native_handle`,
the initializer will assign the handle as is to the child process.
That is the file descriptor/handle gets cloned into the subprocess and used without modification.
When passing a filesystem::path, the initializer will attempt to open the file and then pass the handle
to the subprocess.
When passing a `readable_pipe` to stdout/stderr or a `writable_pipe` to stdin by reference,
the initializer to create the other side of the pipe (`writable_pipe` for stdout/stderr, `readable_pipe` for `stdin`),
connect the pair and pass the native_handle to the child process.
That is, these two are equivalent:
.Implicit construction of the readable pipe.
[source,cpp]
----
asio::io_context ctx;
asio::writable_pipe wp{ctx};
// create a readable pipe internally and connect it to wp
process proc{ctx, "/bin/bash", {}, process_stdio{.in=wp}};
// create it explicitly
{
// the pipe the child process reads from
asio::readable_pipe rp{ctx};
asio::connect_pipe(rp, wp);
// `rp.native_handle()` will be assigned to the child processes stdin
process proc{ctx, "/bin/bash", {}, process_stdio{.in=rp}};
rp.close(); // close it so the pipe closes when the `proc exits.
}
----
The explicit version allows you to assign the same `writable_pipe` to `stdout` and `stderr`:
[source,cpp]
----
// the pipe the parent process reads from and both
// stderr & stdout of the child process write to
asio::readable_pipe rp{ctx};
asio::writable_pipe wp{ctx};
asio::connect_pipe(rp, wp);
process proc{ctx, "/bin/bash", {}, process_stdio{.out=wp, .err=wp}};
wp.close(); // close it so the pipe closes when the `proc exits.
----
NOTE: If the child writes to a pipe, the parent reads from it et vice versa.
[source,cpp] [source,cpp]
@@ -97,4 +52,4 @@ struct process_stdio
__implementation_defined__ out; __implementation_defined__ out;
__implementation_defined__ err; __implementation_defined__ err;
}; };
---- ----

View File

@@ -16,7 +16,7 @@ automatically connected and the other side will get assigned to the child proces
include::../example/stdio.cpp[tag=readable_pipe] include::../example/stdio.cpp[tag=readable_pipe]
---- ----
readable pipes can be assigned to `out` and `err`, while writable_pipes can be assigned to `in`. readable pipes can be assigned to `out` an `err`, while writable_pipes can be assigned to `in`.
== `FILE*` == `FILE*`

View File

@@ -13,7 +13,7 @@ The major changes are
* separate compilation * separate compilation
* fd safe by default * fd safe by default
Version 2 is now the default. In order to discourage usage of the deprecated v1, it's documentation has been removed. Version 2 is now the defauled. In order to discourage usage of the deprecated v1, it's documentation has been removed.
== Simplified Interface == Simplified Interface
@@ -64,7 +64,7 @@ This concerns especially the `wait_for` and `wait_until` functions on the proces
The latter are easy to do on windows, but posix does not provide an API for this. The latter are easy to do on windows, but posix does not provide an API for this.
Thus the wait_for used signals or fork, which was all but safe. Thus the wait_for used signals or fork, which was all but safe.
Since process v2 is based on asio and thus supports cancellation, Since process v2 is based on asio and thus supports cancellation,
a wait_for can now safely be implemented with an async_wait + timeout. a wait_for can not safely be implemented with an async_wait + timeout.
== UTF-8 == UTF-8

View File

@@ -42,30 +42,4 @@ int main()
process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env)); process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env));
// end::subprocess_env[] // end::subprocess_env[]
} }
{
// tag::vector_env[]
asio::io_context ctx;
auto c = environment::current();
// we need to use a value, since windows needs wchar_t.
std::vector<environment::key_value_pair> my_env{c.begin(), c.end()};
my_env.push_back("SECRET=THIS_IS_A_TEST");
auto exe = environment::find_executable("g++", my_env);
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
// end::vector_env[]
}
{
// tag::map_env[]
asio::io_context ctx;
std::unordered_map<environment::key, environment::value> my_env;
for (const auto & kv : environment::current())
if (kv.key().string() != "SECRET")
my_env[kv.key()] = kv.value();
auto exe = environment::find_executable("g++", my_env);
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
// end::map_env[]
}
} }

View File

@@ -1 +1 @@
#include <boost/process/v2/posix/bind_fd.hpp> #include <boost/process/v2/bind_fd.hpp>

View File

@@ -1 +1 @@
#include <boost/process/v2/posix/default_launcher.hpp> #include <boost/process/v2/default_launcher.hpp>

View File

@@ -1 +1 @@
#include <boost/process/v2/posix/fork_and_forget_launcher.hpp> #include <boost/process/v2/fork_and_forget_launcher.hpp>

View File

@@ -1 +1 @@
#include <boost/process/v2/posix/pdfork_launcher.hpp> #include <boost/process/v2/pdfork_launcher.hpp>

View File

@@ -1 +1 @@
#include <boost/process/v2/posix/vfork_launcher.hpp> #include <boost/process/v2/vfork_launcher.hpp>

View File

@@ -1,28 +0,0 @@
// Copyright (c) 2024 Klemens D. Morgenstern
//
// 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_PROCESS_V1_HPP
#define BOOST_PROCESS_V1_HPP
#include <boost/process/v1/args.hpp>
#include <boost/process/v1/async.hpp>
#include <boost/process/v1/async_system.hpp>
#include <boost/process/v1/group.hpp>
#include <boost/process/v1/child.hpp>
#include <boost/process/v1/cmd.hpp>
#include <boost/process/v1/env.hpp>
#include <boost/process/v1/environment.hpp>
#include <boost/process/v1/error.hpp>
#include <boost/process/v1/exe.hpp>
#include <boost/process/v1/group.hpp>
#include <boost/process/v1/handles.hpp>
#include <boost/process/v1/io.hpp>
#include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/shell.hpp>
#include <boost/process/v1/search_path.hpp>
#include <boost/process/v1/spawn.hpp>
#include <boost/process/v1/system.hpp>
#include <boost/process/v1/start_dir.hpp>
#endif //BOOST_PROCESS_V1_HPP

View File

@@ -114,7 +114,7 @@ io_context ios;
child c("ls", ios, on_exit=[](int exit, const std::error_code& ec_in){}); child c("ls", ios, on_exit=[](int exit, const std::error_code& ec_in){});
std::future<int> exit_code; std::future<int> exit_code;
child c2("ls", ios, on_exit=exit_code); chlid c2("ls", ios, on_exit=exit_code);
\endcode \endcode

View File

@@ -26,7 +26,7 @@ namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
#if defined(BOOST_PROCESS_DOXYGEN) #if defined(BOOST_PROCESS_DOXYGEN)
/** Class implementing an asynchronous I/O-Object for use with boost.asio. /** Class implementing an asnychronous I/O-Object for use with boost.asio.
* It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or * It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or
* boost::asio::posix::stream_descriptor. * boost::asio::posix::stream_descriptor.
* *

View File

@@ -39,7 +39,7 @@ child::child(Args&&...args)
typedef ::boost::process::v1::detail::api::pid_t pid_t; typedef ::boost::process::v1::detail::api::pid_t pid_t;
#if defined(BOOST_PROCESS_DOXYGEN) #if defined(BOOST_PROCESS_DOXYGEN)
/** The main class to hold a child process. It is similar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread), /** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread),
* in that it has a join and detach function. * in that it has a join and detach function.
* *
* @attention The destructor will call terminate on the process if not joined or detached without any warning. * @attention The destructor will call terminate on the process if not joined or detached without any warning.
@@ -128,7 +128,7 @@ class child
/** Same as valid, for convenience. */ /** Same as valid, for convenience. */
explicit operator bool() const; explicit operator bool() const;
/** Check if the the child process is in any process group. */ /** Check if the the chlid process is in any process group. */
bool in_group() const; bool in_group() const;
/** \overload bool in_group() const */ /** \overload bool in_group() const */

View File

@@ -107,7 +107,7 @@ public:
using string_type = std::basic_string<char_type>; using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **; using native_handle_type = char_type **;
void reload() {this->_env_impl = environ;} void reload() {this->_env_impl = ::environ;}
string_type get(const pointer_type id) { return getenv(id); } string_type get(const pointer_type id) { return getenv(id); }
void set(const pointer_type id, const pointer_type value) void set(const pointer_type id, const pointer_type value)
@@ -136,7 +136,7 @@ public:
native_environment_impl & operator=(native_environment_impl && ) = default; native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = environ; native_handle_type _env_impl = environ;
native_handle_type native_handle() const {return environ;} native_handle_type native_handle() const {return ::environ;}
}; };

View File

@@ -275,7 +275,7 @@ class executor
prepare_cmd_style_fn = exe; prepare_cmd_style_fn = exe;
if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK)) if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK))
{ {
const auto * e = environ; const auto * e = ::environ;
while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH=")) while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH="))
e++; e++;
@@ -316,7 +316,7 @@ public:
const char * exe = nullptr; const char * exe = nullptr;
char *const* cmd_line = nullptr; char *const* cmd_line = nullptr;
bool cmd_style = false; bool cmd_style = false;
char **env = environ; char **env = ::environ;
pid_t pid = -1; pid_t pid = -1;
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active); std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);

View File

@@ -31,8 +31,6 @@ inline std::string make_pipe_name()
static std::atomic_size_t cnt{0}; static std::atomic_size_t cnt{0};
name += std::to_string(pid); name += std::to_string(pid);
name += "_"; name += "_";
name += std::to_string(intptr_t(&cnt)); // to unclash Boost instances in plug-in DLLs
name += "_";
name += std::to_string(cnt++); name += std::to_string(cnt++);
return name; return name;
@@ -62,6 +60,8 @@ public:
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name) async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name)
: async_pipe(ios_source, ios_sink, name, false) {} : async_pipe(ios_source, ios_sink, name, false) {}
inline async_pipe(const async_pipe& rhs); inline async_pipe(const async_pipe& rhs);
async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink)) async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
{ {
@@ -153,6 +153,7 @@ public:
return _sink.write_some(buffers); return _sink.write_some(buffers);
} }
template<typename MutableBufferSequence> template<typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
{ {
@@ -280,6 +281,7 @@ async_pipe::async_pipe(const async_pipe& p) :
_sink. assign(sink); _sink. assign(sink);
} }
async_pipe::async_pipe(boost::asio::io_context & ios_source, async_pipe::async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink, boost::asio::io_context & ios_sink,
const std::string & name, bool private_) : _source(ios_source), _sink(ios_sink) const std::string & name, bool private_) : _source(ios_source), _sink(ios_sink)
@@ -296,6 +298,7 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
| FILE_FLAG_OVERLAPPED_, //write flag | FILE_FLAG_OVERLAPPED_, //write flag
0, private_ ? 1 : ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr); 0, private_ ? 1 : ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
if (source == boost::winapi::INVALID_HANDLE_VALUE_) if (source == boost::winapi::INVALID_HANDLE_VALUE_)
::boost::process::v1::detail::throw_last_error("create_named_pipe(" + name + ") failed"); ::boost::process::v1::detail::throw_last_error("create_named_pipe(" + name + ") failed");

View File

@@ -162,9 +162,7 @@ struct exe_cmd_init : handler_base_ext
} }
static exe_cmd_init<Char> exe_args_shell(string_type && exe, std::vector<string_type> && args) static exe_cmd_init<Char> exe_args_shell(string_type && exe, std::vector<string_type> && args)
{ {
std::vector<string_type> args_ = {c_arg(Char())}; std::vector<string_type> args_ = {c_arg(Char()), std::move(exe)};
if (!exe.empty())
args_.emplace_back(std::move(exe));
args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end())); args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end()));
string_type sh = get_shell(Char()); string_type sh = get_shell(Char());

View File

@@ -222,7 +222,7 @@ basic_environment_impl<Char>::basic_environment_impl(const native_environment_im
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>())) while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
p++; p++;
p++; //pointing to the second nullchar p++; //pointing to the second nullchar
p++; //to get the pointer behind the second nullchar, so it's end. p++; //to get the pointer behing the second nullchar, so it's end.
this->_data.assign(beg, p); this->_data.assign(beg, p);
this->reload(); this->reload();

View File

@@ -627,7 +627,7 @@ public:
using base_type::operator=; using base_type::operator=;
}; };
///Type definition to hold a separate environment. ///Type definition to hold a seperate environment.
template<typename Char> template<typename Char>
class basic_environment : public basic_environment_impl<Char, detail::api::basic_environment_impl> class basic_environment : public basic_environment_impl<Char, detail::api::basic_environment_impl>
{ {
@@ -646,10 +646,10 @@ typedef basic_native_environment<char> native_environment;
typedef basic_native_environment<wchar_t> wnative_environment; typedef basic_native_environment<wchar_t> wnative_environment;
#if !defined(BOOST_NO_ANSI_APIS) #if !defined(BOOST_NO_ANSI_APIS)
///Type definition to hold a separate environment. ///Type definition to hold a seperate environment.
typedef basic_environment<char> environment; typedef basic_environment<char> environment;
#endif #endif
///Type definition to hold a separate environment. ///Type definition to hold a seperate environment.
typedef basic_environment<wchar_t> wenvironment; typedef basic_environment<wchar_t> wenvironment;
}} }}
@@ -673,10 +673,10 @@ inline int get_id() { return ::boost::process::v1::detail::a
///Get the native handle of the current process. ///Get the native handle of the current process.
inline native_handle_type native_handle() { return ::boost::process::v1::detail::api::native_handle();} inline native_handle_type native_handle() { return ::boost::process::v1::detail::api::native_handle();}
#if !defined(BOOST_NO_ANSI_APIS) #if !defined(BOOST_NO_ANSI_APIS)
///Get the environment of the current process. ///Get the enviroment of the current process.
inline native_environment environment() { return ::boost::process::v1:: native_environment(); } inline native_environment environment() { return ::boost::process::v1:: native_environment(); }
#endif #endif
///Get the environment of the current process. ///Get the enviroment of the current process.
inline wnative_environment wenvironment() { return ::boost::process::v1::wnative_environment(); } inline wnative_environment wenvironment() { return ::boost::process::v1::wnative_environment(); }
///Get the path environment variable of the current process runs. ///Get the path environment variable of the current process runs.
inline std::vector<boost::process::v1::filesystem::path> path() inline std::vector<boost::process::v1::filesystem::path> path()

View File

@@ -124,7 +124,7 @@ struct handler
template <class Executor> template <class Executor>
void on_setup(Executor&) const {} void on_setup(Executor&) const {}
/** This function is invoked if an error occurred while trying to launch the process. /** This function is invoked if an error occured while trying to launch the process.
* \note It is not required to be const. * \note It is not required to be const.
*/ */
template <class Executor> template <class Executor>
@@ -136,7 +136,7 @@ struct handler
template <class Executor> template <class Executor>
void on_success(Executor&) const {} void on_success(Executor&) const {}
/**This function is invoked if an error occurred during the call of `fork`. /**This function is invoked if an error occured during the call of `fork`.
* \note This function will only be called on posix. * \note This function will only be called on posix.
*/ */
template<typename Executor> template<typename Executor>
@@ -249,7 +249,7 @@ struct posix_executor
///A pointer to the argument-vector. ///A pointer to the argument-vector.
char *const* cmd_line = nullptr; char *const* cmd_line = nullptr;
///A pointer to the environment variables, as default it is set to [environ](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html) ///A pointer to the environment variables, as default it is set to [environ](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html)
char **env = environ; char **env = ::environ;
///The pid of the process - it will be -1 before invoking [fork](http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html), and after forking either 0 for the new process or a positive value if in the current process. */ ///The pid of the process - it will be -1 before invoking [fork](http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html), and after forking either 0 for the new process or a positive value if in the current process. */
pid_t pid = -1; pid_t pid = -1;
///This shared-pointer holds the exit code. It's done this way, so it can be shared between an `asio::io_context` and \ref child. ///This shared-pointer holds the exit code. It's done this way, so it can be shared between an `asio::io_context` and \ref child.
@@ -335,7 +335,7 @@ struct windows_executor
void set_startup_info_ex(); void set_startup_info_ex();
///This element is an instance or a reference (if \ref startup_info_ex exists) to the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx) for the process. ///This element is an instance or a reference (if \ref startup_info_ex exists) to the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx) for the process.
startup_info_t startup_info; startup_info_t startup_info;
///This element is the instance of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx). It is only available with a winapi-version equal or higher than 6. ///This element is the instance of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx). It is only available with a winapi-version equal or highter than 6.
startup_info_ex_t startup_info_ex; startup_info_ex_t startup_info_ex;
}; };

View File

@@ -78,9 +78,8 @@ inline std::locale default_locale()
std::locale global_loc = std::locale(); std::locale global_loc = std::locale();
return std::locale(global_loc, new std::codecvt_utf8<wchar_t>); return std::locale(global_loc, new std::codecvt_utf8<wchar_t>);
# else // Other POSIX # else // Other POSIX
// ISO C calls std::locale("") "the locale-specific native environment", and this // Return a default locale object.
// locale is the default for many POSIX-based operating systems such as Linux. return std::locale();
return std::locale("");
# endif # endif
} }

View File

@@ -18,8 +18,6 @@
#else #else
#if defined(BOOST_PROCESS_V2_PDFORK) #if defined(BOOST_PROCESS_V2_PDFORK)
#include <boost/process/v2/posix/pdfork_launcher.hpp> #include <boost/process/v2/posix/pdfork_launcher.hpp>
#elif defined(BOOST_PROCESS_V2_PIPEFORK)
#include <boost/process/v2/posix/pipe_fork_launcher.hpp>
#else #else
#include <boost/process/v2/posix/default_launcher.hpp> #include <boost/process/v2/posix/default_launcher.hpp>
#endif #endif
@@ -50,8 +48,6 @@ typedef windows::default_launcher default_process_launcher;
#else #else
#if defined(BOOST_PROCESS_V2_PDFORK) #if defined(BOOST_PROCESS_V2_PDFORK)
typedef posix::pdfork_launcher default_process_launcher; typedef posix::pdfork_launcher default_process_launcher;
#elif defined(BOOST_PROCESS_V2_PIPEFORK)
typedef posix::pipe_fork_launcher default_process_launcher;
#else #else
typedef posix::default_launcher default_process_launcher; typedef posix::default_launcher default_process_launcher;
#endif #endif

View File

@@ -165,7 +165,7 @@ BOOST_PROCESS_V2_END_NAMESPACE
#include <sys/syscall.h> #include <sys/syscall.h>
#if defined(SYS_pidfd_open) && !defined(BOOST_PROCESS_V2_DISABLE_PIDFD_OPEN) #if defined(SYS_pidfd_open)
#define BOOST_PROCESS_V2_PIDFD_OPEN 1 #define BOOST_PROCESS_V2_PIDFD_OPEN 1
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1 #define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
#endif #endif

View File

@@ -14,13 +14,8 @@
#include <boost/process/v2/detail/config.hpp> #include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/cstring_ref.hpp> #include <boost/process/v2/cstring_ref.hpp>
#if defined(__APPLE__) #if defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
# include <crt_externs.h> extern "C" { extern char **environ; }
# if !defined(environ)
# define environ (*_NSGetEnviron())
# endif
#elif defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
extern "C" { extern char **environ; }
#endif #endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE BOOST_PROCESS_V2_BEGIN_NAMESPACE

View File

@@ -85,7 +85,7 @@ struct key_char_traits
if (s1 < s2) if (s1 < s2)
return std::move(s2, s2 + n, s1); return std::move(s2, s2 + n, s1);
else else
return std::move_backward(s2, s2 + n, s1 + n); return std::move_backward(s2, s2 + n, s1);
} }
BOOST_CONSTEXPR static BOOST_CONSTEXPR static

View File

@@ -69,8 +69,6 @@ struct basic_process_handle_fd
basic_process_handle_fd(executor_type executor, pid_type pid) basic_process_handle_fd(executor_type executor, pid_type pid)
: pid_(pid), descriptor_(executor, syscall(SYS_pidfd_open, pid, 0)) : pid_(pid), descriptor_(executor, syscall(SYS_pidfd_open, pid, 0))
{ {
if (descriptor_.native_handle() == -1)
detail::throw_error(detail::get_last_error(), "wait(pid)");
} }
basic_process_handle_fd(executor_type executor, pid_type pid, native_handle_type process_handle) basic_process_handle_fd(executor_type executor, pid_type pid, native_handle_type process_handle)
@@ -257,7 +255,7 @@ struct basic_process_handle_fd
ec.clear(); ec.clear();
exit_code = code; exit_code = code;
} }
return false; return false;
} }
bool running(native_exit_code_type &exit_code) bool running(native_exit_code_type &exit_code)
@@ -288,21 +286,24 @@ struct basic_process_handle_fd
{ {
net::posix::basic_descriptor<Executor> &descriptor; net::posix::basic_descriptor<Executor> &descriptor;
pid_type pid_; pid_type pid_;
native_exit_code_type & exit_code;
template<typename Self> template<typename Self>
void operator()(Self &&self) void operator()(Self &&self)
{ {
self.reset_cancellation_state(asio::enable_total_cancellation()); self.reset_cancellation_state(asio::enable_total_cancellation());
error_code ec; error_code ec;
native_exit_code_type exit_code{};
int wait_res = -1; int wait_res = -1;
if (pid_ <= 0) // error, complete early if (pid_ <= 0) // error, complete early
BOOST_PROCESS_V2_ASSIGN_EC(ec, net::error::bad_descriptor); ec = net::error::bad_descriptor;
else if (process_is_running(exit_code)) else
{ {
wait_res = ::waitpid(pid_, &exit_code, WNOHANG); wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
if (wait_res == -1) if (wait_res == -1)
ec = get_last_error(); ec = get_last_error();
} }
if (!ec && (wait_res == 0)) if (!ec && (wait_res == 0))
{ {
descriptor.async_wait(net::posix::descriptor_base::wait_read, std::move(self)); descriptor.async_wait(net::posix::descriptor_base::wait_read, std::move(self));
@@ -312,39 +313,38 @@ struct basic_process_handle_fd
struct completer struct completer
{ {
error_code ec; error_code ec;
native_exit_code_type code;
typename std::decay<Self>::type self; typename std::decay<Self>::type self;
void operator()() void operator()()
{ {
self.complete(ec); self.complete(ec, code);
} }
}; };
net::dispatch( net::post(descriptor.get_executor(), completer{ec, exit_code, std::move(self)});
net::get_associated_immediate_executor(self, descriptor.get_executor()),
completer{ec, std::move(self)});
} }
template<typename Self> template<typename Self>
void operator()(Self &&self, error_code ec, int = 0) void operator()(Self &&self, error_code ec, int = 0)
{ {
if (!ec && process_is_running(exit_code)) native_exit_code_type exit_code{};
if (!ec)
if (::waitpid(pid_, &exit_code, 0) == -1) if (::waitpid(pid_, &exit_code, 0) == -1)
ec = get_last_error(); ec = get_last_error();
std::move(self).complete(ec); std::move(self).complete(ec, exit_code);
} }
}; };
public: public:
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code)) template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
WaitHandler = net::default_completion_token_t<executor_type>> WaitHandler = net::default_completion_token_t<executor_type>>
auto async_wait(native_exit_code_type & exit_code, auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>())
WaitHandler &&handler = net::default_completion_token_t<executor_type>()) -> decltype(net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
-> decltype(net::async_compose<WaitHandler, void(error_code)>( async_wait_op_{descriptor_, pid_}, handler, descriptor_))
async_wait_op_{descriptor_, pid_, exit_code}, handler, descriptor_))
{ {
return net::async_compose<WaitHandler, void(error_code)>( return net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{descriptor_, pid_, exit_code}, handler, descriptor_); async_wait_op_{descriptor_, pid_}, handler, descriptor_);
} }
}; };

View File

@@ -18,27 +18,19 @@
#if defined(BOOST_PROCESS_V2_STANDALONE) #if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/any_io_executor.hpp> #include <asio/any_io_executor.hpp>
#include <asio/append.hpp>
#include <asio/associated_immediate_executor.hpp>
#include <asio/compose.hpp> #include <asio/compose.hpp>
#include <asio/dispatch.hpp> #include <asio/dispatch.hpp>
#include <asio/posix/basic_stream_descriptor.hpp> #include <asio/posix/basic_stream_descriptor.hpp>
#include <asio/post.hpp> #include <asio/post.hpp>
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET) #include <asio/windows/signal_set.hpp>
#include <asio/signal_set.hpp>
#endif
#else #else
#include <boost/asio/any_io_executor.hpp> #include <boost/asio/any_io_executor.hpp>
#include <boost/asio/append.hpp>
#include <boost/asio/associated_immediate_executor.hpp>
#include <boost/asio/compose.hpp> #include <boost/asio/compose.hpp>
#include <boost/asio/dispatch.hpp> #include <boost/asio/dispatch.hpp>
#include <boost/asio/posix/basic_stream_descriptor.hpp> #include <boost/asio/posix/basic_stream_descriptor.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
#include <boost/asio/signal_set.hpp> #include <boost/asio/signal_set.hpp>
#endif #endif
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE BOOST_PROCESS_V2_BEGIN_NAMESPACE
@@ -53,7 +45,7 @@ struct basic_process_handle_fd_or_signal
typedef Executor executor_type; typedef Executor executor_type;
executor_type get_executor() executor_type get_executor()
{ return descriptor_.get_executor(); } { return signal_set_.get_executor(); }
/// Rebinds the process_handle to another executor. /// Rebinds the process_handle to another executor.
template<typename Executor1> template<typename Executor1>
@@ -285,13 +277,14 @@ struct basic_process_handle_fd_or_signal
int res = ::waitpid(pid_, &code, WNOHANG); int res = ::waitpid(pid_, &code, WNOHANG);
if (res == -1) if (res == -1)
ec = get_last_error(); ec = get_last_error();
else if (res == 0) else
ec.clear();
if (process_is_running(res))
return true; return true;
else else
{
ec.clear();
exit_code = code; exit_code = code;
}
return false; return false;
} }
@@ -318,21 +311,13 @@ struct basic_process_handle_fd_or_signal
struct basic_process_handle_fd_or_signal; struct basic_process_handle_fd_or_signal;
pid_type pid_ = -1; pid_type pid_ = -1;
net::posix::basic_stream_descriptor<Executor> descriptor_; net::posix::basic_stream_descriptor<Executor> descriptor_;
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
net::basic_signal_set<Executor> signal_set_{descriptor_.get_executor(), SIGCHLD}; net::basic_signal_set<Executor> signal_set_{descriptor_.get_executor(), SIGCHLD};
#else
int signal_set_;
#endif
struct async_wait_op_ struct async_wait_op_
{ {
net::posix::basic_descriptor<Executor> &descriptor; net::posix::basic_descriptor<Executor> &descriptor;
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
net::basic_signal_set<Executor> &handle; net::basic_signal_set<Executor> &handle;
#else
int dummy;
#endif
pid_type pid_; pid_type pid_;
native_exit_code_type & exit_code;
bool needs_post = true; bool needs_post = true;
template<typename Self> template<typename Self>
@@ -345,10 +330,11 @@ struct basic_process_handle_fd_or_signal
template<typename Self> template<typename Self>
void operator()(Self &&self, error_code ec, int = 0) void operator()(Self &&self, error_code ec, int = 0)
{ {
native_exit_code_type exit_code{};
int wait_res = -1; int wait_res = -1;
if (pid_ <= 0) // error, complete early if (pid_ <= 0) // error, complete early
ec = net::error::bad_descriptor; ec = net::error::bad_descriptor;
else if (process_is_running(exit_code)) else
{ {
wait_res = ::waitpid(pid_, &exit_code, WNOHANG); wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
if (wait_res == -1) if (wait_res == -1)
@@ -357,53 +343,46 @@ struct basic_process_handle_fd_or_signal
if (!ec && (wait_res == 0)) if (!ec && (wait_res == 0))
{ {
needs_post = false;
if (descriptor.is_open()) if (descriptor.is_open())
{ descriptor.async_wait(
needs_post = false; net::posix::descriptor_base::wait_read,
descriptor.async_wait( std::move(self));
net::posix::descriptor_base::wait_read,
std::move(self));
return;
}
else else
{ handle.async_wait(std::move(self));
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET) return;
needs_post = false;
handle.async_wait(std::move(self));
return;
#else
BOOST_PROCESS_V2_ASSIGN_EC(ec, net::error::operation_not_supported);
#endif
}
} }
struct completer
{
error_code ec;
native_exit_code_type code;
typename std::decay<Self>::type self;
void operator()()
{
self.complete(ec, code);
}
};
const auto exec = self.get_executor();
completer cpl{ec, exit_code, std::move(self)};
if (needs_post) if (needs_post)
{ net::post(exec, std::move(cpl));
auto exec = net::get_associated_immediate_executor(self, descriptor.get_executor());
net::dispatch(exec, net::append(std::move(self), exit_code, ec));
}
else else
{ net::dispatch(exec, std::move(cpl));
auto exec = net::get_associated_executor(self);
net::dispatch(exec, net::append(std::move(self), exit_code, ec));
}
}
template<typename Self>
void operator()(Self &&self, native_exit_code_type code, error_code ec)
{
self.complete(ec);
} }
}; };
public: public:
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code)) template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
WaitHandler = net::default_completion_token_t<executor_type>> WaitHandler = net::default_completion_token_t<executor_type>>
auto async_wait(native_exit_code_type & exit_code, auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>())
WaitHandler &&handler = net::default_completion_token_t<executor_type>()) -> decltype(net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
-> decltype(net::async_compose<WaitHandler, void(error_code)>( async_wait_op_{descriptor_, signal_set_, pid_}, handler, descriptor_))
async_wait_op_{descriptor_, signal_set_, pid_, exit_code}, handler, descriptor_))
{ {
return net::async_compose<WaitHandler, void(error_code)>( return net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{descriptor_, signal_set_, pid_, exit_code}, handler, descriptor_); async_wait_op_{descriptor_, signal_set_, pid_}, handler, descriptor_);
} }
}; };
} }

View File

@@ -17,25 +17,17 @@
#if defined(BOOST_PROCESS_V2_STANDALONE) #if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/any_io_executor.hpp> #include <asio/any_io_executor.hpp>
#include <asio/append.hpp>
#include <asio/associated_immediate_executor.hpp>
#include <asio/compose.hpp> #include <asio/compose.hpp>
#include <asio/dispatch.hpp> #include <asio/dispatch.hpp>
#include <asio/post.hpp> #include <asio/post.hpp>
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
#include <asio/signal_set.hpp> #include <asio/signal_set.hpp>
#endif
#else #else
#include <boost/asio/any_io_executor.hpp> #include <boost/asio/any_io_executor.hpp>
#include <boost/asio/append.hpp>
#include <boost/asio/associated_immediate_executor.hpp>
#include <boost/asio/compose.hpp> #include <boost/asio/compose.hpp>
#include <boost/asio/dispatch.hpp> #include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
#include <boost/asio/signal_set.hpp> #include <boost/asio/signal_set.hpp>
#endif #endif
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE BOOST_PROCESS_V2_BEGIN_NAMESPACE
@@ -94,14 +86,9 @@ struct basic_process_handle_signal
basic_process_handle_signal& operator=(basic_process_handle_signal && handle) basic_process_handle_signal& operator=(basic_process_handle_signal && handle)
{ {
pid_ = handle.id(); pid_ = handle.id();
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
signal_set_.~basic_signal_set(); signal_set_.~basic_signal_set();
using ss = net::basic_signal_set<Executor>; using ss = net::basic_signal_set<Executor>;
new (&signal_set_) ss(handle.get_executor(), SIGCHLD); new (&signal_set_) ss(handle.get_executor(), SIGCHLD);
#else
signal_set_.executor = handle.signal_set_.executor;
#endif
handle.pid_ = -1; handle.pid_ = -1;
return *this; return *this;
} }
@@ -257,13 +244,11 @@ struct basic_process_handle_signal
int res = ::waitpid(pid_, &code, WNOHANG); int res = ::waitpid(pid_, &code, WNOHANG);
if (res == -1) if (res == -1)
ec = get_last_error(); ec = get_last_error();
else if (res == 0)
if (res == 0)
return true; return true;
else else
{
ec.clear();
exit_code = code; exit_code = code;
}
return false; return false;
} }
@@ -288,28 +273,13 @@ struct basic_process_handle_signal
template<typename> template<typename>
friend struct basic_process_handle_signal; friend struct basic_process_handle_signal;
pid_type pid_ = -1; pid_type pid_ = -1;
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
net::basic_signal_set<Executor> signal_set_; net::basic_signal_set<Executor> signal_set_;
#else
struct signal_set_dummy_
{
signal_set_dummy_(signal_set_dummy_ &&) = default;
signal_set_dummy_(const signal_set_dummy_ &) = default;
Executor executor;
using executor_type = Executor;
executor_type get_executor() {return executor;}
signal_set_dummy_(Executor executor, int) : executor(std::move(executor)) {}
};
signal_set_dummy_ signal_set_;
#endif
struct async_wait_op_ struct async_wait_op_
{ {
#if !defined(BOOST_PROCESS_V2_DISABLE_SIGNALSET)
net::basic_signal_set<Executor> &handle; net::basic_signal_set<Executor> &handle;
pid_type pid_; pid_type pid_;
native_exit_code_type & exit_code;
template<typename Self> template<typename Self>
void operator()(Self &&self) void operator()(Self &&self)
{ {
@@ -320,18 +290,19 @@ struct basic_process_handle_signal
} }
template<typename Self> template<typename Self>
void operator()(Self &&self, error_code ec, int /*sig*/) void operator()(Self &&self, error_code ec, int sig)
{ {
if (ec == net::error::operation_aborted && if (ec == net::error::operation_aborted &&
self.get_cancellation_state().cancelled() self.get_cancellation_state().cancelled()
== net::cancellation_type::none) == net::cancellation_type::none)
ec.clear(); ec.clear();
native_exit_code_type exit_code = -1;
int wait_res = -1; int wait_res = -1;
if (pid_ <= 0) // error, complete early if (pid_ <= 0) // error, complete early
ec = net::error::bad_descriptor; ec = net::error::bad_descriptor;
else if (!ec && process_is_running(exit_code)) else if (!ec)
{ {
wait_res = ::waitpid(pid_, &exit_code, WNOHANG); wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
if (wait_res == -1) if (wait_res == -1)
@@ -344,37 +315,31 @@ struct basic_process_handle_signal
return; return;
} }
struct completer
{
error_code ec;
native_exit_code_type code;
typename std::decay<Self>::type self;
void operator()()
{
self.complete(ec, code);
}
};
const auto exec = self.get_executor(); const auto exec = self.get_executor();
net::dispatch(exec, net::append(std::move(self), ec)); net::dispatch(exec, completer{ec, exit_code, std::move(self)});
}
#else
signal_set_dummy_ dummy_;
pid_t pid;
template<typename Self>
void operator()(Self &&self)
{
auto exec = net::get_associated_immediate_executor(self, dummy_.get_executor());
error_code ec;
BOOST_PROCESS_V2_ASSIGN_EC(ec, net::error::operation_not_supported);
net::dispatch(exec, net::append(std::move(self), native_exit_code_type(), ec));
}
#endif
template<typename Self>
void operator()(Self &&self, error_code ec)
{
self.complete(ec);
} }
}; };
public: public:
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code)) template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
WaitHandler = net::default_completion_token_t<executor_type>> WaitHandler = net::default_completion_token_t<executor_type>>
auto async_wait(native_exit_code_type & exit_code, auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>())
WaitHandler &&handler = net::default_completion_token_t<executor_type>()) -> decltype(net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
-> decltype(net::async_compose<WaitHandler, void(error_code)>( async_wait_op_{signal_set_, pid_}, handler, signal_set_))
async_wait_op_{signal_set_, pid_, exit_code}, handler, signal_set_))
{ {
return net::async_compose<WaitHandler, void(error_code)>( return net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{signal_set_, pid_, exit_code}, handler, signal_set_); async_wait_op_{signal_set_, pid_}, handler, signal_set_);
} }
}; };

View File

@@ -275,7 +275,7 @@ struct basic_process_handle_win
struct async_wait_op_ struct async_wait_op_
{ {
handle_type &handle; handle_type &handle;
native_exit_code_type & exit_code;
template<typename Self> template<typename Self>
void operator()(Self &&self) void operator()(Self &&self)
{ {
@@ -296,24 +296,24 @@ struct basic_process_handle_win
template<typename Self> template<typename Self>
void operator()(Self &&self, error_code ec) void operator()(Self &&self, error_code ec)
{ {
native_exit_code_type exit_code{};
if (ec == asio::error::operation_aborted && !self.get_cancellation_state().cancelled()) if (ec == asio::error::operation_aborted && !self.get_cancellation_state().cancelled())
return handle.async_wait(std::move(self)); return handle.async_wait(std::move(self));
if (!ec && process_is_running(exit_code)) // exit_code could be set by another call to wait. if (!ec)
detail::get_exit_code_(handle.native_handle(), exit_code, ec); detail::get_exit_code_(handle.native_handle(), exit_code, ec);
std::move(self).complete(ec); std::move(self).complete(ec, exit_code);
} }
}; };
public: public:
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code)) template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
WaitHandler = net::default_completion_token_t<executor_type>> WaitHandler = net::default_completion_token_t<executor_type>>
auto async_wait(native_exit_code_type & exit_code, auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>())
WaitHandler &&handler = net::default_completion_token_t<executor_type>()) -> decltype(net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
-> decltype(net::async_compose<WaitHandler, void(error_code)>( async_wait_op_{handle_}, handler, handle_))
async_wait_op_{handle_, exit_code}, handler, handle_))
{ {
return net::async_compose<WaitHandler, void(error_code)>( return net::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{handle_, exit_code}, handler, handle_ async_wait_op_{handle_}, handler, handle_
); );
} }
}; };

View File

@@ -44,14 +44,9 @@ std::basic_string<CharOut, Traits, Allocator> conv_string(
if (ec) if (ec)
detail::throw_error(ec, "size_as_utf8"); detail::throw_error(ec, "size_as_utf8");
std::basic_string<CharOut, Traits, Allocator> res(allocator); std::basic_string<CharOut, Traits, Allocator> res(allocator);
res.resize(req_size); res.resize(req_size);
if (req_size == 0)
return res;
auto res_size = convert_to_utf8(data, size, &res.front(), req_size, ec); auto res_size = convert_to_utf8(data, size, &res.front(), req_size, ec);
if (ec) if (ec)
detail::throw_error(ec, "convert_to_utf8"); detail::throw_error(ec, "convert_to_utf8");
@@ -75,9 +70,6 @@ std::basic_string<CharOut, Traits, Allocator> conv_string(
std::basic_string<CharOut, Traits, Allocator> res(allocator); std::basic_string<CharOut, Traits, Allocator> res(allocator);
res.resize(req_size); res.resize(req_size);
if (req_size == 0)
return res;
auto res_size = convert_to_wide(data, size, &res.front(), req_size, ec); auto res_size = convert_to_wide(data, size, &res.front(), req_size, ec);
if (ec) if (ec)
detail::throw_error(ec, "convert_to_wide"); detail::throw_error(ec, "convert_to_wide");

View File

@@ -40,16 +40,16 @@ namespace environment
/// A char traits type that reflects the OS rules for string representing environment keys. /// A char traits type that reflects the OS rules for string representing environment keys.
/** Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`. /** Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`.
* *
* Windows treats keys as case-insensitive yet preserving. The char traits are made to reflect * Windows treats keys as case-insensitive yet perserving. The char traits are made to reflect
* that behaviour. * that behaviour.
*/ */
template<typename Char> tempalte<typename Char>
using key_char_traits = implementation_defined ; using key_char_traits = implementation_defined ;
/// A char traits type that reflects the OS rules for string representing environment values. /// A char traits type that reflects the OS rules for string representing environment values.
/** Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`. /** Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`.
*/ */
template<typename Char> tempalte<typename Char>
using value_char_traits = implementation_defined ; using value_char_traits = implementation_defined ;
/// The character type used by the environment. Either `char` or `wchar_t`. /// The character type used by the environment. Either `char` or `wchar_t`.
@@ -1372,8 +1372,6 @@ struct current_view
environment::native_iterator iterator_; environment::native_iterator iterator_;
}; };
using const_iterator = iterator;
iterator begin() const {return iterator(handle_.get());} iterator begin() const {return iterator(handle_.get());}
iterator end() const {return iterator(detail::find_end(handle_.get()));} iterator end() const {return iterator(detail::find_end(handle_.get()));}
@@ -1762,12 +1760,9 @@ struct process_environment
std::vector<environment::key_value_pair> env_buffer; std::vector<environment::key_value_pair> env_buffer;
std::vector<wchar_t> unicode_env; std::vector<wchar_t> unicode_env;
BOOST_PROCESS_V2_DECL
error_code on_setup(windows::default_launcher & launcher, error_code on_setup(windows::default_launcher & launcher,
const filesystem::path &, const std::wstring &) const filesystem::path &, const std::wstring &);
{
return do_setup(launcher);
}
BOOST_PROCESS_V2_DECL error_code do_setup(windows::default_launcher & launcher);
#else #else
@@ -1816,13 +1811,7 @@ struct process_environment
BOOST_PROCESS_V2_DECL BOOST_PROCESS_V2_DECL
error_code on_setup(posix::default_launcher & launcher, error_code on_setup(posix::default_launcher & launcher,
const filesystem::path &, const char * const *) const filesystem::path &, const char * const *);
{
return do_setup(launcher);
}
BOOST_PROCESS_V2_DECL error_code do_setup(posix::default_launcher & launcher);
std::vector<environment::key_value_pair> env_buffer; std::vector<environment::key_value_pair> env_buffer;
std::vector<const char *> env; std::vector<const char *> env;

View File

@@ -30,13 +30,9 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#if defined(__APPLE__)
# include <crt_externs.h> #if defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
# if !defined(environ) extern "C" { extern char **environ; }
# define environ (*_NSGetEnviron())
# endif
#elif defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
extern "C" { extern char **environ; }
#endif #endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE BOOST_PROCESS_V2_BEGIN_NAMESPACE
@@ -264,7 +260,7 @@ inline void on_exec_error(Launcher & launcher, const filesystem::path &executabl
struct default_launcher struct default_launcher
{ {
/// The pointer to the environment forwarded to the subprocess. /// The pointer to the environment forwarded to the subprocess.
const char * const * env = environ; const char * const * env = ::environ;
/// The pid of the subprocess - will be assigned after fork. /// The pid of the subprocess - will be assigned after fork.
int pid = -1; int pid = -1;
@@ -352,9 +348,9 @@ struct default_launcher
} }
fd_whitelist.push_back(pg.p[1]); fd_whitelist.push_back(pg.p[1]);
#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
auto & ctx = net::query( auto & ctx = net::query(
exec, net::execution::context); exec, net::execution::context);
#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)
ctx.notify_fork(net::execution_context::fork_prepare); ctx.notify_fork(net::execution_context::fork_prepare);
#endif #endif
pid = ::fork(); pid = ::fork();
@@ -386,7 +382,7 @@ struct default_launcher
ignore_unused(::write(pg.p[1], &errno, sizeof(int))); ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category()); BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
detail::on_exec_error(*this, executable, argv, ec, inits...); detail::on_exec_error(*this, executable, argv, ec, inits...);
::_exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
return basic_process<Executor>{exec}; return basic_process<Executor>{exec};
} }
#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)

View File

@@ -115,7 +115,7 @@ struct fork_and_forget_launcher : default_launcher
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category()); BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
detail::on_exec_error(*this, executable, argv, ec, inits...); detail::on_exec_error(*this, executable, argv, ec, inits...);
::_exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
return basic_process<Executor>{exec}; return basic_process<Executor>{exec};
} }
#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)

View File

@@ -136,7 +136,7 @@ struct pdfork_launcher : default_launcher
default_launcher::ignore_unused(::write(pg.p[1], &errno, sizeof(int))); default_launcher::ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category()); BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
detail::on_exec_error(*this, executable, argv, ec, inits...); detail::on_exec_error(*this, executable, argv, ec, inits...);
::_exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
return basic_process<Executor>{exec}; return basic_process<Executor>{exec};
} }
#if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK)

View File

@@ -1,185 +0,0 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// 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_PROCESS_V2_POSIX_PIPE_FORK_LAUNCHER_HPP
#define BOOST_PROCESS_V2_POSIX_PIPE_FORK_LAUNCHER_HPP
#include <boost/process/v2/posix/default_launcher.hpp>
#include <unistd.h>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace posix
{
/// A launcher using `pipe_fork`. Default on FreeBSD
struct pipe_fork_launcher : default_launcher
{
/// The file descriptor of the subprocess. Set after fork.
pipe_fork_launcher() = default;
template<typename ExecutionContext, typename Args, typename ... Inits>
auto operator()(ExecutionContext & context,
const typename std::enable_if<is_convertible<
ExecutionContext&, net::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
{
error_code ec;
auto proc = (*this)(context, ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
v2::detail::throw_error(ec, "pipe_fork_launcher");
return proc;
}
template<typename ExecutionContext, typename Args, typename ... Inits>
auto operator()(ExecutionContext & context,
error_code & ec,
const typename std::enable_if<is_convertible<
ExecutionContext&, net::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
{
return (*this)(context.get_executor(), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
}
template<typename Executor, typename Args, typename ... Inits>
auto operator()(Executor exec,
const typename std::enable_if<
net::execution::is_executor<Executor>::value ||
net::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
error_code ec;
auto proc = (*this)(std::move(exec), ec, executable, std::forward<Args>(args), std::forward<Inits>(inits)...);
if (ec)
v2::detail::throw_error(ec, "pipe_fork_launcher");
return proc;
}
template<typename Executor, typename Args, typename ... Inits>
auto operator()(Executor exec,
error_code & ec,
const typename std::enable_if<
net::execution::is_executor<Executor>::value ||
net::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
auto argv = this->build_argv_(executable, std::forward<Args>(args));
int fd = -1;
{
pipe_guard pg, pg_wait;
if (::pipe(pg.p))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
return basic_process<Executor>{exec};
}
if (::fcntl(pg.p[1], F_SETFD, FD_CLOEXEC))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
return basic_process<Executor>{exec};
}
if (::pipe(pg_wait.p))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
return basic_process<Executor>{exec};
}
if (::fcntl(pg_wait.p[1], F_SETFD, FD_CLOEXEC))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
return basic_process<Executor>{exec};
}
ec = detail::on_setup(*this, executable, argv, inits ...);
if (ec)
{
detail::on_error(*this, executable, argv, ec, inits...);
return basic_process<Executor>(exec);
}
fd_whitelist.push_back(pg.p[1]);
fd_whitelist.push_back(pg_wait.p[1]);
auto & ctx = net::query(
exec, net::execution::context);
ctx.notify_fork(net::execution_context::fork_prepare);
pid = ::fork();
if (pid == -1)
{
ctx.notify_fork(net::execution_context::fork_parent);
detail::on_fork_error(*this, executable, argv, ec, inits...);
detail::on_error(*this, executable, argv, ec, inits...);
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
return basic_process<Executor>{exec};
}
else if (pid == 0)
{
ctx.notify_fork(net::execution_context::fork_child);
::close(pg.p[0]);
ec = detail::on_exec_setup(*this, executable, argv, inits...);
if (!ec)
{
close_all_fds(ec);
}
if (!ec)
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
default_launcher::ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category());
detail::on_exec_error(*this, executable, argv, ec, inits...);
::_exit(EXIT_FAILURE);
return basic_process<Executor>{exec};
}
ctx.notify_fork(net::execution_context::fork_parent);
::close(pg.p[1]);
pg.p[1] = -1;
::close(pg_wait.p[1]);
pg_wait.p[1] = -1;
int child_error{0};
int count = -1;
while ((count = ::read(pg.p[0], &child_error, sizeof(child_error))) == -1)
{
int err = errno;
if ((err != EAGAIN) && (err != EINTR))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category());
break;
}
}
if (count != 0)
BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category());
if (ec)
{
detail::on_error(*this, executable, argv, ec, inits...);
return basic_process<Executor>{exec};
}
std::swap(fd, pg_wait.p[0]);
}
basic_process<Executor> proc(exec, pid, fd);
detail::on_success(*this, executable, argv, ec, inits...);
return proc;
}
};
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_POSIX_PIPE_FORK_LAUNCHER_HPP

View File

@@ -20,12 +20,10 @@
#if defined(BOOST_PROCESS_V2_STANDALONE) #if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/any_io_executor.hpp> #include <asio/any_io_executor.hpp>
#include <boost/asio/dispatch.hpp>
#include <asio/post.hpp> #include <asio/post.hpp>
#include <utility> #include <utility>
#else #else
#include <boost/asio/any_io_executor.hpp> #include <boost/asio/any_io_executor.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <boost/core/exchange.hpp> #include <boost/core/exchange.hpp>
#endif #endif
@@ -233,7 +231,7 @@ struct basic_process
void resume() void resume()
{ {
error_code ec; error_code ec;
resume(ec); suspend(ec);
if (ec) if (ec)
detail::throw_error(ec, "resume"); detail::throw_error(ec, "resume");
} }
@@ -302,8 +300,6 @@ struct basic_process
*/ */
bool running() bool running()
{ {
if (!process_is_running(exit_status_))
return false;
error_code ec; error_code ec;
native_exit_code_type exit_code{}; native_exit_code_type exit_code{};
auto r = process_handle_.running(exit_code, ec); auto r = process_handle_.running(exit_code, ec);
@@ -318,8 +314,6 @@ struct basic_process
/// Throwing @overload bool running(error_code & ec) /// Throwing @overload bool running(error_code & ec)
bool running(error_code & ec) noexcept bool running(error_code & ec) noexcept
{ {
if (!process_is_running(exit_status_))
return false;
native_exit_code_type exit_code{}; native_exit_code_type exit_code{};
auto r = process_handle_.running(exit_code, ec); auto r = process_handle_.running(exit_code, ec);
if (!ec && !r) if (!ec && !r)
@@ -361,22 +355,23 @@ private:
} }
}; };
net::dispatch( net::post(handle.get_executor(),
net::get_associated_immediate_executor(handle, handle.get_executor()), completer{static_cast<int>(res), std::move(self)});
completer{static_cast<int>(res), std::move(self)});
} }
else else
handle.async_wait(res, std::move(self)); handle.async_wait(std::move(self));
} }
template<typename Self> template<typename Self>
void operator()(Self && self, error_code ec) void operator()(Self && self, error_code ec, native_exit_code_type code)
{ {
if (!ec && process_is_running(res)) if (!ec && process_is_running(code))
handle.async_wait(res, std::move(self)); handle.async_wait(std::move(self));
else else
{ {
std::move(self).complete(ec, evaluate_exit_code(res)); if (!ec)
res = code;
std::move(self).complete(ec, evaluate_exit_code(code));
} }
} }
}; };

View File

@@ -13,7 +13,7 @@
#if defined(BOOST_PROCESS_V2_PIDFD_OPEN) #if defined(BOOST_PROCESS_V2_PIDFD_OPEN)
#include <boost/process/v2/detail/process_handle_fd.hpp> #include <boost/process/v2/detail/process_handle_fd.hpp>
#elif defined(BOOST_PROCESS_V2_PDFORK) || defined(BOOST_PROCESS_V2_PIPEFORK) #elif defined(BOOST_PROCESS_V2_PDFORK)
#include <boost/process/v2/detail/process_handle_fd_or_signal.hpp> #include <boost/process/v2/detail/process_handle_fd_or_signal.hpp>
#else #else
// with asio support we could use EVFILT_PROC:NOTE_EXIT as well. // with asio support we could use EVFILT_PROC:NOTE_EXIT as well.
@@ -26,7 +26,7 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(GENERATING_DOCUMENTATION) #if defined(GENERATING_DOCUMENTATION)
/** A process handle is an unmanaged version of a process. /** A process handle is an unmanaged version of a process.
* This means it does not terminate the process on destruction and * This means it does not terminate the proces on destruction and
* will not keep track of the exit-code. * will not keep track of the exit-code.
* *
* Note that the exit code might be discovered early, during a call to `running`. * Note that the exit code might be discovered early, during a call to `running`.
@@ -107,9 +107,9 @@ struct basic_process_handle
void request_exit() void request_exit()
/// Unconditionally terminates the process and stores the exit code in exit_status. /// Unconditionally terminates the process and stores the exit code in exit_status.
void terminate(native_exit_code_type &exit_status, error_code &ec); void terminate(native_exit_code_type &exit_status, error_code &ec);\
/// Throwing @overload void terminate(native_exit_code_type &exit_code, error_code & ec) /// Throwing @overload void terminate(native_exit_code_type &exit_code, error_code & ec)
void terminate(native_exit_code_type &exit_status); void terminate(native_exit_code_type &exit_status);/
/// Checks if the current process is running. /// Checks if the current process is running.
/**If it has already completed, it assigns the exit code to `exit_code`. /**If it has already completed, it assigns the exit code to `exit_code`.
@@ -137,7 +137,7 @@ using basic_process_handle = detail::basic_process_handle_win<Executor>;
#if defined(BOOST_PROCESS_V2_PIDFD_OPEN) #if defined(BOOST_PROCESS_V2_PIDFD_OPEN)
template<typename Executor = net::any_io_executor> template<typename Executor = net::any_io_executor>
using basic_process_handle = detail::basic_process_handle_fd<Executor>; using basic_process_handle = detail::basic_process_handle_fd<Executor>;
#elif defined(BOOST_PROCESS_V2_PDFORK) || defined(BOOST_PROCESS_V2_PIPEFORK) #elif defined(BOOST_PROCESS_V2_PDFORK) || defined(BOOST_PROCESS_V2_PIPE_LAUNCHER)
template<typename Executor = net::any_io_executor> template<typename Executor = net::any_io_executor>
using basic_process_handle = detail::basic_process_handle_fd_or_signal<Executor>; using basic_process_handle = detail::basic_process_handle_fd_or_signal<Executor>;
#else #else

View File

@@ -31,33 +31,8 @@
#endif #endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE BOOST_PROCESS_V2_BEGIN_NAMESPACE
template<typename T>
struct is_readable_pipe : std::false_type
{
};
template<typename Executor>
struct is_readable_pipe<asio::basic_readable_pipe<Executor>> : std::true_type
{
};
template<typename T>
struct is_writable_pipe : std::false_type
{
};
template<typename Executor>
struct is_writable_pipe<asio::basic_writable_pipe<Executor>> : std::true_type
{
};
namespace detail namespace detail
{ {
#if defined(BOOST_PROCESS_V2_WINDOWS) #if defined(BOOST_PROCESS_V2_WINDOWS)
struct handle_closer struct handle_closer
@@ -129,10 +104,16 @@ struct process_io_binding
} }
template<typename ReadablePipe> template<typename Executor>
process_io_binding(ReadablePipe & pipe, process_io_binding(net::basic_readable_pipe<Executor> & pipe)
typename std::enable_if<is_readable_pipe<ReadablePipe>::value && Target != STD_INPUT_HANDLE>::type * = nullptr)
{ {
if (Target == STD_INPUT_HANDLE)
{
auto h_ = pipe.native_handle();
h = std::unique_ptr<void, handle_closer>{h_, get_flags(h_)};
return ;
}
net::detail::native_pipe_handle p[2]; net::detail::native_pipe_handle p[2];
error_code ec; error_code ec;
net::detail::create_pipe(p, ec); net::detail::create_pipe(p, ec);
@@ -144,10 +125,15 @@ struct process_io_binding
} }
template<typename WritablePipe> template<typename Executor>
process_io_binding(WritablePipe & pipe, process_io_binding(net::basic_writable_pipe<Executor> & pipe)
typename std::enable_if<is_writable_pipe<WritablePipe>::value && Target == STD_INPUT_HANDLE>::type * = nullptr)
{ {
if (Target != STD_INPUT_HANDLE)
{
auto h_ = pipe.native_handle();
h = std::unique_ptr<void, handle_closer>{h_, get_flags(h_)};
return ;
}
net::detail::native_pipe_handle p[2]; net::detail::native_pipe_handle p[2];
error_code ec; error_code ec;
net::detail::create_pipe(p, ec); net::detail::create_pipe(p, ec);
@@ -184,7 +170,7 @@ struct process_io_binding
process_io_binding & operator=(const process_io_binding &) = delete; process_io_binding & operator=(const process_io_binding &) = delete;
process_io_binding(process_io_binding && other) noexcept process_io_binding(process_io_binding && other) noexcept
: fd(other.fd), fd_needs_closing(other.fd_needs_closing), ec(other.ec) : fd(other.fd), fd_needs_closing(other.fd), ec(other.ec)
{ {
other.fd = target; other.fd = target;
other.fd_needs_closing = false; other.fd_needs_closing = false;
@@ -221,10 +207,15 @@ struct process_io_binding
{ {
} }
template<typename ReadablePipe> template<typename Executor>
process_io_binding(ReadablePipe & readable_pipe, process_io_binding(net::basic_readable_pipe<Executor> & readable_pipe)
typename std::enable_if<is_readable_pipe<ReadablePipe>::value && Target != STDIN_FILENO>::type * = nullptr)
{ {
if (Target == STDIN_FILENO)
{
fd = readable_pipe.native_handle();
return ;
}
net::detail::native_pipe_handle p[2]; net::detail::native_pipe_handle p[2];
net::detail::create_pipe(p, ec); net::detail::create_pipe(p, ec);
if (ec) if (ec)
@@ -241,10 +232,15 @@ struct process_io_binding
} }
template<typename WritablePipe> template<typename Executor>
process_io_binding(WritablePipe & writable_pipe, process_io_binding(net::basic_writable_pipe<Executor> & writable_pipe)
typename std::enable_if<is_writable_pipe<WritablePipe>::value && Target == STDIN_FILENO>::type * = nullptr)
{ {
if (Target != STDIN_FILENO)
{
fd = writable_pipe.native_handle();
return ;
}
net::detail::native_pipe_handle p[2]; net::detail::native_pipe_handle p[2];
error_code ec; error_code ec;
net::detail::create_pipe(p, ec); net::detail::create_pipe(p, ec);
@@ -267,7 +263,7 @@ struct process_io_binding
return ec; return ec;
} }
error_code on_exec_setup(posix::default_launcher &, error_code on_exec_setup(posix::default_launcher & launcher,
const filesystem::path &, const char * const *) const filesystem::path &, const char * const *)
{ {
if (::dup2(fd, target) == -1) if (::dup2(fd, target) == -1)
@@ -308,7 +304,7 @@ typedef process_io_binding<STDERR_FILENO> process_error_binding;
* * @code {.cpp} * * @code {.cpp}
* asio::io_context ctx; * asio::io_context ctx;
* /// C++17 * /// C++17
* v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{.err=nullptr}); * v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{.stderr=nullptr});
* /// C++11 & C++14 * /// C++11 & C++14
* v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{ {}, {}, nullptr}); * v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{ {}, {}, nullptr});
* stdin ^ ^ stderr * stdin ^ ^ stderr

View File

@@ -109,7 +109,7 @@ inline std::false_type probe_on_error(
template<typename Launcher, typename Init> template<typename Launcher, typename Init>
inline auto probe_on_error(Launcher & launcher, Init && init, derived && ) inline auto probe_on_error(Launcher & launcher, Init && init, derived && )
-> std::is_same<error_code, decltype(init.on_error(launcher, std::declval<const filesystem::path &>(), std::declval<std::wstring &>(), std::declval<error_code&>()))>; -> std::is_same<error_code, decltype(init.on_error(launcher, std::declval<const filesystem::path &>(), std::declval<std::wstring &>(), std::declval<std::error_code&>()))>;
template<typename Launcher, typename Init> template<typename Launcher, typename Init>
using has_on_error = decltype(probe_on_error(std::declval<Launcher&>(), std::declval<Init>(), derived{})); using has_on_error = decltype(probe_on_error(std::declval<Launcher&>(), std::declval<Init>(), derived{}));
@@ -225,9 +225,6 @@ struct default_launcher
INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE}, INVALID_HANDLE_VALUE},
nullptr}; nullptr};
/// Allow batch files to be executed, which might pose a security threat.
bool allow_batch_files = false;
/// The process_information that gets assigned after a call to CreateProcess /// The process_information that gets assigned after a call to CreateProcess
PROCESS_INFORMATION process_information{nullptr, nullptr, 0,0}; PROCESS_INFORMATION process_information{nullptr, nullptr, 0,0};
@@ -296,12 +293,6 @@ struct default_launcher
Args && args, Args && args,
Inits && ... inits ) -> enable_init<Executor, Inits...> Inits && ... inits ) -> enable_init<Executor, Inits...>
{ {
if (!allow_batch_files && ((executable.extension() == ".bat") || (executable.extension() == ".cmd")))
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_ACCESS_DENIED, system_category());
return basic_process<Executor>(exec);
}
auto command_line = this->build_command_line(executable, std::forward<Args>(args)); auto command_line = this->build_command_line(executable, std::forward<Args>(args));
ec = detail::on_setup(*this, executable, command_line, inits...); ec = detail::on_setup(*this, executable, command_line, inits...);
@@ -361,6 +352,7 @@ struct default_launcher
BOOST_PROCESS_V2_DECL static BOOST_PROCESS_V2_DECL static
std::size_t escape_argv_string(wchar_t * itr, std::size_t max_size, std::size_t escape_argv_string(wchar_t * itr, std::size_t max_size,
basic_string_view<wchar_t> ws); basic_string_view<wchar_t> ws);
@@ -403,7 +395,6 @@ struct default_launcher
{ {
return detail::conv_string<wchar_t>(arg.data(), arg.size()); return detail::conv_string<wchar_t>(arg.data(), arg.size());
}); });
return build_command_line_impl(pt, argw, L""); return build_command_line_impl(pt, argw, L"");
} }
@@ -412,14 +403,8 @@ struct default_launcher
static std::wstring build_command_line(const filesystem::path & pt, const Args & args) static std::wstring build_command_line(const filesystem::path & pt, const Args & args)
{ {
if (std::begin(args) == std::end(args)) if (std::begin(args) == std::end(args))
{ return pt.native();
std::wstring buffer;
buffer.resize(escaped_argv_length(pt.native()));
if (!buffer.empty())
escape_argv_string(&buffer.front(), buffer.size(), pt.native());
return buffer;
}
return build_command_line_impl(pt, args, *std::begin(args)); return build_command_line_impl(pt, args, *std::begin(args));
} }
@@ -448,4 +433,4 @@ BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP #endif //BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP

View File

@@ -10,7 +10,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=doc/html/index.html"> <meta http-equiv="refresh" content="0; url=../../doc/html/process.html">
<title>Boost.Process</title> <title>Boost.Process</title>
<style> <style>
body { body {
@@ -26,7 +26,7 @@
<body> <body>
<p> <p>
Automatic redirection failed, please go to Automatic redirection failed, please go to
<a href="doc/html/index.html">doc/html/index.html</a> <a href="../../doc/html/process.html">../../doc/html/process.html</a>
</p> </p>
<p> <p>
&copy; 2016 Klemens D. Morgenstern &copy; 2016 Klemens D. Morgenstern

View File

@@ -51,7 +51,7 @@ void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_c
} }
native_handle_type load_native_handle() { return environ; } native_handle_type load_native_handle() { return ::environ; }
native_iterator next(native_iterator nh) native_iterator next(native_iterator nh)

View File

@@ -54,8 +54,6 @@ std::size_t size_as_utf8(const wchar_t * in, std::size_t size, error_code & ec)
std::size_t size_as_wide(const char * in, std::size_t size, error_code & ec) std::size_t size_as_wide(const char * in, std::size_t size, error_code & ec)
{ {
if (size == 0u)
return 0u;
auto res = ::MultiByteToWideChar( auto res = ::MultiByteToWideChar(
CP_UTF8, // CodePage CP_UTF8, // CodePage
0, // dwFlags 0, // dwFlags
@@ -90,8 +88,6 @@ std::size_t convert_to_utf8(const wchar_t *in, std::size_t size, char * out,
std::size_t convert_to_wide(const char *in, std::size_t size, wchar_t * out, std::size_t convert_to_wide(const char *in, std::size_t size, wchar_t * out,
std::size_t max_size, error_code & ec) std::size_t max_size, error_code & ec)
{ {
if (size == 0u)
return 0u;
auto res = ::MultiByteToWideChar( auto res = ::MultiByteToWideChar(
CP_UTF8, // CodePage CP_UTF8, // CodePage
0, // dwFlags 0, // dwFlags
@@ -214,8 +210,10 @@ std::size_t size_as_wide(const char * in, std::size_t size, error_code &)
const auto from = in; const auto from = in;
const auto from_end = from + size; const auto from_end = from + size;
const char * from_next = from; const char * from_next = from;
std::size_t char_count = 0u;
while (from_next < from_end) while (from_next < from_end)
{ {
++char_count;
unsigned int octet_count = get_octet_count(*from_next); unsigned int octet_count = get_octet_count(*from_next);
// The buffer may represent incomplete characters, so terminate early if one is found // The buffer may represent incomplete characters, so terminate early if one is found
if (octet_count > static_cast<std::size_t>(from_end - from_next)) if (octet_count > static_cast<std::size_t>(from_end - from_next))

View File

@@ -17,7 +17,7 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(BOOST_PROCESS_V2_WINDOWS) #if defined(BOOST_PROCESS_V2_WINDOWS)
error_code process_environment::do_setup(windows::default_launcher & launcher) error_code process_environment::on_setup(windows::default_launcher & launcher, const filesystem::path &, const std::wstring &)
{ {
if (!unicode_env.empty() && !ec) if (!unicode_env.empty() && !ec)
{ {
@@ -30,7 +30,7 @@ error_code process_environment::do_setup(windows::default_launcher & launcher)
#else #else
error_code process_environment::do_setup(posix::default_launcher & launcher) error_code process_environment::on_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *)
{ {
launcher.env = env.data(); launcher.env = env.data();
return error_code{}; return error_code{};

View File

@@ -100,7 +100,7 @@ struct exit_code_category final : public error_category
# if defined(SIGILL) # if defined(SIGILL)
case SIGILL: return "SIGILL: Illegal Instruction"; case SIGILL: return "SIGILL: Illegal Instruction";
# endif # endif
# if defined(SIGINFO) && SIGINFO != SIGPWR # if defined(SIGINFO)
case SIGINFO: return "SIGINFO: A synonym for SIGPWR"; case SIGINFO: return "SIGINFO: A synonym for SIGPWR";
# endif # endif
# if defined(SIGINT) # if defined(SIGINT)

View File

@@ -31,7 +31,7 @@
#endif #endif
#endif #endif
#if (defined(__linux__) || defined(__ANDROID__) || defined(__gnu_hurd__)) #if (defined(__linux__) || defined(__ANDROID__))
#include <cstdio> #include <cstdio>
#endif #endif
@@ -211,7 +211,7 @@ shell cmd(boost::process::v2::pid_type pid, error_code & ec)
return make_cmd_shell_::make(std::move(procargs), argc, argv.release(), fr_func); return make_cmd_shell_::make(std::move(procargs), argc, argv.release(), fr_func);
} }
#elif (defined(__linux__) || defined(__ANDROID__) || defined(__gnu_hurd__)) #elif (defined(__linux__) || defined(__ANDROID__))
shell cmd(boost::process::v2::pid_type pid, error_code & ec) shell cmd(boost::process::v2::pid_type pid, error_code & ec)
{ {
@@ -403,10 +403,10 @@ shell cmd(boost::process::v2::pid_type pid, error_code & ec)
} }
#else #else
shell cmd(boost::process::v2::pid_type, error_code & ec) filesystem::path cmd(boost::process::v2::pid_type, error_code & ec)
{ {
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category()); BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category());
return {}; return "";
} }
#endif #endif

View File

@@ -124,7 +124,7 @@ filesystem::path cwd(boost::process::v2::pid_type pid, error_code & ec)
filesystem::path("/proc") / std::to_string(pid) / "cwd", ec filesystem::path("/proc") / std::to_string(pid) / "cwd", ec
); );
#elif defined(__sun) #elif defined(__sun)
return filesystem::canonical( return fileystem::canonical(
filesystem::path("/proc") / std::to_string(pid) / "path/cwd", ec filesystem::path("/proc") / std::to_string(pid) / "path/cwd", ec
); );
#endif #endif

View File

@@ -246,7 +246,7 @@ env_view env(boost::process::v2::pid_type pid, error_code & ec)
return {}; return {};
} }
#elif (defined(__APPLE__) && defined(__MACH__)) && !TARGET_OS_IOS #elif (defined(__APPLE___) || defined(__MACH__)) && !TARGET_OS_IOS
env_view env(boost::process::v2::pid_type pid, error_code & ec) env_view env(boost::process::v2::pid_type pid, error_code & ec)
{ {
@@ -309,7 +309,7 @@ env_view env(boost::process::v2::pid_type pid, error_code & ec)
return ev; return ev;
} }
#elif (defined(__linux__) || defined(__ANDROID__)) || defined(__gnu_hurd__) #elif (defined(__linux__) || defined(__ANDROID__))
env_view env(boost::process::v2::pid_type pid, error_code & ec) env_view env(boost::process::v2::pid_type pid, error_code & ec)
{ {

View File

@@ -141,7 +141,7 @@ filesystem::path exe(boost::process::v2::pid_type pid, error_code & ec)
filesystem::path("/proc") / std::to_string(pid) / "exe", ec filesystem::path("/proc") / std::to_string(pid) / "exe", ec
); );
#elif defined(__sun) #elif defined(__sun)
return filesystem::canonical( return fileystem::canonical(
filesystem::path("/proc") / std::to_string(pid) / "path/a.out", ec filesystem::path("/proc") / std::to_string(pid) / "path/a.out", ec
); );
#endif #endif

View File

@@ -179,6 +179,7 @@ std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
{ {
std::vector<pid_type> vec; std::vector<pid_type> vec;
#if defined(PROC_PPID_ONLY) #if defined(PROC_PPID_ONLY)
vec.resize(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0) / sizeof(pid_type)); vec.resize(proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, nullptr, 0) / sizeof(pid_type));
const auto sz = proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, &vec[0], sizeof(pid_type) * vec.size()); const auto sz = proc_listpids(PROC_PPID_ONLY, (uint32_t)pid, &vec[0], sizeof(pid_type) * vec.size());
if (sz < 0) if (sz < 0)
@@ -188,14 +189,7 @@ std::vector<pid_type> child_pids(pid_type pid, error_code & ec)
} }
vec.resize(sz); vec.resize(sz);
#else #else
std::vector<pid_type> pids = all_pids(ec); BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category());
for (std::size_t i = 0; i < pids.size(); i++)
{
if (pid == parent_pid(pids[i], ec))
{
vec.push_back(pids[i]);
}
}
#endif #endif
return vec; return vec;
} }

View File

@@ -185,7 +185,7 @@ void close_all(const std::vector<int> & whitelist, error_code & ec)
return ; return ;
} }
auto dir_fd = dirfd(dir.get()); auto dir_fd = ::dirfd(dir.get());
if (dir_fd == -1) if (dir_fd == -1)
{ {
ec = BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error(); ec = BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();

View File

@@ -24,72 +24,54 @@ namespace windows
if (ws.empty()) if (ws.empty())
return 2u; // just quotes return 2u; // just quotes
constexpr static auto space = L' ';
constexpr static auto quote = L'"'; constexpr static auto quote = L'"';
const auto needs_quotes = ws.find_first_of(L" \t") != basic_string_view<wchar_t>::npos;
std::size_t needed_escapes = 0u; const auto has_space = ws.find(space) != basic_string_view<wchar_t>::npos;
for (auto itr = ws.begin(); itr != ws.end(); itr ++) const auto quoted = (ws.front() == quote) && (ws.back() == quote);
{ const auto needs_escape = has_space && !quoted ;
if (*itr == quote)
needed_escapes++; if (!needs_escape)
else if (*itr == L'\\') return ws.size();
{ else
auto nx = std::next(itr); return ws.size() + std::count(ws.begin(), ws.end(), quote) + 2u;
if (nx != ws.end() && *nx == L'"')
needed_escapes ++;
else if (nx == ws.end())
needed_escapes ++;
}
}
return ws.size() + needed_escapes + (needs_quotes ? 2u : 0u);
} }
std::size_t default_launcher::escape_argv_string(wchar_t * itr, std::size_t max_size, std::size_t default_launcher::escape_argv_string(wchar_t * itr, std::size_t max_size,
basic_string_view<wchar_t> ws) basic_string_view<wchar_t> ws)
{ {
constexpr static auto quote = L'"'; const auto sz = escaped_argv_length(ws);
const auto needs_quotes = ws.find_first_of(L" \t") != basic_string_view<wchar_t>::npos;
const auto needed_escapes = std::count(ws.begin(), ws.end(), quote);
const auto sz = ws.size() + needed_escapes + (needs_quotes ? 2u : 0u);
if (sz > max_size) if (sz > max_size)
return 0u; return 0u;
if (ws.empty()) if (ws.empty())
{ {
itr[0] = quote; itr[0] = L'"';
itr[1] = quote; itr[1] = L'"';
return 2u; return 2u;
} }
const auto has_space = ws.find(L' ') != basic_string_view<wchar_t>::npos;
const auto quoted = (ws.front() == L'"') && (ws.back() == L'"');
const auto needs_escape = has_space && !quoted;
if (!needs_escape)
return std::copy(ws.begin(), ws.end(), itr) - itr;
if (sz < (2u + ws.size()))
return 0u;
const auto end = itr + sz; const auto end = itr + sz;
const auto begin = itr; const auto begin = itr;
if (needs_quotes) *(itr ++) = L'"';
*(itr++) = quote; for (auto wc : ws)
for (auto it = ws.begin(); it != ws.end(); it ++)
{ {
if (*it == quote) // makes it \" if (wc == L'"')
*(itr++) = L'\\'; *(itr++) = L'\\';
*(itr++) = wc;
if (*it == L'\\') // \" needs to become \\\"
{
auto nx = std::next(it);
if (nx != ws.end() && *nx == L'"')
*(itr++) = L'\\';
else if (nx == ws.end())
*(itr++) = L'\\';
}
*(itr++) = *it;
} }
if (needs_quotes) *(itr ++) = L'"';
*(itr++) = quote;
return itr - begin; return itr - begin;
} }
@@ -126,18 +108,13 @@ namespace windows
auto tl = get_thread_attribute_list(ec); auto tl = get_thread_attribute_list(ec);
if (ec) if (ec)
return; return;
auto itr = std::unique(inherited_handles.begin(), inherited_handles.end());
auto size = std::distance(inherited_handles.begin(), itr);
if (!::UpdateProcThreadAttribute( if (!::UpdateProcThreadAttribute(
tl, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, tl, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
inherited_handles.data(), size * sizeof(HANDLE), nullptr, nullptr)) inherited_handles.data(), inherited_handles.size() * sizeof(HANDLE), nullptr, nullptr))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec); BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
} }
} }
BOOST_PROCESS_V2_END_NAMESPACE BOOST_PROCESS_V2_END_NAMESPACE
#endif #endif

View File

@@ -21,7 +21,9 @@
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
namespace bp = boost::process::v1; namespace bp = boost::process;
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(args, *boost::unit_test::timeout(2)) BOOST_AUTO_TEST_CASE(args, *boost::unit_test::timeout(2))
{ {

View File

@@ -19,7 +19,7 @@
#include <boost/process/v1/error.hpp> #include <boost/process/v1/error.hpp>
#include <boost/process/v1/child.hpp> #include <boost/process/v1/child.hpp>
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(implicit_args_fs_path) BOOST_AUTO_TEST_CASE(implicit_args_fs_path)

View File

@@ -3,34 +3,11 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_ASIO_NO_DEPRECATED 1 #define BOOST_ASIO_NO_DEPRECATED 1
#include <boost/process/v1/args.hpp> #include <boost/process.hpp>
#include <boost/process/v1/async.hpp>
#include <boost/process/v1/async_pipe.hpp>
#include <boost/process/v1/async_system.hpp>
#include <boost/process/v1/child.hpp>
#include <boost/process/v1/cmd.hpp>
#include <boost/process/v1/env.hpp>
#include <boost/process/v1/environment.hpp>
#include <boost/process/v1/error.hpp>
#include <boost/process/v1/exception.hpp>
#include <boost/process/v1/exe.hpp>
#include <boost/process/v1/extend.hpp>
#include <boost/process/v1/filesystem.hpp>
#include <boost/process/v1/group.hpp>
#include <boost/process/v1/handles.hpp>
#include <boost/process/v1/io.hpp>
#include <boost/process/v1/locale.hpp>
#include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/search_path.hpp>
#include <boost/process/v1/shell.hpp>
#include <boost/process/v1/spawn.hpp>
#include <boost/process/v1/start_dir.hpp>
#include <boost/process/v1/system.hpp>
int main() {} int main() {}
#if defined(BOOST_POSIX_API) #if defined(BOOST_POSIX_API)
#include <boost/process/v1/posix.hpp> #include <boost/process/v1/posix.hpp>
#else #else
#include <boost/process/v1/windows.hpp> #include <boost/process/v1/windows.hpp>
#endif #endif

View File

@@ -25,7 +25,7 @@
using namespace std; using namespace std;
namespace bp = boost::process::v1; namespace bp = boost::process;
#if __APPLE__ #if __APPLE__
auto abort_sig = signal(SIGALRM, +[](int){std::terminate();}); auto abort_sig = signal(SIGALRM, +[](int){std::terminate();});

View File

@@ -29,7 +29,7 @@ BOOST_AUTO_TEST_SUITE( async );
using namespace std; using namespace std;
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(async_out_future, *boost::unit_test::timeout(2)) BOOST_AUTO_TEST_CASE(async_out_future, *boost::unit_test::timeout(2))
{ {
@@ -103,4 +103,4 @@ BOOST_AUTO_TEST_CASE(emtpy_out, *boost::unit_test::timeout(2))
BOOST_CHECK_EQUAL(fut.get(), ""); BOOST_CHECK_EQUAL(fut.get(), "");
} }
BOOST_AUTO_TEST_SUITE_END(); BOOST_AUTO_TEST_SUITE_END();

View File

@@ -20,7 +20,7 @@
#include <boost/asio/streambuf.hpp> #include <boost/asio/streambuf.hpp>
using namespace std; using namespace std;
namespace bp = boost::process::v1; namespace bp = boost::process;
namespace asio = boost::asio; namespace asio = boost::asio;
BOOST_AUTO_TEST_SUITE( async ); BOOST_AUTO_TEST_SUITE( async );

View File

@@ -18,7 +18,7 @@
#include <boost/process/v1/async_system.hpp> #include <boost/process/v1/async_system.hpp>
#include <system_error> #include <system_error>
namespace bp = boost::process::v1; namespace bp = boost::process;;
void fail_func() void fail_func()
{ {

View File

@@ -23,7 +23,7 @@
#include <vector> #include <vector>
#include <array> #include <array>
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( async ); BOOST_AUTO_TEST_SUITE( async );
BOOST_AUTO_TEST_CASE(future, *boost::unit_test::timeout(15)) BOOST_AUTO_TEST_CASE(future, *boost::unit_test::timeout(15))

View File

@@ -27,7 +27,7 @@
#include <array> #include <array>
BOOST_AUTO_TEST_SUITE( async ); BOOST_AUTO_TEST_SUITE( async );
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15)) BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15))
{ {
using boost::unit_test::framework::master_test_suite; using boost::unit_test::framework::master_test_suite;

View File

@@ -26,7 +26,7 @@
#include <array> #include <array>
BOOST_AUTO_TEST_SUITE( async ); BOOST_AUTO_TEST_SUITE( async );
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15)) BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15))
{ {
using boost::unit_test::framework::master_test_suite; using boost::unit_test::framework::master_test_suite;

View File

@@ -26,7 +26,7 @@
#include <array> #include <array>
BOOST_AUTO_TEST_SUITE( async ); BOOST_AUTO_TEST_SUITE( async );
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(stackful_except, *boost::unit_test::timeout(15)) BOOST_AUTO_TEST_CASE(stackful_except, *boost::unit_test::timeout(15))
{ {
using boost::unit_test::framework::master_test_suite; using boost::unit_test::framework::master_test_suite;

View File

@@ -25,7 +25,7 @@
#include <array> #include <array>
BOOST_AUTO_TEST_SUITE( async ); BOOST_AUTO_TEST_SUITE( async );
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(stackless, *boost::unit_test::timeout(15)) BOOST_AUTO_TEST_CASE(stackless, *boost::unit_test::timeout(15))
{ {
using boost::unit_test::framework::master_test_suite; using boost::unit_test::framework::master_test_suite;

View File

@@ -39,7 +39,7 @@ typedef boost::asio::posix::stream_descriptor pipe_end;
#endif #endif
namespace fs = boost::process::v1::filesystem; namespace fs = boost::process::v1::filesystem;
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( bind_stderr ); BOOST_AUTO_TEST_SUITE( bind_stderr );
BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(2)) BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(2))

View File

@@ -43,7 +43,7 @@ typedef boost::asio::posix::stream_descriptor pipe_end;
namespace fs = boost::process::v1::filesystem; namespace fs = boost::process::v1::filesystem;
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(10)) BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(10))
{ {

View File

@@ -22,7 +22,7 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( bind_stdin_stdout ); BOOST_AUTO_TEST_SUITE( bind_stdin_stdout );
BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(10)) BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(10))

View File

@@ -42,7 +42,7 @@ BOOST_AUTO_TEST_SUITE( bind_stdout );
namespace fs = boost::process::v1::filesystem; namespace fs = boost::process::v1::filesystem;
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(5)) BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(5))
{ {

View File

@@ -34,7 +34,7 @@ typedef boost::asio::windows::stream_handle pipe_end;
typedef boost::asio::posix::stream_descriptor pipe_end; typedef boost::asio::posix::stream_descriptor pipe_end;
#endif #endif
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( bind_stdout_stderr ); BOOST_AUTO_TEST_SUITE( bind_stdout_stderr );

View File

@@ -22,7 +22,7 @@
# include <sys/wait.h> # include <sys/wait.h>
#endif #endif
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(close_stderr) BOOST_AUTO_TEST_CASE(close_stderr)

View File

@@ -22,7 +22,7 @@
# include <sys/wait.h> # include <sys/wait.h>
#endif #endif
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(close_stdin) BOOST_AUTO_TEST_CASE(close_stdin)
{ {

View File

@@ -22,7 +22,7 @@
# include <sys/wait.h> # include <sys/wait.h>
#endif #endif
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(close_stdout) BOOST_AUTO_TEST_CASE(close_stdout)
{ {

View File

@@ -26,7 +26,7 @@
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <cstdlib> #include <cstdlib>
namespace bp = boost::process::v1; namespace bp = boost::process;
namespace fs = boost::process::v1::filesystem; namespace fs = boost::process::v1::filesystem;

View File

@@ -27,7 +27,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <list> #include <list>
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(inherit_env, *boost::unit_test::timeout(2)) BOOST_AUTO_TEST_CASE(inherit_env, *boost::unit_test::timeout(2))
{ {

View File

@@ -12,7 +12,7 @@
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <boost/process/v1/environment.hpp> #include <boost/process/v1/environment.hpp>
namespace bp = boost::process::v1; namespace bp = boost::process;
namespace std namespace std

View File

@@ -19,7 +19,7 @@
namespace bp = boost::process::v1; namespace bp = boost::process;
struct err_set struct err_set
{ {

View File

@@ -26,7 +26,7 @@ typedef boost::asio::windows::stream_handle pipe_end;
typedef boost::asio::posix::stream_descriptor pipe_end; typedef boost::asio::posix::stream_descriptor pipe_end;
#endif #endif
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(sync_wait, *boost::unit_test::timeout(10)) BOOST_AUTO_TEST_CASE(sync_wait, *boost::unit_test::timeout(10))
{ {

View File

@@ -17,7 +17,7 @@
#include <boost/process/v1/extend.hpp> #include <boost/process/v1/extend.hpp>
namespace bp = boost::process::v1; namespace bp = boost::process;
struct run_exe struct run_exe

View File

@@ -29,7 +29,7 @@
#include <iostream> #include <iostream>
#include <cstdlib> #include <cstdlib>
namespace bp = boost::process::v1; namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(group_test, *boost::unit_test::timeout(5)) BOOST_AUTO_TEST_CASE(group_test, *boost::unit_test::timeout(5))
{ {

View File

@@ -30,7 +30,7 @@
#include <iostream> #include <iostream>
#include <cstdlib> #include <cstdlib>
namespace bp = boost::process::v1; namespace bp = boost::process;

View File

@@ -7,7 +7,9 @@
#define BOOST_TEST_IGNORE_SIGCHLD #define BOOST_TEST_IGNORE_SIGCHLD
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <boost/process/v1/system.hpp> #include <iostream>
#include <boost/process.hpp>
#include <boost/process/v1/handles.hpp> #include <boost/process/v1/handles.hpp>
#include <boost/process/v1/pipe.hpp> #include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/io.hpp> #include <boost/process/v1/io.hpp>
@@ -30,7 +32,8 @@
#include <dirent.h> #include <dirent.h>
#endif #endif
namespace bp = boost::process::v1; namespace fs = boost::process::v1::filesystem;
namespace bp = boost::process;
namespace bt = boost::this_process; namespace bt = boost::this_process;
BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5)) BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5))
@@ -107,7 +110,7 @@ BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5))
BOOST_CHECK(!bt::is_stream_handle(event_fd , ec)); BOOST_CHECK_MESSAGE(!ec, ec.message()); BOOST_CHECK(!bt::is_stream_handle(event_fd , ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
#endif #endif
auto od = ::opendir("."); auto od = ::opendir(".");
int dir_fd = dirfd(od); int dir_fd = ::dirfd(od);
BOOST_CHECK(!bt::is_stream_handle(dir_fd , ec)); BOOST_CHECK_MESSAGE(!ec, ec.message()); BOOST_CHECK(!bt::is_stream_handle(dir_fd , ec)); BOOST_CHECK_MESSAGE(!ec, ec.message());
#endif #endif

View File

@@ -4,32 +4,4 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/process/v1/args.hpp> #include <boost/process.hpp>
#include <boost/process/v1/async.hpp>
#include <boost/process/v1/async_pipe.hpp>
#include <boost/process/v1/async_system.hpp>
#include <boost/process/v1/child.hpp>
#include <boost/process/v1/cmd.hpp>
#include <boost/process/v1/env.hpp>
#include <boost/process/v1/environment.hpp>
#include <boost/process/v1/error.hpp>
#include <boost/process/v1/exception.hpp>
#include <boost/process/v1/exe.hpp>
#include <boost/process/v1/extend.hpp>
#include <boost/process/v1/filesystem.hpp>
#include <boost/process/v1/group.hpp>
#include <boost/process/v1/handles.hpp>
#include <boost/process/v1/io.hpp>
#include <boost/process/v1/locale.hpp>
#include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/search_path.hpp>
#include <boost/process/v1/shell.hpp>
#include <boost/process/v1/spawn.hpp>
#include <boost/process/v1/start_dir.hpp>
#include <boost/process/v1/system.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/v1/posix.hpp>
#else
#include <boost/process/v1/windows.hpp>
#endif

View File

@@ -3,32 +3,4 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/process/v1/args.hpp> #include <boost/process.hpp>
#include <boost/process/v1/async.hpp>
#include <boost/process/v1/async_pipe.hpp>
#include <boost/process/v1/async_system.hpp>
#include <boost/process/v1/child.hpp>
#include <boost/process/v1/cmd.hpp>
#include <boost/process/v1/env.hpp>
#include <boost/process/v1/environment.hpp>
#include <boost/process/v1/error.hpp>
#include <boost/process/v1/exception.hpp>
#include <boost/process/v1/exe.hpp>
#include <boost/process/v1/extend.hpp>
#include <boost/process/v1/filesystem.hpp>
#include <boost/process/v1/group.hpp>
#include <boost/process/v1/handles.hpp>
#include <boost/process/v1/io.hpp>
#include <boost/process/v1/locale.hpp>
#include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/search_path.hpp>
#include <boost/process/v1/shell.hpp>
#include <boost/process/v1/spawn.hpp>
#include <boost/process/v1/start_dir.hpp>
#include <boost/process/v1/system.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/v1/posix.hpp>
#else
#include <boost/process/v1/windows.hpp>
#endif

View File

@@ -6,30 +6,5 @@
#include <boost/system/api_config.hpp> #include <boost/system/api_config.hpp>
#if defined(BOOST_WINDOWS_API) #if defined(BOOST_WINDOWS_API)
#define BOOST_NO_ANSI_APIS 1 #define BOOST_NO_ANSI_APIS 1
#include <boost/process/v1/args.hpp>
#include <boost/process/v1/async.hpp>
#include <boost/process/v1/async_pipe.hpp>
#include <boost/process/v1/async_system.hpp>
#include <boost/process/v1/child.hpp>
#include <boost/process/v1/cmd.hpp>
#include <boost/process/v1/env.hpp>
#include <boost/process/v1/environment.hpp>
#include <boost/process/v1/error.hpp>
#include <boost/process/v1/exception.hpp>
#include <boost/process/v1/exe.hpp>
#include <boost/process/v1/extend.hpp>
#include <boost/process/v1/filesystem.hpp>
#include <boost/process/v1/group.hpp>
#include <boost/process/v1/handles.hpp>
#include <boost/process/v1/io.hpp>
#include <boost/process/v1/locale.hpp>
#include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/search_path.hpp>
#include <boost/process/v1/shell.hpp>
#include <boost/process/v1/spawn.hpp>
#include <boost/process/v1/start_dir.hpp>
#include <boost/process/v1/system.hpp>
#include <boost/process/v1/windows.hpp>
#endif #endif
#include <boost/process.hpp>
int main() {}

View File

@@ -10,8 +10,7 @@
#define BOOST_TEST_MAIN #define BOOST_TEST_MAIN
#define BOOST_TEST_IGNORE_SIGCHLD #define BOOST_TEST_IGNORE_SIGCHLD
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <boost/process/v1/async.hpp> #include <boost/process.hpp>
#include <boost/process/v1/child.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
@@ -27,7 +26,7 @@ BOOST_AUTO_TEST_CASE(single_ios, *boost::unit_test::timeout(6))
return; return;
} }
namespace bp = boost::process::v1; namespace bp = boost::process;
boost::asio::io_context ios; boost::asio::io_context ios;
std::chrono::steady_clock::time_point p1, p2; std::chrono::steady_clock::time_point p1, p2;

View File

@@ -10,8 +10,7 @@
#define BOOST_TEST_MAIN #define BOOST_TEST_MAIN
#define BOOST_TEST_IGNORE_SIGCHLD #define BOOST_TEST_IGNORE_SIGCHLD
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <boost/process/v1/async.hpp> #include <boost/process.hpp>
#include <boost/process/v1/child.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
@@ -27,7 +26,7 @@ BOOST_AUTO_TEST_CASE(double_ios, *boost::unit_test::timeout(6))
return; return;
} }
namespace bp = boost::process::v1; namespace bp = boost::process;
boost::asio::io_context ios; boost::asio::io_context ios;
std::chrono::steady_clock::time_point p1, p2; std::chrono::steady_clock::time_point p1, p2;

View File

@@ -10,8 +10,7 @@
#define BOOST_TEST_MAIN #define BOOST_TEST_MAIN
#define BOOST_TEST_IGNORE_SIGCHLD #define BOOST_TEST_IGNORE_SIGCHLD
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
#include <boost/process/v1/async.hpp> #include <boost/process.hpp>
#include <boost/process/v1/child.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
@@ -27,7 +26,7 @@ BOOST_AUTO_TEST_CASE(double_ios_threaded, *boost::unit_test::timeout(6))
return; return;
} }
namespace bp = boost::process::v1; namespace bp = boost::process;
boost::asio::io_context ios; boost::asio::io_context ios;
std::chrono::steady_clock::time_point p1, p2; std::chrono::steady_clock::time_point p1, p2;

Some files were not shown because too many files have changed in this diff Show More