mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 04:42:24 +00:00
Compare commits
16 Commits
boost-1.82
...
group-v2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
deeb975c33 | ||
|
|
dcee0936c1 | ||
|
|
4cc469b2a4 | ||
|
|
6e4d1e29d2 | ||
|
|
dada865fd0 | ||
|
|
380dd1b00f | ||
|
|
7832cb6af3 | ||
|
|
68f4c50be9 | ||
|
|
cd226a7616 | ||
|
|
4243ce72f8 | ||
|
|
9065833e61 | ||
|
|
7cb7af6c8b | ||
|
|
90cbe7cec0 | ||
|
|
df33c1ad7b | ||
|
|
bbabea30dd | ||
|
|
8a61f8daa3 |
15
.drone.star
15
.drone.star
@@ -14,18 +14,17 @@ windowsglobalimage="cppalliance/dronevs2019"
|
||||
|
||||
def main(ctx):
|
||||
return [
|
||||
freebsd_cxx("gcc 11 freebsd", "g++-11", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '17,20', 'B2_LINKFLAGS': '-Wl,-rpath=/usr/local/lib/gcc11'}, globalenv=globalenv),
|
||||
freebsd_cxx("clang 14 freebsd", "clang++-14", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'clang-14', 'B2_CXXSTD': '17,20'}, globalenv=globalenv),
|
||||
linux_cxx("docs", "", packages="docbook docbook-xml docbook-xsl xsltproc libsaxonhe-java default-jre-headless flex libfl-dev bison unzip rsync", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv),
|
||||
#freebsd_cxx("FreeBSD", "g++10", packages="g++10", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv),
|
||||
linux_cxx("docs", "", packages="docbook docbook-xml docbook-xsl xsltproc libsaxonhe-java default-jre-headless flex libfl-dev bison unzip rsync mlocate", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv),
|
||||
linux_cxx("asan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_ASAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'DRONE_EXTRA_PRIVILEGED': 'True', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv, privileged=True),
|
||||
linux_cxx("ubsan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'ubsan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_UBSAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'B2_LINKFLAGS': '-fuse-ld=gold', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv),
|
||||
#linux_cxx("gcc 11 arm64", "g++-11", packages="g++-11", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", environment={ 'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '17ba079169m'}, arch="arm64", globalenv=globalenv),
|
||||
linux_cxx("GCC 10, Debug + Coverage", "g++-10", packages="g++-10 libssl-dev libffi-dev binutils-gold gdb",
|
||||
linux_cxx("gcc 11 arm64", "g++-11", packages="g++-11", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", environment={ 'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '17ba079169m'}, arch="arm64", globalenv=globalenv),
|
||||
linux_cxx("GCC 10, Debug + Coverage", "g++-10", packages="g++-10 libssl-dev libffi-dev binutils-gold gdb mlocate",
|
||||
image="cppalliance/droneubuntu2004:1", buildtype="boost", buildscript="drone", environment={"GCOV": "gcov-10", "LCOV_VERSION": "1.15", "VARIANT": "process_coverage", "TOOLSET": "gcc", "COMPILER": "g++-10", "CXXSTD": "11", "DRONE_BEFORE_INSTALL" : "process_coverage", "CODECOV_TOKEN": {"from_secret": "codecov_token"}}, globalenv=globalenv, privileged=True),
|
||||
# A set of jobs based on the earlier .travis.yml configuration:
|
||||
linux_cxx("Default clang++ with libc++", "clang++-libc++", packages="libc++-dev", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "B2_TOOLSET": "clang-7", "B2_CXXSTD": "11", "VARIANT": "debug", "TOOLSET": "clang", "COMPILER": "clang++-libc++", "CXXSTD": "11", "CXX_FLAGS": "<cxxflags>-stdlib=libc++ <linkflags>-stdlib=libc++", "TRAVISCLANG" : "yes" }, globalenv=globalenv),
|
||||
linux_cxx("Default g++", "g++", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv),
|
||||
linux_cxx("Clang 3.8, UBasan", "clang++-3.8", packages="clang-3.8 libssl-dev", llvm_os="precise", llvm_ver="3.8", image="cppalliance/droneubuntu1604:1", buildtype="boost", buildscript="drone", environment={"VARIANT": "process_ubasan", "TOOLSET": "clang", "COMPILER": "clang++-3.8", "CXXSTD": "11", "UBSAN_OPTIONS": 'print_stacktrace=1', "DRONE_BEFORE_INSTALL": "UBasan" }, globalenv=globalenv),
|
||||
linux_cxx("Default clang++ with libc++", "clang++-libc++", packages="libc++-dev mlocate", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "B2_TOOLSET": "clang-7", "B2_CXXSTD": "11", "VARIANT": "debug", "TOOLSET": "clang", "COMPILER": "clang++-libc++", "CXXSTD": "11", "CXX_FLAGS": "<cxxflags>-stdlib=libc++ <linkflags>-stdlib=libc++", "TRAVISCLANG" : "yes" }, globalenv=globalenv),
|
||||
linux_cxx("Default g++", "g++", packages="mlocate", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv),
|
||||
linux_cxx("Clang 3.8, UBasan", "clang++-3.8", packages="clang-3.8 libssl-dev mlocate", llvm_os="precise", llvm_ver="3.8", image="cppalliance/droneubuntu1604:1", buildtype="boost", buildscript="drone", environment={"VARIANT": "process_ubasan", "TOOLSET": "clang", "COMPILER": "clang++-3.8", "CXXSTD": "11", "UBSAN_OPTIONS": 'print_stacktrace=1', "DRONE_BEFORE_INSTALL": "UBasan" }, globalenv=globalenv),
|
||||
linux_cxx("gcc 6", "g++-6", packages="g++-6", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'B2_TOOLSET': 'gcc-6', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '902ba3cda1'}, globalenv=globalenv),
|
||||
linux_cxx("clang 3.8", "clang++-3.8", packages="clang-3.8", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu1604:1", environment={'B2_TOOLSET': 'clang', 'COMPILER': 'clang++-3.8', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '7b52009b64'}, globalenv=globalenv),
|
||||
osx_cxx("clang", "g++", packages="", buildtype="boost", buildscript="drone", environment={'B2_TOOLSET': 'clang', 'B2_CXXSTD': '11,17', 'DRONE_JOB_UUID': '91032ad7bb'}, globalenv=globalenv),
|
||||
|
||||
125
.github/workflows/ci.yml
vendored
125
.github/workflows/ci.yml
vendored
@@ -17,6 +17,10 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: gcc-4.8
|
||||
cxxstd: "11"
|
||||
os: ubuntu-18.04
|
||||
install: g++-4.8
|
||||
- toolset: gcc-5
|
||||
cxxstd: "11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
@@ -28,10 +32,21 @@ jobs:
|
||||
- toolset: gcc-7
|
||||
cxxstd: "11,14,17"
|
||||
os: ubuntu-18.04
|
||||
- toolset: gcc-8
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-18.04
|
||||
install: g++-8
|
||||
- toolset: gcc-9
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
- toolset: gcc-10
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: g++-10
|
||||
- toolset: gcc-11
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: g++-11
|
||||
- toolset: gcc-12
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: ubuntu-22.04
|
||||
@@ -247,4 +262,114 @@ jobs:
|
||||
cmake --build .
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
posix-cmake-install:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install
|
||||
|
||||
- name: Use the installed library
|
||||
run: |
|
||||
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
|
||||
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
posix-cmake-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
|
||||
|
||||
- name: Build tests
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target tests
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -31,5 +31,9 @@
|
||||
/notes.cpp
|
||||
/notes_p.txt
|
||||
.settings
|
||||
.DS_Store
|
||||
|
||||
*.make
|
||||
*.cmake
|
||||
*.rsp
|
||||
*.marks
|
||||
cmake-*
|
||||
@@ -8,6 +8,4 @@ A special thank you goes to [@http://www.intra2net.com/ Intra2net AG] (especiall
|
||||
|
||||
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/time-killer-games Samuel Venable] for contributing the v2::ext functionality and all the research that went into it.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -41,7 +41,7 @@ which means, that the named pipe behaves like a file.
|
||||
Windows does provide a facility called [@https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx named pipes],
|
||||
which also have file-like names, but are in a different scope than the actual file system.
|
||||
|
||||
[note The main reason named pipes are part of this library, is because they need to be internally used for asynchronous communication on windows.]
|
||||
[note The main reason named pipes are part of this library, is because they need to be internally used for asynchrounous communication on windows.]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ else if (pid == 0) //child process
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_exec_error">on_exec_error</methodname>(*this);
|
||||
|
||||
<emphasis>unspecified();</emphasis>//here the error is sent to the father process internally
|
||||
<emphasis>unspecified();</emphasis>//here the error is send to the father process interally
|
||||
|
||||
<ulink url="http://en.cppreference.com/w/cpp/utility/program/exit">std::exit</ulink>(<ulink url="http://en.cppreference.com/w/c/program/EXIT_status">EXIT_FAILURE</ulink>);
|
||||
return <classname alt="boost::process::child">child</classname>(); //for C++ compliance
|
||||
@@ -39,7 +39,7 @@ else if (pid == 0) //child process
|
||||
|
||||
<classname alt="boost::process::child">child</classname> c(pid, exit_code);
|
||||
|
||||
<emphasis>unspecified();</emphasis>//here, we read the error from the child process
|
||||
<emphasis>unspecified();</emphasis>//here, we read the the error from the child process
|
||||
|
||||
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
|
||||
for (auto & s : seq)
|
||||
@@ -48,7 +48,7 @@ else
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
|
||||
|
||||
//now we check again, because an on_success handler might've errored.
|
||||
//now we check again, because a on_success handler might've errored.
|
||||
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
|
||||
@@ -9,7 +9,7 @@ Additionally, environment can be lists separated by `:` or `;`; `environment::va
|
||||
`environment::value_view` can be used to iterate those.
|
||||
|
||||
Beyond that, the requirements on an environment are a low as possible;
|
||||
an environment is either a list of strings or a list of string-pairs. It is however recommended to use the environment types,
|
||||
an environment is either a list of strings or a list of string-pairs. It is however recommented to use the environment types,
|
||||
as to have the right value comparisons.
|
||||
|
||||
To note is the `find_executable` functions, which searches in an environment for an executable.
|
||||
|
||||
@@ -27,7 +27,7 @@ For process v2, the interfaces is simple:
|
||||
extern asio::io_context ctx;
|
||||
process proc(ctx, "./test", {"--help"}, process_io{nullptr, {}, {}}, process_environment(my_env));
|
||||
|
||||
Every initializer addresses one logical component (e.g. stdio) instead of multiple ones accumulating.
|
||||
Every initializer adresses one logical compoent (e.g. stdio) instead of multiple ones accumulating.
|
||||
Furthermore, every process has a path and arguments, instead of a confusing mixture of cmd-style and
|
||||
exe-args that can be randomly spread out.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ A launcher is invoked through the call operator.
|
||||
```
|
||||
auto l = windows::as_user_launcher((HANDLE)0xDEADBEEF);
|
||||
asio::io_context ctx;
|
||||
boost::system::error_code ec;
|
||||
boost::system::eror_code ec;
|
||||
auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {});
|
||||
```
|
||||
|
||||
@@ -38,7 +38,7 @@ Alternatively, the `vfork_launcher` can report errors directly back to the paren
|
||||
Thus some calls to the initializers occur after forking from the child process.
|
||||
|
||||
```
|
||||
struct custom_initializer
|
||||
struct custom_initalizer
|
||||
{
|
||||
// functions called from the parent process:
|
||||
|
||||
@@ -47,7 +47,7 @@ Thus some calls to the initializers occur after forking from the child process.
|
||||
template<typename Launcher>
|
||||
error_code on_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
// called for every initializer if an error occurred during setup or process creation
|
||||
// called for every initializer if an error occured during setup or process creation
|
||||
template<typename Launcher>
|
||||
void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
|
||||
const error_code & ec);
|
||||
@@ -56,7 +56,7 @@ Thus some calls to the initializers occur after forking from the child process.
|
||||
template<typename Launcher>
|
||||
void on_success(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
// called for every initializer if an error occurred when forking, in addition to on_error.
|
||||
// called for every initializer if an error occured when forking, in addtion to on_error.
|
||||
template<typename Launcher>
|
||||
void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
|
||||
const error_code & ec);
|
||||
@@ -94,7 +94,7 @@ The launcher will close all non-whitelisted file descriptors after `on_exec_setu
|
||||
|
||||
[section:windows Windows Launchers]
|
||||
|
||||
Windows launchers are pretty straight forward, they will call the following functions on the initializer if present.
|
||||
Windows launchers are pretty streight forward, they will call the following functions on the initializer if present.
|
||||
|
||||
```
|
||||
struct custom_initializer
|
||||
@@ -103,7 +103,7 @@ Windows launchers are pretty straight forward, they will call the following func
|
||||
template<typename Launcher>
|
||||
error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
|
||||
|
||||
// called for every initializer if an error occurred during setup or process creation
|
||||
// called for every initializer if an error occured during setup or process creation
|
||||
template<typename Launcher>
|
||||
void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
|
||||
const error_code & ec);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[section:quickstart Quickstart]
|
||||
[section:quickstart Quickstrat]
|
||||
|
||||
A process needs four things to be launched:
|
||||
|
||||
@@ -32,7 +32,7 @@ also returned from `.wait()`.
|
||||
```
|
||||
|
||||
The normal exit-code is what the subprocess returned from `main`;
|
||||
posix will however add additional information about the process.
|
||||
posix will however add addtional information about the process.
|
||||
This is called the `native_exit_code`.
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ The `.running()` function can be used to detect if the process is still active.
|
||||
|
||||
[section:signal Signalling the subprocess]
|
||||
|
||||
The parent process can signal the subprocess demanding certain actions.
|
||||
The parent process can signal the subprocess demaning certain actions.
|
||||
|
||||
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
|
||||
This is the only reliable & portable way to end a subprocess.
|
||||
@@ -76,7 +76,7 @@ interpret as a signal to shutdown.
|
||||
|
||||
[section:execute Execute functions]
|
||||
|
||||
Process v2 provides `execute` and `async_execute` functions that can be used for managed executions.
|
||||
Process v2 provides `execute` and `async_execute` functons that can be used for managed executions.
|
||||
|
||||
```
|
||||
assert(execute(process("/bin/ls", {}) == 0));
|
||||
@@ -90,7 +90,7 @@ The async version supports cancellation and will forward cancellation types as f
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
asio::steady_timer timeout{ctx, std::chrono::seconds(10)};
|
||||
asio::steady_timer timout{ctx, std::chrono::seconds(10)};
|
||||
|
||||
asio::cancellation_signal sig;
|
||||
async_execute(process("/usr/bin/g++", {"hello_world.cpp"}),
|
||||
|
||||
@@ -23,7 +23,7 @@ automatically connected and the other side will get assigned to the child proces
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
readable pipes can be assigned to `out` an `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`.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ else
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
|
||||
|
||||
//now we check again, because an on_success handler might've errored.
|
||||
//now we check again, because a on_success handler might've errored.
|
||||
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2022 Klemens Morgenstern
|
||||
// Copyright (c) 2022Klemens Morgernstern
|
||||
//
|
||||
// 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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2022Klemens Morgenstern
|
||||
// Copyright (c) 2022Klemens Morgernstern
|
||||
//
|
||||
// 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)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
/** \file boost/process/async.hpp
|
||||
|
||||
The header which provides the basic asynchronous features.
|
||||
The header which provides the basic asynchrounous features.
|
||||
It provides the on_exit property, which allows callbacks when the process exits.
|
||||
It also implements the necessary traits for passing an boost::asio::io_context,
|
||||
which is needed for asynchronous communication.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
/**
|
||||
* \file boost/process/async_system.hpp
|
||||
*
|
||||
* Defines the asynchronous version of the system function.
|
||||
* Defines the asynchrounous version of the system function.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP
|
||||
@@ -38,11 +38,12 @@ namespace process {
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename Handler>
|
||||
template<typename ExitHandler>
|
||||
struct async_system_handler : ::boost::process::detail::api::async_handler
|
||||
{
|
||||
boost::asio::io_context & ios;
|
||||
Handler handler;
|
||||
boost::asio::async_completion<
|
||||
ExitHandler, void(boost::system::error_code, int)> init;
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
bool errored = false;
|
||||
@@ -51,8 +52,9 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
|
||||
template<typename ExitHandler_>
|
||||
async_system_handler(
|
||||
boost::asio::io_context & ios,
|
||||
ExitHandler_ && exit_handler) : ios(ios), handler(std::forward<ExitHandler_>(exit_handler))
|
||||
ExitHandler_ && exit_handler) : ios(ios), init(exit_handler)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -62,15 +64,21 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
|
||||
#if defined(BOOST_POSIX_API)
|
||||
errored = true;
|
||||
#endif
|
||||
auto h = std::make_shared<Handler>(std::move(handler));
|
||||
auto & h = init.completion_handler;
|
||||
boost::asio::post(
|
||||
ios.get_executor(),
|
||||
[h, ec]() mutable
|
||||
{
|
||||
(*h)(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
|
||||
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
|
||||
});
|
||||
}
|
||||
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
|
||||
get_result()
|
||||
{
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
|
||||
{
|
||||
@@ -78,10 +86,10 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
|
||||
if (errored)
|
||||
return [](int , const std::error_code &){};
|
||||
#endif
|
||||
auto h = std::make_shared<Handler>(std::move(handler));
|
||||
auto & h = init.completion_handler;
|
||||
return [h](int exit_code, const std::error_code & ec) mutable
|
||||
{
|
||||
(*h)(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
|
||||
h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -112,36 +120,21 @@ inline boost::process::detail::dummy
|
||||
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct async_system_init_op
|
||||
{
|
||||
|
||||
template<typename Handler, typename ... Args>
|
||||
void operator()(Handler && handler, asio::io_context & ios, Args && ... args)
|
||||
{
|
||||
detail::async_system_handler<typename std::decay<Handler>::type> async_h{ios, std::forward<Handler>(handler)};
|
||||
child(ios, std::forward<Args>(args)..., async_h ).detach();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename ExitHandler, typename ...Args>
|
||||
inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
|
||||
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args)
|
||||
{
|
||||
|
||||
detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};
|
||||
|
||||
typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
|
||||
has_err_handling;
|
||||
|
||||
static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
|
||||
|
||||
return boost::asio::async_initiate<ExitHandler, void (boost::system::error_code, int)>(
|
||||
detail::async_system_init_op{}, exit_handler, ios, std::forward<Args>(args)...
|
||||
);
|
||||
|
||||
child(ios, std::forward<Args>(args)..., async_h ).detach();
|
||||
|
||||
return async_h.get_result();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -125,10 +125,7 @@ public:
|
||||
boost::process::detail::throw_error(ec, "wait error");
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
std::error_code ec;
|
||||
@@ -138,7 +135,6 @@ public:
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
std::error_code ec;
|
||||
@@ -146,7 +142,6 @@ public:
|
||||
boost::process::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool running(std::error_code & ec) noexcept
|
||||
{
|
||||
@@ -183,16 +178,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
|
||||
{
|
||||
if (!_exited())
|
||||
@@ -205,7 +197,7 @@ public:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
|
||||
@@ -114,8 +114,6 @@ template<typename Char> constexpr Char space_sign();
|
||||
template<> constexpr char space_sign<char> () {return ' '; }
|
||||
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}}
|
||||
#endif
|
||||
|
||||
@@ -39,10 +39,10 @@ inline std::string build_cmd_shell(const std::string & exe, std::vector<std::str
|
||||
//the first one is put directly onto the output,
|
||||
//because then I don't have to copy the whole string
|
||||
arg.insert(arg.begin(), '"' );
|
||||
arg += '"'; //that is the post one.
|
||||
arg += '"'; //thats the post one.
|
||||
}
|
||||
|
||||
if (!st.empty())//first one does not need a preceding space
|
||||
if (!st.empty())//first one does not need a preceeding space
|
||||
st += ' ';
|
||||
|
||||
st += arg;
|
||||
@@ -155,15 +155,13 @@ private:
|
||||
|
||||
std::vector<char*> exe_cmd_init<char>::make_cmd()
|
||||
{
|
||||
// any string must be writable.
|
||||
static char empty_string[1] = "";
|
||||
std::vector<char*> vec;
|
||||
if (!exe.empty())
|
||||
vec.push_back(exe.empty() ? empty_string : &exe.front());
|
||||
vec.push_back(&exe.front());
|
||||
|
||||
if (!args.empty()) {
|
||||
for (auto & v : args)
|
||||
vec.push_back(v.empty() ? empty_string : &v.front());
|
||||
vec.push_back(&v.front());
|
||||
}
|
||||
|
||||
vec.push_back(nullptr);
|
||||
|
||||
@@ -444,7 +444,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
|
||||
}
|
||||
if (_ec)
|
||||
{
|
||||
//if an error occurred we need to reap the child process
|
||||
//if an error occured we need to reap the child process
|
||||
::waitpid(this->pid, nullptr, WNOHANG);
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
|
||||
@@ -80,7 +80,7 @@ struct io_context_ref : handler_base_ext
|
||||
void on_success(Executor& exec)
|
||||
{
|
||||
ios.notify_fork(boost::asio::io_context::fork_parent);
|
||||
//must be on the heap, so I can move it into the lambda.
|
||||
//must be on the heap so I can move it into the lambda.
|
||||
auto asyncs = boost::fusion::filter_if<
|
||||
is_async_handler<
|
||||
typename std::remove_reference< boost::mpl::_ > ::type
|
||||
|
||||
@@ -34,7 +34,7 @@ inline bool is_running(const child_handle &p, int & exit_code, std::error_code &
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno != ECHILD) //because it no child is running, then this one isn't either, obviously.
|
||||
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -27,11 +27,7 @@ inline boost::process::filesystem::path search_path(
|
||||
for (const boost::process::filesystem::path & pp : path)
|
||||
{
|
||||
auto p = pp / filename;
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
std::error_code ec;
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
#endif
|
||||
bool file = boost::process::filesystem::is_regular_file(p, ec);
|
||||
if (!ec && file && ::access(p.c_str(), X_OK) == 0)
|
||||
return p;
|
||||
|
||||
@@ -7,18 +7,14 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
|
||||
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/consign.hpp>
|
||||
#include <boost/asio/append.hpp>
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <signal.h>
|
||||
#include <functional>
|
||||
#include <sys/wait.h>
|
||||
#include <list>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
@@ -27,45 +23,8 @@ class sigchld_service : public boost::asio::detail::service_base<sigchld_service
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> _strand{get_io_context().get_executor()};
|
||||
boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
|
||||
|
||||
std::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
|
||||
std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
|
||||
inline void _handle_signal(const boost::system::error_code & ec);
|
||||
|
||||
struct initiate_async_wait_op
|
||||
{
|
||||
sigchld_service * self;
|
||||
template<typename Initiation>
|
||||
void operator()(Initiation && init, ::pid_t pid)
|
||||
{
|
||||
// check if the child actually is running first
|
||||
int status;
|
||||
auto pid_res = ::waitpid(pid, &status, WNOHANG);
|
||||
if (pid_res < 0)
|
||||
{
|
||||
auto ec = get_last_error();
|
||||
boost::asio::post(
|
||||
self->_strand,
|
||||
asio::append(std::forward<Initiation>(init), pid_res, ec));
|
||||
}
|
||||
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
boost::asio::post(
|
||||
self->_strand,
|
||||
boost::asio::append(std::forward<Initiation>(init), status, std::error_code{}));
|
||||
else //still running
|
||||
{
|
||||
sigchld_service * self_ = self;
|
||||
if (self->_receivers.empty())
|
||||
self->_signal_set.async_wait(
|
||||
boost::asio::bind_executor(
|
||||
self->_strand,
|
||||
[self_](const boost::system::error_code &ec, int)
|
||||
{
|
||||
self_->_handle_signal(ec);
|
||||
}));
|
||||
self->_receivers.emplace_back(pid, init);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
sigchld_service(boost::asio::io_context & io_context)
|
||||
: boost::asio::detail::service_base<sigchld_service>(io_context)
|
||||
@@ -77,10 +36,47 @@ public:
|
||||
void (int, std::error_code))
|
||||
async_wait(::pid_t pid, SignalHandler && handler)
|
||||
{
|
||||
return boost::asio::async_initiate<
|
||||
SignalHandler,
|
||||
void(int, std::error_code)>(
|
||||
initiate_async_wait_op{this}, handler, pid);
|
||||
boost::asio::async_completion<
|
||||
SignalHandler, void(boost::system::error_code)> init{handler};
|
||||
|
||||
auto & h = init.completion_handler;
|
||||
boost::asio::dispatch(
|
||||
_strand,
|
||||
[this, pid, h]
|
||||
{
|
||||
//check if the child actually is running first
|
||||
int status;
|
||||
auto pid_res = ::waitpid(pid, &status, WNOHANG);
|
||||
if (pid_res < 0)
|
||||
{
|
||||
auto ec = get_last_error();
|
||||
boost::asio::post(
|
||||
_strand,
|
||||
[pid_res, ec, h]
|
||||
{
|
||||
h(pid_res, ec);
|
||||
});
|
||||
}
|
||||
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
boost::asio::post(
|
||||
_strand,
|
||||
[status, h]
|
||||
{
|
||||
h(status, {}); //successfully exited already
|
||||
});
|
||||
else //still running
|
||||
{
|
||||
if (_receivers.empty())
|
||||
_signal_set.async_wait(
|
||||
[this](const boost::system::error_code &ec, int)
|
||||
{
|
||||
boost::asio::dispatch(_strand, [this, ec]{this->_handle_signal(ec);});
|
||||
});
|
||||
_receivers.emplace_back(pid, h);
|
||||
}
|
||||
});
|
||||
|
||||
return init.result.get();
|
||||
}
|
||||
void shutdown() override
|
||||
{
|
||||
|
||||
@@ -62,7 +62,7 @@ inline std::string build_args(const std::string & exe, std::vector<std::string>
|
||||
}
|
||||
}
|
||||
|
||||
if (!st.empty())//first one does not need a preceding space
|
||||
if (!st.empty())//first one does not need a preceeding space
|
||||
st += ' ';
|
||||
|
||||
st += arg;
|
||||
@@ -106,7 +106,7 @@ inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstrin
|
||||
}
|
||||
}
|
||||
|
||||
if (!st.empty())//first one does not need a preceding space
|
||||
if (!st.empty())//first one does not need a preceeding space
|
||||
st += L' ';
|
||||
|
||||
st += arg;
|
||||
|
||||
@@ -81,7 +81,7 @@ struct child_handle
|
||||
{
|
||||
::boost::winapi::BOOL_ value;
|
||||
if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
|
||||
throw_last_error("IsProcessInJob Failed");
|
||||
throw_last_error("IsProcessinJob Failed");
|
||||
return value!=0;
|
||||
}
|
||||
bool in_group(std::error_code &ec) const noexcept
|
||||
|
||||
@@ -73,8 +73,8 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
|
||||
|
||||
if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
|
||||
{
|
||||
/* limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
|
||||
* but I used 32768, so it is a multiple of 4096.
|
||||
/*limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
|
||||
* but I used 32768 so it is a multiple of 4096.
|
||||
*/
|
||||
constexpr static std::size_t max_size = 32768;
|
||||
//Handle variables longer then buf.
|
||||
@@ -90,12 +90,12 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
|
||||
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
|
||||
else
|
||||
return std::basic_string<Char>(
|
||||
buf.data(), buf.data()+ size);
|
||||
buf.data(), buf.data()+ size + 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return std::basic_string<Char>(buf, buf+size);
|
||||
return std::basic_string<Char>(buf, buf+size+1);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
@@ -232,7 +232,7 @@ basic_environment_impl<Char>::basic_environment_impl(const native_environment_im
|
||||
template<typename Char>
|
||||
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
|
||||
{
|
||||
if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
|
||||
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
|
||||
return string_type(_data.data());
|
||||
|
||||
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
|
||||
@@ -273,7 +273,7 @@ template<typename Char>
|
||||
inline void basic_environment_impl<Char>::reset(const string_type &id)
|
||||
{
|
||||
//ok, we need to check the size of data first
|
||||
if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
|
||||
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
|
||||
return;
|
||||
|
||||
//check if it's the first one, spares us the search.
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
#include <boost/winapi/get_current_process_id.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/handle_info.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
@@ -164,7 +163,7 @@ struct limit_handles_ : handler_base_ext
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor & exec) const
|
||||
void on_sucess(Executor & exec) const
|
||||
{
|
||||
for (auto handle : handles_with_inherit_flag)
|
||||
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
@@ -35,9 +35,7 @@ inline boost::process::filesystem::path search_path(
|
||||
[&](const value_type & e)
|
||||
{return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
|
||||
|
||||
std::vector<std::wstring> extensions_in;
|
||||
if (itr != ne.cend())
|
||||
extensions_in = itr->to_vector();
|
||||
auto extensions_in = itr->to_vector();
|
||||
|
||||
std::vector<std::wstring> extensions((extensions_in.size() * 2) + 1);
|
||||
|
||||
@@ -63,11 +61,7 @@ inline boost::process::filesystem::path search_path(
|
||||
{
|
||||
boost::process::filesystem::path pp_ext = p;
|
||||
pp_ext += ext;
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
std::error_code ec;
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
#endif
|
||||
bool file = boost::process::filesystem::is_regular_file(pp_ext, ec);
|
||||
if (!ec && file &&
|
||||
::boost::winapi::sh_get_file_info(pp_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))
|
||||
|
||||
@@ -437,7 +437,7 @@ for both `id` and `value`.
|
||||
|
||||
\subsubsection env_reset Reset variables
|
||||
|
||||
Resetting single variables can be done in the following way:
|
||||
Reseting signle variables can be done in the following way:
|
||||
|
||||
\code{.cpp}
|
||||
env[id] = boost::none;
|
||||
|
||||
@@ -263,7 +263,7 @@ public:
|
||||
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
const int len = std::char_traits<Char>::length(*p);
|
||||
const auto len = std::char_traits<Char>::length(*p);
|
||||
if ((std::distance(st1.begin(), st1.end()) < len)
|
||||
&& std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
|
||||
@@ -70,7 +70,7 @@ using ::boost::process::detail::get_used_handles;
|
||||
|
||||
///This handler is invoked before the process in launched, to setup parameters. The required signature is `void(Exec &)`, where `Exec` is a template parameter.
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_setup_> on_setup;
|
||||
///This handler is invoked if an error occurred. The required signature is `void(auto & exec, const std::error_code&)`, where `Exec` is a template parameter.
|
||||
///This handler is invoked if an error occured. The required signature is `void(auto & exec, const std::error_code&)`, where `Exec` is a template parameter.
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_error_> on_error;
|
||||
///This handler is invoked if launching the process has succeeded. The required signature is `void(auto & exec)`, where `Exec` is a template parameter.
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_success_> on_success;
|
||||
|
||||
@@ -122,11 +122,9 @@ public:
|
||||
{
|
||||
boost::process::detail::api::wait(_group_handle, ec);
|
||||
}
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
/** Wait for the process group to exit for period of time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time);
|
||||
@@ -134,7 +132,6 @@ public:
|
||||
|
||||
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time, ec);
|
||||
@@ -143,19 +140,17 @@ public:
|
||||
/** Wait for the process group to exit until a point in time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
return boost::process::detail::api::wait_until(_group_handle, timeout_time);
|
||||
}
|
||||
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec);
|
||||
}
|
||||
#endif
|
||||
|
||||
///Check if the group has a valid handle.
|
||||
bool valid() const
|
||||
{
|
||||
|
||||
@@ -82,7 +82,7 @@ using limit_handles_ = ::boost::process::detail::api::limit_handles_;
|
||||
}
|
||||
|
||||
/**
|
||||
* The limit_handles property sets all properties to be inherited only explicitly. It closes all unused file-descriptors on posix after the fork and
|
||||
* The limit_handles property sets all properties to be inherited only expcitly. It closes all unused file-descriptors on posix after the fork and
|
||||
* removes the inherit flags on windows.
|
||||
*
|
||||
* \note This is executed after the fork on posix.
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace boost {
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
///Namespace containing the posix extensions.
|
||||
///Namespace containing the posix exensions.
|
||||
namespace posix {
|
||||
|
||||
/** This property lets you modify file-descriptors other than the standard ones (0,1,2).
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
//
|
||||
// boost/process/v2/bind_launcher.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_BIND_LAUNCHER_HPP
|
||||
#define BOOST_PROCESS_V2_BIND_LAUNCHER_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/default_launcher.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<std::size_t ... Idx>
|
||||
struct index_sequence { };
|
||||
|
||||
template<std::size_t Size, typename T>
|
||||
struct make_index_sequence_impl;
|
||||
|
||||
template<std::size_t Size, std::size_t ... Idx>
|
||||
struct make_index_sequence_impl<Size, index_sequence<Idx...>>
|
||||
{
|
||||
constexpr make_index_sequence_impl() {}
|
||||
using type = typename make_index_sequence_impl<Size - 1u, index_sequence<Size - 1u, Idx...>>::type;
|
||||
};
|
||||
|
||||
template<std::size_t ... Idx>
|
||||
struct make_index_sequence_impl<0u, index_sequence<Idx...>>
|
||||
{
|
||||
constexpr make_index_sequence_impl() {}
|
||||
using type = index_sequence<Idx...>;
|
||||
};
|
||||
|
||||
|
||||
template<std::size_t Cnt>
|
||||
struct make_index_sequence
|
||||
{
|
||||
using type = typename make_index_sequence_impl<Cnt, index_sequence<>>::type;
|
||||
};
|
||||
|
||||
template<std::size_t Cnt>
|
||||
using make_index_sequence_t = typename make_index_sequence<Cnt>::type;
|
||||
|
||||
}
|
||||
|
||||
/** @brief Utility class to bind initializers to a launcher
|
||||
* @tparam Launcher The inner launcher to be used
|
||||
* @tparam ...Init The initializers to be prepended.
|
||||
*
|
||||
* This can be used when multiple processes shared some settings,
|
||||
* e.g.
|
||||
*
|
||||
*/
|
||||
template<typename Launcher, typename ... Init>
|
||||
struct bound_launcher
|
||||
{
|
||||
template<typename Launcher_, typename ... Init_>
|
||||
bound_launcher(Launcher_ && l, Init_ && ... init) :
|
||||
launcher_(std::forward<Launcher_>(l)), init_(std::forward<Init_>(init)...)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ExecutionContext, typename Args, typename ... Inits>
|
||||
auto operator()(ExecutionContext & context,
|
||||
const typename std::enable_if<std::is_convertible<
|
||||
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
|
||||
{
|
||||
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
|
||||
context,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
|
||||
template<typename ExecutionContext, typename Args, typename ... Inits>
|
||||
auto operator()(ExecutionContext & context,
|
||||
error_code & ec,
|
||||
const typename std::enable_if<std::is_convertible<
|
||||
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
|
||||
{
|
||||
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
|
||||
context, 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<
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<Executor>
|
||||
{
|
||||
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
|
||||
std::move(exec),
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
template<typename Executor, typename Args, typename ... Inits>
|
||||
auto operator()(Executor exec,
|
||||
error_code & ec,
|
||||
const typename std::enable_if<
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<Executor>
|
||||
{
|
||||
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
|
||||
std::move(exec), ec,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
private:
|
||||
template<std::size_t ... Idx, typename ExecutionContext, typename Args, typename ... Inits>
|
||||
auto invoke(detail::index_sequence<Idx...>,
|
||||
ExecutionContext & context,
|
||||
const typename std::enable_if<std::is_convertible<
|
||||
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
|
||||
{
|
||||
return launcher_(context,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::get<Idx>(init_)...,
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
|
||||
template<std::size_t ... Idx, typename ExecutionContext, typename Args, typename ... Inits>
|
||||
auto invoke(detail::index_sequence<Idx...>,
|
||||
ExecutionContext & context,
|
||||
error_code & ec,
|
||||
const typename std::enable_if<std::is_convertible<
|
||||
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
|
||||
{
|
||||
return launcher_(context, ec,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::get<Idx>(init_)...,
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
template<std::size_t ... Idx, typename Executor, typename Args, typename ... Inits>
|
||||
auto invoke(detail::index_sequence<Idx...>,
|
||||
Executor exec,
|
||||
const typename std::enable_if<
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<Executor>
|
||||
{
|
||||
return launcher_(std::move(exec),
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::get<Idx>(init_)...,
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
template<std::size_t ... Idx, typename Executor, typename Args, typename ... Inits>
|
||||
auto invoke(detail::index_sequence<Idx...>,
|
||||
Executor exec,
|
||||
error_code & ec,
|
||||
const typename std::enable_if<
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<Executor>
|
||||
{
|
||||
return launcher_(std::move(exec), ec,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::get<Idx>(init_)...,
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
Launcher launcher_;
|
||||
std::tuple<Init...> init_;
|
||||
};
|
||||
|
||||
|
||||
template<typename Launcher, typename ... Init>
|
||||
auto bind_launcher(Launcher && launcher, Init && ... init)
|
||||
-> bound_launcher<typename std::decay<Launcher>::type,
|
||||
typename std::decay<Init>::type...>
|
||||
{
|
||||
return bound_launcher<typename std::decay<Launcher>::type,
|
||||
typename std::decay<Init>::type...>(
|
||||
std::forward<Launcher>(launcher),
|
||||
std::forward<Init>(init)...);
|
||||
}
|
||||
|
||||
/// @brief @overload bind_launcher(Launcher && launcher, Init && init)
|
||||
/// @tparam ...Init The initializer types to bind to the default_launcher.
|
||||
/// @param ...init The initializers types to bind to the default_launcher.
|
||||
/// @return The new default_launcher.
|
||||
template<typename ... Init>
|
||||
auto bind_default_launcher(Init && ... init)
|
||||
-> bound_launcher<default_process_launcher,
|
||||
typename std::decay<Init>::type...>
|
||||
{
|
||||
return bound_launcher<default_process_launcher,
|
||||
typename std::decay<Init>::type...>(
|
||||
default_process_launcher(),
|
||||
std::forward<Init>(init)...);
|
||||
}
|
||||
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_BIND_LAUNCHER_HPP
|
||||
@@ -106,7 +106,7 @@ struct basic_cstring_ref
|
||||
BOOST_CXX14_CONSTEXPR const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= size())
|
||||
throw_exception(std::out_of_range("cstring-view out of range"));
|
||||
throw std::out_of_range("cstring-view out of range");
|
||||
return view_[pos];
|
||||
}
|
||||
BOOST_CONSTEXPR const_reference front() const {return *view_;}
|
||||
|
||||
@@ -7,19 +7,18 @@
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
|
||||
#define BOOST_PROCESS_V2_ASIO_NAMESPACE asio
|
||||
#define BOOST_PROCESS_V2_ASIO_NAMESPACE ::asio
|
||||
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) ASIO_COMPLETION_TOKEN_FOR(Sig)
|
||||
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
|
||||
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
|
||||
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
|
||||
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
|
||||
|
||||
|
||||
#include <asio/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <filesystem>
|
||||
#include <string_view>
|
||||
#include <iomanip>
|
||||
#include <optional>
|
||||
|
||||
#if defined(ASIO_WINDOWS)
|
||||
#define BOOST_PROCESS_V2_WINDOWS 1
|
||||
@@ -40,19 +39,18 @@
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_PROCESS_V2_ASIO_NAMESPACE boost::asio
|
||||
#define BOOST_PROCESS_V2_ASIO_NAMESPACE ::boost::asio
|
||||
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) BOOST_ASIO_COMPLETION_TOKEN_FOR(Sig)
|
||||
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
|
||||
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
|
||||
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
|
||||
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/io/quoted.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_category.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
#define BOOST_PROCESS_V2_WINDOWS 1
|
||||
@@ -74,9 +72,11 @@
|
||||
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#else
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#endif
|
||||
|
||||
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { namespace v2 {
|
||||
@@ -97,14 +97,6 @@ namespace filesystem = std::filesystem;
|
||||
using std::quoted;
|
||||
using std::optional;
|
||||
|
||||
#define BOOST_PROCESS_V2_RETURN_EC(ev) \
|
||||
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category()); \
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) ec.assign(__VA_ARGS__);
|
||||
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
|
||||
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error()); \
|
||||
|
||||
|
||||
#else
|
||||
|
||||
using boost::system::error_code ;
|
||||
@@ -120,25 +112,6 @@ namespace filesystem = std::filesystem;
|
||||
namespace filesystem = boost::filesystem;
|
||||
#endif
|
||||
|
||||
#define BOOST_PROCESS_V2_RETURN_EC(ev) \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category(), &loc##__LINE__); \
|
||||
}
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
ec.assign(__VA_ARGS__, &loc##__LINE__); \
|
||||
}
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error(), &loc##__LINE__); \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
@@ -169,7 +142,7 @@ BOOST_PROCESS_V2_END_NAMESPACE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) && defined(BOOST_PROCESS_V2_ENABLE_PDFORK)
|
||||
#if defined(__FreeBSD__) && !defined(BOOST_PROCESS_V2_DISABLE_PDFORK)
|
||||
#define BOOST_PROCESS_V2_PDFORK 1
|
||||
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
|
||||
#endif
|
||||
@@ -177,4 +150,6 @@ BOOST_PROCESS_V2_END_NAMESPACE
|
||||
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_CONFIG_HPP
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
|
||||
#if defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
|
||||
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__)
|
||||
extern "C" { extern char **environ; }
|
||||
#endif
|
||||
|
||||
@@ -77,4 +77,4 @@ BOOST_PROCESS_V2_DECL bool is_executable(const filesystem::path & pth, error_cod
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
#endif
|
||||
417
include/boost/process/v2/detail/group_impl_windows.hpp
Normal file
417
include/boost/process/v2/detail/group_impl_windows.hpp
Normal file
@@ -0,0 +1,417 @@
|
||||
// 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_GROUP_IMPL_HPP
|
||||
#define BOOST_PROCESS_V2_GROUP_IMPL_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
#include <asio/any_io_executor.hpp>
|
||||
#include <asio/append.hpp>
|
||||
#include <asio/compose.hpp>
|
||||
#include <asio/dispatch.hpp>
|
||||
#include <asio/post.hpp>
|
||||
#include <asio/windows/basic_object_handle.hpp>
|
||||
#else
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/append.hpp>
|
||||
#include <boost/asio/compose.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/windows/basic_object_handle.hpp>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
struct single_process_exit;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL bool job_object_is_empty(HANDLE job_object, error_code & ec);
|
||||
|
||||
template<typename Allocator>
|
||||
BOOST_PROCESS_V2_DECL std::pair<DWORD, DWORD> job_object_something_exited(HANDLE job_object, std::vector<int> & store, Allocator alloc_, error_code & ec)
|
||||
{
|
||||
// let's start with a
|
||||
typename std::aligned_storage<sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) * 16, alignof(JOBOBJECT_BASIC_PROCESS_ID_LIST)>::type storage;
|
||||
JOBOBJECT_BASIC_PROCESS_ID_LIST * id_list = static_cast<JOBOBJECT_BASIC_PROCESS_ID_LIST*>(storage);
|
||||
|
||||
if (!QueryInformationJobObject(job_object,
|
||||
JobObjectBasicProcessIdList,
|
||||
id_list, sizeof(storage), nullptr))
|
||||
ec = detail::get_last_error();
|
||||
|
||||
if (ec)
|
||||
return {};
|
||||
|
||||
using allocator_type = std::allocator_traits<Allocator>::rebind_alloc<JOBOBJECT_BASIC_PROCESS_ID_LIST>;
|
||||
allocator_type alloc{alloc_};
|
||||
|
||||
std::size_t sz = (std::numeric_limits<std::size_t>::max)();
|
||||
// dit not fit in the buffer, alloc a buffer
|
||||
if (id_list.NumberOfAssignedProcesses != id_list.NumberOfProcessIdsInList)
|
||||
{
|
||||
// required size:
|
||||
const additional_size = id_list.NumberOfAssignedProcesses - 1;
|
||||
sz = (additional_size / (sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) / sizeof(ULONG_PTR))) + 1;
|
||||
id_list = std::allocator_traits<allocator_type>::allocate(alloc_, sz);
|
||||
|
||||
if (!QueryInformationJobObject(job_object,
|
||||
JobObjectBasicProcessIdList,
|
||||
id_list, sz, nullptr))
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
goto complete;
|
||||
}
|
||||
|
||||
}
|
||||
std::pair<DWORD, DWORD> result;
|
||||
|
||||
auto * begin = id_list->ProcessIdList,
|
||||
* end = id_list->ProcessIdList + id_list->NumberOfProcessIdsInList;
|
||||
|
||||
for (auto itr = store.begin(); itr != store.end(); itr++)
|
||||
{
|
||||
// cross check if it's in the job object
|
||||
auto it = std::find(begin, end, *itr);
|
||||
if (it == end) // missing a job
|
||||
{
|
||||
result.first = *itr;
|
||||
// ::GetExitCodeProcess(); // this can't be done based on PID, i need the f'in handle.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
complete:
|
||||
if (sz != (std::numeric_limits<std::size_t>::max)())
|
||||
std::allocator_traits<allocator_type>::deallocate(alloc_, id_list, sz);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
//extern template
|
||||
#endif
|
||||
|
||||
struct basic_group_impl_base
|
||||
{
|
||||
using native_handle_type = HANDLE;
|
||||
|
||||
struct job_object_deleter
|
||||
{
|
||||
bool terminate_on_delete = true;
|
||||
void operator()(HANDLE h)
|
||||
{
|
||||
if (h != nullptr && terminate_on_delete)
|
||||
::TerminateJobObject(h, 255u);
|
||||
if (h != nullptr && h != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(h);
|
||||
}
|
||||
};
|
||||
BOOST_PROCESS_V2_DECL void add(DWORD pid, HANDLE handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL bool contains(DWORD pid, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void wait_one(DWORD &pid, int &exit_code, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void wait_all(error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void interrupt(error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void request_exit(error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void terminate(error_code & ec);
|
||||
bool is_open() const
|
||||
{
|
||||
return job_object_.get() != nullptr;
|
||||
}
|
||||
|
||||
struct initializer_t
|
||||
{
|
||||
basic_group_impl_base * self;
|
||||
error_code & success_ec;
|
||||
|
||||
error_code on_setup(windows::default_launcher & launcher,
|
||||
const filesystem::path &,
|
||||
const std::wstring &) const
|
||||
{
|
||||
launcher.creation_flags |= CREATE_SUSPENDED;
|
||||
return error_code {};
|
||||
};
|
||||
|
||||
|
||||
void on_success(windows::default_launcher & launcher,
|
||||
const filesystem::path &,
|
||||
const std::wstring &) const
|
||||
{
|
||||
if (!::AssignProcessToJobObject(self->job_object_.get(), launcher.process_information.hProcess))
|
||||
success_ec = detail::get_last_error();
|
||||
|
||||
if (!success_ec &&
|
||||
::ResumeThread(launcher.process_information.hThread) == static_cast<DWORD>(-1))
|
||||
success_ec = detail::get_last_error();
|
||||
};
|
||||
};
|
||||
initializer_t get_initializer(error_code & ec)
|
||||
{
|
||||
return initializer_t{this, ec};
|
||||
}
|
||||
basic_group_impl_base(BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context & ctx)
|
||||
{
|
||||
}
|
||||
~basic_group_impl_base()
|
||||
{
|
||||
}
|
||||
void detach() {job_object_.get_deleter().terminate_on_delete = false;}
|
||||
protected:
|
||||
std::unique_ptr<void, job_object_deleter> job_object_{CreateJobObject(nullptr, nullptr)};
|
||||
};
|
||||
|
||||
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>
|
||||
struct basic_group_impl : basic_group_impl_base
|
||||
{
|
||||
|
||||
// Get the native group handle
|
||||
native_handle_type native_handle() {return port_.native_handle();}
|
||||
|
||||
basic_group_impl(Executor exec)
|
||||
: basic_group_impl_base(BOOST_PROCESS_V2_ASIO_NAMESPACE::query(exec,
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::context)),
|
||||
port_(exec, ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1))
|
||||
{
|
||||
error_code ec;
|
||||
JOBOBJECT_ASSOCIATE_COMPLETION_PORT port{job_object_.get(), port_.native_handle()};
|
||||
|
||||
if (!::SetInformationJobObject(
|
||||
job_object_.get(),
|
||||
JobObjectAssociateCompletionPortInformation,
|
||||
&port, sizeof(port)))
|
||||
ec = v2::detail::get_last_error();
|
||||
}
|
||||
|
||||
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, single_process_exit))
|
||||
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, single_process_exit))
|
||||
async_wait_one(
|
||||
WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
|
||||
{
|
||||
printf("FOOBAR %d %p\n", port_.native_handle(), this);
|
||||
|
||||
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<
|
||||
WaitHandler,
|
||||
void (error_code, single_process_exit)>(
|
||||
wait_one_op{this},
|
||||
handler, port_);
|
||||
}
|
||||
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code))
|
||||
async_wait_all(
|
||||
WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
|
||||
{
|
||||
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<
|
||||
WaitHandler,
|
||||
void (error_code)>(
|
||||
wait_all_op{this},
|
||||
handler, port_);
|
||||
}
|
||||
|
||||
using executor_type = Executor;
|
||||
executor_type get_executor() {return port_.get_executor();}
|
||||
|
||||
void wait_all(error_code &ec)
|
||||
{
|
||||
if (job_object_is_empty(job_object_.get(), ec))
|
||||
return ;
|
||||
|
||||
DWORD completion_code;
|
||||
ULONG_PTR completion_key;
|
||||
LPOVERLAPPED overlapped;
|
||||
|
||||
int res;
|
||||
while (!!(res = GetQueuedCompletionStatus(
|
||||
port_.native_handle(),
|
||||
&completion_code,
|
||||
&completion_key,
|
||||
&overlapped,
|
||||
INFINITE)))
|
||||
{
|
||||
if (completion_code == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!res)
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
void wait_one(DWORD & pid, int & exit_code, error_code &ec)
|
||||
{
|
||||
if (job_object_is_empty(job_object_.get(), ec))
|
||||
{
|
||||
ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::broken_pipe;
|
||||
return ;
|
||||
}
|
||||
DWORD completion_code;
|
||||
ULONG_PTR completion_key;
|
||||
LPOVERLAPPED overlapped;
|
||||
|
||||
int res;
|
||||
while (!!(res = GetQueuedCompletionStatus(
|
||||
port_.native_handle(),
|
||||
&completion_code,
|
||||
&completion_key,
|
||||
&overlapped,
|
||||
INFINITE)))
|
||||
{
|
||||
if (completion_code == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
|
||||
{
|
||||
ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::broken_pipe;
|
||||
return;
|
||||
}
|
||||
else if (completion_code == JOB_OBJECT_MSG_EXIT_PROCESS
|
||||
|| completion_code == JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS)
|
||||
{
|
||||
pid = *reinterpret_cast<DWORD*>(&overlapped);
|
||||
const auto p = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
|
||||
if (p == INVALID_HANDLE_VALUE || p == nullptr)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD code;
|
||||
res = ::GetExitCodeProcess(p, &code);
|
||||
exit_code = static_cast<int>(code);
|
||||
break;
|
||||
}
|
||||
else if (job_object_is_empty(job_object_.get(), ec))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!res)
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
private:
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::windows::basic_object_handle<Executor> port_;
|
||||
|
||||
struct wait_one_op
|
||||
{
|
||||
basic_group_impl * this_;
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self && self)
|
||||
{
|
||||
printf("FOOBAR %d %p\n", __LINE__, this_);
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::dispatch(this_->port_.get_executor(),
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::append(std::move(self), error_code{}));
|
||||
}
|
||||
|
||||
template<typename Self>
|
||||
void operator()(Self && self, error_code ec)
|
||||
{
|
||||
using namespace BOOST_PROCESS_V2_ASIO_NAMESPACE;
|
||||
single_process_exit res;
|
||||
|
||||
/*// we need to install our handler first, THEN check, THEN
|
||||
using allocator_type = associated_allocator_t<typename std::decay<Handler::type>;
|
||||
allocator_type allocator = get_associated_allocator(handler);
|
||||
*/
|
||||
printf("FOOBAR %d %p\n", __LINE__, this_);
|
||||
if (ec)
|
||||
return self.complete(ec, res);
|
||||
auto exec = self.get_executor();
|
||||
printf("FOOBAR %d %p\n", __LINE__, this_);
|
||||
if (job_object_is_empty(this_->job_object_.get(), ec))
|
||||
return self.complete(BOOST_PROCESS_V2_ASIO_NAMESPACE::error::broken_pipe, res);
|
||||
printf("FOOBAR %d %p\n", __LINE__, this_);
|
||||
|
||||
//check if done
|
||||
if (this->poll_one(ec, res))
|
||||
return self.complete(ec, res);
|
||||
else
|
||||
this_->port_.async_wait(std::move(self));
|
||||
printf("FOOBAR %d %p\n", __LINE__, this_);
|
||||
}
|
||||
|
||||
bool poll_one(error_code & ec, single_process_exit & se)
|
||||
{
|
||||
DWORD completion_code;
|
||||
ULONG_PTR completion_key;
|
||||
LPOVERLAPPED overlapped;
|
||||
auto res = GetQueuedCompletionStatus(
|
||||
this_->port_.native_handle(),
|
||||
&completion_code,
|
||||
&completion_key,
|
||||
&overlapped,
|
||||
0u);
|
||||
|
||||
if (!res && ::GetLastError() == ERROR_ABANDONED_WAIT_0)
|
||||
return false;
|
||||
|
||||
if (completion_code == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
|
||||
{
|
||||
ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::broken_pipe;
|
||||
return true;
|
||||
}
|
||||
else if (completion_code == JOB_OBJECT_MSG_EXIT_PROCESS
|
||||
|| completion_code == JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS)
|
||||
{
|
||||
se.pid = *reinterpret_cast<DWORD*>(&overlapped);
|
||||
const auto p = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, se.pid);
|
||||
|
||||
if (p == INVALID_HANDLE_VALUE || p == nullptr)
|
||||
{
|
||||
ec = detail::get_last_error();
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD code;
|
||||
res = ::GetExitCodeProcess(p, &code);
|
||||
se.exit_code = static_cast<int>(code);
|
||||
return true;
|
||||
}
|
||||
else if (job_object_is_empty(this_->job_object_.get(), ec))
|
||||
{
|
||||
ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::broken_pipe;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct wait_all_op
|
||||
{
|
||||
basic_group_impl * this_;
|
||||
template<typename Self>
|
||||
void operator()(Self && self)
|
||||
{
|
||||
/*
|
||||
using namespace BOOST_PROCESS_V2_ASIO_NAMESPACE;
|
||||
using allocator_type = associated_allocator_t<typename std::decay<Handler::type>;
|
||||
allocator_type allocator = get_associated_allocator(handler);
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
extern template struct basic_group_impl<BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
#include <boost/process/v2/detail/impl/group_impl_windows.ipp>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_GROUP_IMPL_HPP
|
||||
@@ -34,7 +34,7 @@ basic_cstring_ref<char_type, value_char_traits<char>> get(
|
||||
auto res = ::getenv(key.c_str());
|
||||
if (res == nullptr)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOENT, system_category())
|
||||
ec.assign(ENOENT, system_category());
|
||||
return {};
|
||||
}
|
||||
return res;
|
||||
@@ -45,13 +45,13 @@ void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (::setenv(key.c_str(), value.c_str(), true))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
}
|
||||
|
||||
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec)
|
||||
{
|
||||
if (::unsetenv(key.c_str()))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ std::basic_string<char_type, value_char_traits<char_type>> get(
|
||||
buf.resize(size);
|
||||
|
||||
if (buf.size() == 0)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -60,14 +60,14 @@ void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableW(key.c_str(), value.c_str()))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
}
|
||||
|
||||
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableW(key.c_str(), nullptr))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ std::basic_string<char, value_char_traits<char>> get(
|
||||
buf.resize(size);
|
||||
|
||||
if (buf.size() == 0)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -98,14 +98,14 @@ void set(basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableA(key.c_str(), value.c_str()))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
}
|
||||
|
||||
void unset(basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableA(key.c_str(), nullptr))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
|
||||
}
|
||||
|
||||
|
||||
|
||||
79
include/boost/process/v2/detail/impl/group_impl_windows.ipp
Normal file
79
include/boost/process/v2/detail/impl/group_impl_windows.ipp
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// boost/process/v2/windows/impl/job_object_service.ipp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_DETAIL_IMPL_GROUP_IMPL_WINDOWS_IPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_IMPL_GROUP_IMPL_WINDOWS_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/group_impl_windows.hpp>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
namespace detail
|
||||
{
|
||||
|
||||
bool job_object_is_empty(HANDLE job_object, error_code & ec)
|
||||
{
|
||||
JOBOBJECT_BASIC_ACCOUNTING_INFORMATION info;
|
||||
if (!QueryInformationJobObject(job_object,
|
||||
JobObjectBasicAccountingInformation,
|
||||
&info, sizeof(info), nullptr))
|
||||
ec = detail::get_last_error();
|
||||
return info.ActiveProcesses == 0u;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
template struct basic_group_impl<BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>;
|
||||
#endif
|
||||
|
||||
|
||||
void basic_group_impl_base::add(DWORD pid, HANDLE handle, error_code & ec)
|
||||
{
|
||||
if (!AssignProcessToJobObject(job_object_.get(), handle))
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
void basic_group_impl_base::terminate(error_code & ec)
|
||||
{
|
||||
if (!::TerminateJobObject(job_object_.get(), 255u))
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
|
||||
bool basic_group_impl_base::contains(DWORD pid, error_code & ec)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
//
|
||||
struct del
|
||||
{
|
||||
void operator()(HANDLE h)
|
||||
{
|
||||
if (h != nullptr && h != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(h);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<void, del> proc{::OpenProcess(PROCESS_QUERY_INFORMATION , FALSE, pid)};
|
||||
|
||||
if (proc.get() != INVALID_HANDLE_VALUE &&
|
||||
!IsProcessInJob(proc.get(), job_object_.get(), &res))
|
||||
ec = detail::get_last_error();
|
||||
|
||||
return res == TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_GROUP_IMPL_WINDOWS_IPP
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <cerrno>
|
||||
#endif
|
||||
@@ -28,6 +28,20 @@ error_code get_last_error()
|
||||
|
||||
}
|
||||
|
||||
void throw_last_error()
|
||||
{
|
||||
throw system_error(get_last_error());
|
||||
}
|
||||
void throw_last_error(const char * msg)
|
||||
{
|
||||
throw system_error(get_last_error(), msg);
|
||||
}
|
||||
void throw_last_error(const std::string & msg)
|
||||
{
|
||||
throw system_error(get_last_error(), msg);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
@@ -9,20 +9,9 @@
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/detail/process_handle_windows.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
|
||||
extern "C"
|
||||
{
|
||||
|
||||
LONG WINAPI NtResumeProcess(HANDLE ProcessHandle);
|
||||
LONG WINAPI NtSuspendProcess(HANDLE ProcessHandle);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
@@ -34,7 +23,7 @@ void get_exit_code_(
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::GetExitCodeProcess(handle, &exit_code))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,12 +31,7 @@ HANDLE open_process_(DWORD pid)
|
||||
{
|
||||
auto proc = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pid);
|
||||
if (proc == nullptr)
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
throw system_error(ec, "open_process()");
|
||||
}
|
||||
|
||||
detail::throw_last_error("open_process()");
|
||||
return proc;
|
||||
}
|
||||
|
||||
@@ -56,17 +40,17 @@ void terminate_if_running_(HANDLE handle)
|
||||
{
|
||||
DWORD exit_code = 0u;
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return ;
|
||||
return ;
|
||||
if (::GetExitCodeProcess(handle, &exit_code))
|
||||
if (exit_code == STILL_ACTIVE)
|
||||
::TerminateProcess(handle, 260);
|
||||
if (exit_code == STILL_ACTIVE)
|
||||
::TerminateProcess(handle, 260);
|
||||
}
|
||||
|
||||
bool check_handle_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
|
||||
ec.assign(ERROR_INVALID_HANDLE_STATE, system_category());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -76,8 +60,8 @@ bool check_pid_(pid_type pid_, error_code & ec)
|
||||
{
|
||||
if (pid_ == 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
|
||||
return false;
|
||||
ec.assign(ERROR_INVALID_HANDLE_STATE, system_category());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -89,73 +73,46 @@ struct enum_windows_data_t
|
||||
};
|
||||
|
||||
static BOOL CALLBACK enum_window(HWND hwnd, LPARAM param)
|
||||
{
|
||||
{
|
||||
auto data = reinterpret_cast<enum_windows_data_t*>(param);
|
||||
DWORD pid{0u};
|
||||
GetWindowThreadProcessId(hwnd, &pid);
|
||||
if (pid != data->pid)
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
|
||||
LRESULT res = ::SendMessageW(hwnd, WM_CLOSE, 0, 0);
|
||||
|
||||
if (res)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(data->ec)
|
||||
data->ec = detail::get_last_error();
|
||||
return res == 0;
|
||||
}
|
||||
}
|
||||
|
||||
void request_exit_(pid_type pid_, error_code & ec)
|
||||
{
|
||||
enum_windows_data_t data{ec, pid_};
|
||||
|
||||
if (!::EnumWindows(enum_window, reinterpret_cast<LONG_PTR>(&data)))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
void interrupt_(pid_type pid_, error_code & ec)
|
||||
{
|
||||
if (!::GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid_))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
void terminate_(HANDLE handle, error_code & ec, DWORD & exit_status)
|
||||
{
|
||||
if (!::TerminateProcess(handle, 260))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
void check_running_(HANDLE handle, error_code & ec, DWORD & exit_status)
|
||||
{
|
||||
if (!::GetExitCodeProcess(handle, &exit_status))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
|
||||
void suspend_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
auto nt_err = NtSuspendProcess(handle);
|
||||
ULONG dos_err = RtlNtStatusToDosError(nt_err);
|
||||
if (dos_err)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void resume_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
auto nt_err = NtResumeProcess(handle);
|
||||
ULONG dos_err = RtlNtStatusToDosError(nt_err);
|
||||
if (dos_err)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
#else
|
||||
void suspend_(HANDLE, error_code & ec)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_CALL_NOT_IMPLEMENTED, system_category())
|
||||
}
|
||||
|
||||
void resume_(HANDLE handle, error_code & ec)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_CALL_NOT_IMPLEMENTED, system_category())
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
template struct basic_process_handle_win<>;
|
||||
|
||||
@@ -27,13 +27,13 @@ inline void handle_error(error_code & ec)
|
||||
switch (err)
|
||||
{
|
||||
case ERROR_INSUFFICIENT_BUFFER:
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::utf8_category)
|
||||
ec.assign(error::insufficient_buffer, error::utf8_category);
|
||||
break;
|
||||
case ERROR_NO_UNICODE_TRANSLATION:
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::utf8_category)
|
||||
ec.assign(error::invalid_character, error::utf8_category);
|
||||
break;
|
||||
default:
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
|
||||
ec.assign(err, system_category());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ inline int get_cont_octet_out_count_impl<4>(wchar_t word) {
|
||||
|
||||
// Note that the following code will generate warnings on some platforms
|
||||
// where wchar_t is defined as UCS2. The warnings are superfluous as the
|
||||
// specialization is never instantiated with such compilers, but this
|
||||
// specialization is never instantitiated with such compilers, but this
|
||||
// can cause problems if warnings are being treated as errors, so we guard
|
||||
// against that. Including <boost/detail/utf8_codecvt_facet.hpp> as we do
|
||||
// should be enough to get WCHAR_MAX defined.
|
||||
@@ -242,7 +242,7 @@ std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
|
||||
if (*from > max_wchar) {
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
|
||||
ec.assign(error::invalid_character, error::get_utf8_category());
|
||||
return 0u;
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
|
||||
if (to == to_end && i != cont_octet_count) {
|
||||
from_next = from;
|
||||
to_next = to - (i + 1);
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
|
||||
ec.assign(error::insufficient_buffer, error::get_utf8_category());
|
||||
return 0u;
|
||||
}
|
||||
++from;
|
||||
@@ -280,7 +280,7 @@ std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
|
||||
|
||||
// Were we done or did we run out of destination space
|
||||
if (from != from_end)
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
|
||||
ec.assign(error::insufficient_buffer, error::get_utf8_category());
|
||||
|
||||
return to_next - out;
|
||||
}
|
||||
@@ -315,7 +315,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
|
||||
if (invalid_leading_octet(*from)) {
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
|
||||
ec.assign(error::invalid_character, error::get_utf8_category());
|
||||
return 0u;
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
|
||||
if (invalid_continuing_octet(*from)) {
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
|
||||
ec.assign(error::invalid_character, error::get_utf8_category());
|
||||
return 0u;
|
||||
}
|
||||
|
||||
@@ -356,7 +356,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
|
||||
// rewind "from" to before the current character translation
|
||||
from_next = from - (i + 1);
|
||||
to_next = to;
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
|
||||
ec.assign(error::insufficient_buffer, error::get_utf8_category());
|
||||
return 0u;
|
||||
}
|
||||
*to++ = ucs_result;
|
||||
@@ -365,7 +365,7 @@ std::size_t convert_to_wide(const char * in, std::size_t size,
|
||||
to_next = to;
|
||||
|
||||
if (from != from_end)
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
|
||||
ec.assign(error::insufficient_buffer, error::get_utf8_category());
|
||||
|
||||
return to_next - out;
|
||||
}
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
|
||||
BOOST_PROCESS_V2_DECL error_code get_last_error();
|
||||
BOOST_PROCESS_V2_DECL void throw_last_error();
|
||||
BOOST_PROCESS_V2_DECL void throw_last_error(const char * msg);
|
||||
BOOST_PROCESS_V2_DECL void throw_last_error(const std::string & msg);
|
||||
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
@@ -101,8 +101,6 @@ struct basic_process_handle_fd
|
||||
pid_type id() const
|
||||
{ return pid_; }
|
||||
|
||||
native_handle_type native_handle() {return pid_;}
|
||||
|
||||
void terminate_if_running(error_code &)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
@@ -184,42 +182,7 @@ struct basic_process_handle_fd
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGSTOP) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
|
||||
@@ -128,7 +128,6 @@ struct basic_process_handle_fd_or_signal
|
||||
|
||||
pid_type id() const
|
||||
{ return pid_; }
|
||||
native_handle_type native_handle() {return pid_;}
|
||||
|
||||
void terminate_if_running(error_code &)
|
||||
{
|
||||
@@ -212,42 +211,6 @@ struct basic_process_handle_fd_or_signal
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGSTOP) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return ;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@ struct basic_process_handle_signal
|
||||
{
|
||||
native_handle_type() = delete;
|
||||
native_handle_type(const native_handle_type & ) = delete;
|
||||
~native_handle_type() = default;
|
||||
~native_handle_type() = delete;
|
||||
};
|
||||
|
||||
typedef Executor executor_type;
|
||||
@@ -101,8 +101,8 @@ struct basic_process_handle_signal
|
||||
handle.pid_ = -1;
|
||||
}
|
||||
|
||||
pid_type id() const { return pid_; }
|
||||
native_handle_type native_handle() {return {};}
|
||||
pid_type id() const
|
||||
{ return pid_; }
|
||||
|
||||
void terminate_if_running(error_code &)
|
||||
{
|
||||
@@ -112,7 +112,7 @@ struct basic_process_handle_signal
|
||||
void terminate_if_running()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
return ;
|
||||
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
|
||||
{
|
||||
::kill(pid_, SIGKILL);
|
||||
@@ -123,7 +123,7 @@ struct basic_process_handle_signal
|
||||
void wait(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
return ;
|
||||
while (::waitpid(pid_, &exit_status, 0) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
@@ -137,7 +137,7 @@ struct basic_process_handle_signal
|
||||
void wait(native_exit_code_type &exit_status)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
return ;
|
||||
error_code ec;
|
||||
wait(exit_status, ec);
|
||||
if (ec)
|
||||
@@ -147,7 +147,7 @@ struct basic_process_handle_signal
|
||||
void interrupt(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
return ;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
@@ -155,7 +155,7 @@ struct basic_process_handle_signal
|
||||
void interrupt()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
return ;
|
||||
error_code ec;
|
||||
interrupt(ec);
|
||||
if (ec)
|
||||
@@ -165,7 +165,7 @@ struct basic_process_handle_signal
|
||||
void request_exit(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
return ;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
@@ -173,53 +173,17 @@ struct basic_process_handle_signal
|
||||
void request_exit()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
return ;
|
||||
error_code ec;
|
||||
request_exit(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGCONT) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
error_code ec;
|
||||
resume(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
if (::kill(pid_, SIGTERM) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
return ;
|
||||
if (::kill(pid_, SIGKILL) == -1)
|
||||
ec = get_last_error();
|
||||
}
|
||||
@@ -227,7 +191,7 @@ struct basic_process_handle_signal
|
||||
void terminate(native_exit_code_type &exit_status)
|
||||
{
|
||||
if (pid_ <= 0)
|
||||
return;
|
||||
return ;
|
||||
error_code ec;
|
||||
terminate(exit_status, ec);
|
||||
if (ec)
|
||||
@@ -320,7 +284,7 @@ struct basic_process_handle_signal
|
||||
if (!ec && (wait_res == 0))
|
||||
{
|
||||
handle.async_wait(std::move(self));
|
||||
return;
|
||||
return ;
|
||||
}
|
||||
|
||||
struct completer
|
||||
|
||||
@@ -32,8 +32,6 @@ BOOST_PROCESS_V2_DECL void terminate_if_running_(void * handle);
|
||||
BOOST_PROCESS_V2_DECL bool check_handle_(void* handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL bool check_pid_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void interrupt_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void suspend_(void * handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void resume_(void * handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void terminate_(void * handle, error_code & ec, native_exit_code_type & exit_code);
|
||||
BOOST_PROCESS_V2_DECL void request_exit_(pid_type pid_, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL void check_running_(void* handle, error_code & ec, native_exit_code_type & exit_status);
|
||||
@@ -178,32 +176,6 @@ struct basic_process_handle_win
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
detail::suspend_(handle_.native_handle(), ec);
|
||||
}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
detail::resume_(handle_.native_handle(), ec);
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec)
|
||||
{
|
||||
if (!detail::check_handle_(handle_.native_handle(), ec))
|
||||
|
||||
@@ -488,7 +488,7 @@ struct key
|
||||
using string_type = std::basic_string<char_type, traits_type>;
|
||||
using string_view_type = basic_string_view<char_type, traits_type>;
|
||||
|
||||
key() {}
|
||||
key() noexcept = default;
|
||||
key( const key& p ) = default;
|
||||
key( key&& p ) noexcept = default;
|
||||
key( const string_type& source ) : value_(source) {}
|
||||
@@ -524,11 +524,7 @@ struct key
|
||||
~key() = default;
|
||||
|
||||
key& operator=( const key& p ) = default;
|
||||
key& operator=( key&& p )
|
||||
{
|
||||
value_ = std::move(p.value_);
|
||||
return *this;
|
||||
}
|
||||
key& operator=( key&& p ) noexcept = default;
|
||||
key& operator=( string_type&& source )
|
||||
{
|
||||
value_ = std::move(source);
|
||||
@@ -712,7 +708,7 @@ struct value
|
||||
using string_type = std::basic_string<char_type, traits_type>;
|
||||
using string_view_type = basic_cstring_ref<char_type, traits_type>;
|
||||
|
||||
value() {}
|
||||
value() noexcept = default;
|
||||
value( const value& p ) = default;
|
||||
|
||||
value( const string_type& source ) : value_(source) {}
|
||||
@@ -746,11 +742,7 @@ struct value
|
||||
~value() = default;
|
||||
|
||||
value& operator=( const value& p ) = default;
|
||||
value& operator=( value&& p )
|
||||
{
|
||||
value_ = std::move(p.value_);
|
||||
return *this;
|
||||
}
|
||||
value& operator=( value&& p ) noexcept = default;
|
||||
value& operator=( string_type&& source )
|
||||
{
|
||||
value_ = std::move(source);
|
||||
@@ -943,7 +935,7 @@ struct key_value_pair
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using string_view_type = basic_cstring_ref<char_type>;
|
||||
|
||||
key_value_pair() {}
|
||||
key_value_pair() noexcept = default;
|
||||
key_value_pair( const key_value_pair& p ) = default;
|
||||
key_value_pair( key_value_pair&& p ) noexcept = default;
|
||||
key_value_pair(key_view key, value_view value) : value_(key.basic_string<char_type, traits_type>() + equality_sign +
|
||||
@@ -1007,11 +999,7 @@ struct key_value_pair
|
||||
~key_value_pair() = default;
|
||||
|
||||
key_value_pair& operator=( const key_value_pair& p ) = default;
|
||||
key_value_pair& operator=( key_value_pair&& p )
|
||||
{
|
||||
value_ = std::move(p.value_);
|
||||
return *this;
|
||||
}
|
||||
key_value_pair& operator=( key_value_pair&& p ) noexcept = default;
|
||||
key_value_pair& operator=( string_type&& source )
|
||||
{
|
||||
value_ = std::move(source);
|
||||
|
||||
@@ -22,7 +22,7 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
* @tparam Executor The asio executor of the process handle
|
||||
* @param proc The process to be run.
|
||||
* @return int The exit code of the process
|
||||
* @exception system_error An error that might have occurred during the wait.
|
||||
* @exception system_error An error that might have occured during the wait.
|
||||
*/
|
||||
template<typename Executor>
|
||||
inline int execute(basic_process<Executor> proc)
|
||||
@@ -92,13 +92,13 @@ struct execute_op
|
||||
/** This function asynchronously for a process to complete.
|
||||
*
|
||||
* Cancelling the execution will signal the child process to exit
|
||||
* with the following interpretations:
|
||||
* with the following intepretations:
|
||||
*
|
||||
* - cancellation_type::total -> interrupt
|
||||
* - cancellation_type::partial -> request_exit
|
||||
* - cancellation_type::terminal -> terminate
|
||||
*
|
||||
* It is to note that `async_execute` will us the lowest selected cancellation
|
||||
* It is to note that `async_execute` will us the lowest seelected cancellation
|
||||
* type. A subprocess might ignore anything not terminal.
|
||||
*/
|
||||
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor,
|
||||
|
||||
@@ -12,15 +12,7 @@
|
||||
#define BOOST_PROCESS_V2_EXIT_CODE_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/error.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
#include <asio/associator.hpp>
|
||||
#include <asio/async_result.hpp>
|
||||
#else
|
||||
#include <boost/asio/associator.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#endif
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_POSIX)
|
||||
#include <sys/wait.h>
|
||||
@@ -28,6 +20,15 @@
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
/// Result of a single process exiting.
|
||||
struct single_process_exit
|
||||
{
|
||||
/// The pid of the process that exited
|
||||
pid_type pid;
|
||||
/// The exit code of the code
|
||||
int exit_code;
|
||||
};
|
||||
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
/// The native exit-code type, usually an integral value
|
||||
@@ -94,157 +95,6 @@ inline int evaluate_exit_code(int code)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** Convert the exit-code in a completion into an error if the actual error isn't set.
|
||||
* @code {.cpp}
|
||||
* process proc{ctx, "exit", {"1"}};
|
||||
*
|
||||
* proc.async_wait(code_as_error(
|
||||
* [](error_code ec)
|
||||
* {
|
||||
* assert(ec.value() == 10);
|
||||
* assert(ec.category() == error::get_exit_code_category());
|
||||
* }));
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
template<typename CompletionToken>
|
||||
struct code_as_error_t
|
||||
{
|
||||
CompletionToken token_;
|
||||
const error_category & category;
|
||||
|
||||
template<typename Token_>
|
||||
code_as_error_t(Token_ && token, const error_category & category)
|
||||
: token_(std::forward<Token_>(token)), category(category)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// Deduction function for code_as_error_t.
|
||||
template<typename CompletionToken>
|
||||
code_as_error_t<CompletionToken> code_as_error(
|
||||
CompletionToken && token,
|
||||
const error_category & category = error::get_exit_code_category())
|
||||
{
|
||||
return code_as_error_t<typename std::decay<CompletionToken>::type>(
|
||||
std::forward<CompletionToken>(token), category);
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename Handler>
|
||||
struct code_as_error_handler
|
||||
{
|
||||
typedef void result_type;
|
||||
|
||||
template<typename H>
|
||||
code_as_error_handler(H && h, const error_category & category)
|
||||
: handler_(std::forward<H>(h)), category(category)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(error_code ec, native_exit_code_type code)
|
||||
{
|
||||
if (!ec)
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, code, category)
|
||||
std::move(handler_)(ec);
|
||||
}
|
||||
|
||||
|
||||
Handler handler_;
|
||||
const error_category & category;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
namespace boost
|
||||
{
|
||||
#endif
|
||||
namespace asio
|
||||
{
|
||||
|
||||
template <typename CompletionToken>
|
||||
struct async_result<
|
||||
BOOST_PROCESS_V2_NAMESPACE::code_as_error_t<CompletionToken>,
|
||||
void(BOOST_PROCESS_V2_NAMESPACE::error_code,
|
||||
BOOST_PROCESS_V2_NAMESPACE::native_exit_code_type)>
|
||||
{
|
||||
using signature = void(BOOST_PROCESS_V2_NAMESPACE::error_code);
|
||||
using return_type = typename async_result<CompletionToken, void(BOOST_PROCESS_V2_NAMESPACE::error_code)>::return_type;
|
||||
|
||||
|
||||
template <typename Initiation>
|
||||
struct init_wrapper
|
||||
{
|
||||
init_wrapper(Initiation init)
|
||||
: initiation_(std::move(init))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Handler, typename... Args>
|
||||
void operator()(
|
||||
Handler && handler,
|
||||
const BOOST_PROCESS_V2_NAMESPACE::error_category & cat,
|
||||
Args && ... args)
|
||||
{
|
||||
std::move(initiation_)(
|
||||
BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<typename decay<Handler>::type>(
|
||||
std::forward<Handler>(handler), cat),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
Initiation initiation_;
|
||||
|
||||
};
|
||||
|
||||
template <typename Initiation, typename RawCompletionToken, typename... Args>
|
||||
static BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, signature,
|
||||
(async_initiate<CompletionToken, signature>(
|
||||
declval<init_wrapper<typename decay<Initiation>::type> >(),
|
||||
declval<CompletionToken&>(),
|
||||
declval<BOOST_ASIO_MOVE_ARG(Args)>()...)))
|
||||
initiate(
|
||||
Initiation && initiation,
|
||||
RawCompletionToken && token,
|
||||
Args &&... args)
|
||||
{
|
||||
return async_initiate<CompletionToken, signature>(
|
||||
init_wrapper<typename decay<Initiation>::type>(
|
||||
std::forward<Initiation>(initiation)),
|
||||
token.token_,
|
||||
token.category,
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<template <typename, typename> class Associator, typename Handler, typename DefaultCandidate>
|
||||
struct associator<Associator,
|
||||
BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<Handler>, DefaultCandidate>
|
||||
: Associator<Handler, DefaultCandidate>
|
||||
{
|
||||
static typename Associator<Handler, DefaultCandidate>::type get(
|
||||
const BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<Handler> & h,
|
||||
const DefaultCandidate& c = DefaultCandidate()) noexcept
|
||||
{
|
||||
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#if !defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
} // boost
|
||||
#endif
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_EXIT_CODE_HPP
|
||||
@@ -1,16 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net)
|
||||
//
|
||||
// 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_EXT_HPP
|
||||
#define BOOST_PROCESS_V2_EXT_HPP
|
||||
|
||||
#include <boost/process/v2/ext/cmd.hpp>
|
||||
#include <boost/process/v2/ext/cwd.hpp>
|
||||
#include <boost/process/v2/ext/env.hpp>
|
||||
#include <boost/process/v2/ext/exe.hpp>
|
||||
|
||||
#endif //BOOST_PROCESS_V2_EXT_HPP
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_CMD_HPP
|
||||
#define BOOST_PROCESS_V2_CMD_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/process_handle.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#include <boost/process/v2/shell.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace ext {
|
||||
|
||||
/// @{
|
||||
/// Get the argument vector of another process
|
||||
BOOST_PROCESS_V2_DECL shell cmd(pid_type pid, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL shell cmd(pid_type pid);
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
BOOST_PROCESS_V2_DECL shell cmd(HANDLE handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL shell cmd(HANDLE handle);
|
||||
#endif
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL shell cmd(basic_process_handle<Executor> & handle, error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return cmd(handle.native_handle(), ec);
|
||||
#else
|
||||
return cmd(handle.id(), ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL shell cmd(basic_process_handle<Executor> & handle)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return cmd(handle.native_handle());
|
||||
#else
|
||||
return cmd(handle.id());
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
#include <boost/process/v2/ext/impl/cmd.ipp>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // BOOST_PROCESS_V2_CMD_HPP
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_CWD_HPP
|
||||
#define BOOST_PROCESS_V2_CWD_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace ext {
|
||||
|
||||
/// @{
|
||||
/// Obtain the current path of another process
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(pid_type pid, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(pid_type pid);
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(basic_process_handle<Executor> & handle, error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return cwd(handle.native_handle(), ec);
|
||||
#else
|
||||
return cwd(handle.id(), ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(basic_process_handle<Executor> & handle)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return cwd(handle.native_handle());
|
||||
#else
|
||||
return cwd(handle.id());
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(HANDLE handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL filesystem::path cwd(HANDLE handle);
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
#include <boost/process/v2/ext/impl/cwd.ipp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PROCESS_V2_CWD_HPP
|
||||
@@ -1,127 +0,0 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_IMPL_DETAIL_PROC_INFO_IPP
|
||||
#define BOOST_PROCESS_V2_IMPL_DETAIL_PROC_INFO_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <cstdlib>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/proc_info.h>
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
namespace ext
|
||||
{
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
// type of process memory to read?
|
||||
enum MEMTYP {MEMCMD, MEMCWD};
|
||||
std::wstring cwd_cmd_from_proc(HANDLE proc, int type, boost::system::error_code & ec)
|
||||
{
|
||||
std::wstring buffer;
|
||||
PEB peb;
|
||||
SIZE_T nRead = 0;
|
||||
ULONG len = 0;
|
||||
PROCESS_BASIC_INFORMATION pbi;
|
||||
RTL_USER_PROCESS_PARAMETERS_EXTENDED upp;
|
||||
|
||||
NTSTATUS status = 0;
|
||||
PVOID buf = nullptr;
|
||||
status = NtQueryInformationProcess(proc, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
|
||||
ULONG error = RtlNtStatusToDosError(status);
|
||||
|
||||
if (error)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error, boost::system::system_category())
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(proc, pbi.PebBaseAddress, &peb, sizeof(peb), &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(proc, peb.ProcessParameters, &upp, sizeof(upp), &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
if (type == MEMCWD)
|
||||
{
|
||||
buf = upp.CurrentDirectory.DosPath.Buffer;
|
||||
len = upp.CurrentDirectory.DosPath.Length;
|
||||
}
|
||||
else if (type == MEMCMD)
|
||||
{
|
||||
buf = upp.CommandLine.Buffer;
|
||||
len = upp.CommandLine.Length;
|
||||
}
|
||||
|
||||
buffer.resize(len / 2 + 1);
|
||||
|
||||
if (!ReadProcessMemory(proc, buf, &buffer[0], len, &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
buffer.pop_back();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// with debug_privilege enabled allows reading info from more processes
|
||||
// this includes stuff such as exe path, cwd path, cmdline, and environ
|
||||
HANDLE open_process_with_debug_privilege(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
HANDLE proc = nullptr;
|
||||
HANDLE hToken = nullptr;
|
||||
LUID luid;
|
||||
TOKEN_PRIVILEGES tkp;
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
||||
{
|
||||
if (LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &luid))
|
||||
{
|
||||
tkp.PrivilegeCount = 1;
|
||||
tkp.Privileges[0].Luid = luid;
|
||||
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
if (AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), nullptr, nullptr))
|
||||
{
|
||||
proc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
|
||||
}
|
||||
}
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
if (!proc)
|
||||
proc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
|
||||
if (!proc)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return proc;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace ext
|
||||
|
||||
} // namespace detail
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_IMPL_DETAIL_PROC_INFO_IPP
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_DETAIL_PROC_INFO_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_PROC_INFO_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
extern "C" ULONG NTAPI RtlNtStatusToDosError(NTSTATUS Status);
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
namespace ext
|
||||
{
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#if !defined(_MSC_VER)
|
||||
#pragma pack(push, 8)
|
||||
#else
|
||||
#include <pshpack8.h>
|
||||
#endif
|
||||
|
||||
/* CURDIR struct from:
|
||||
https://github.com/processhacker/phnt/
|
||||
CC BY 4.0 licence */
|
||||
|
||||
typedef struct {
|
||||
UNICODE_STRING DosPath;
|
||||
HANDLE Handle;
|
||||
} CURDIR;
|
||||
|
||||
/* RTL_DRIVE_LETTER_CURDIR struct from:
|
||||
https://github.com/processhacker/phnt/
|
||||
CC BY 4.0 licence */
|
||||
|
||||
typedef struct {
|
||||
USHORT Flags;
|
||||
USHORT Length;
|
||||
ULONG TimeStamp;
|
||||
STRING DosPath;
|
||||
} RTL_DRIVE_LETTER_CURDIR;
|
||||
|
||||
/* RTL_USER_PROCESS_PARAMETERS struct from:
|
||||
https://github.com/processhacker/phnt/
|
||||
CC BY 4.0 licence */
|
||||
|
||||
typedef struct {
|
||||
ULONG MaximumLength;
|
||||
ULONG Length;
|
||||
ULONG Flags;
|
||||
ULONG DebugFlags;
|
||||
HANDLE ConsoleHandle;
|
||||
ULONG ConsoleFlags;
|
||||
HANDLE StandardInput;
|
||||
HANDLE StandardOutput;
|
||||
HANDLE StandardError;
|
||||
CURDIR CurrentDirectory;
|
||||
UNICODE_STRING DllPath;
|
||||
UNICODE_STRING ImagePathName;
|
||||
UNICODE_STRING CommandLine;
|
||||
PVOID Environment;
|
||||
ULONG StartingX;
|
||||
ULONG StartingY;
|
||||
ULONG CountX;
|
||||
ULONG CountY;
|
||||
ULONG CountCharsX;
|
||||
ULONG CountCharsY;
|
||||
ULONG FillAttribute;
|
||||
ULONG WindowFlags;
|
||||
ULONG ShowWindowFlags;
|
||||
UNICODE_STRING WindowTitle;
|
||||
UNICODE_STRING DesktopInfo;
|
||||
UNICODE_STRING ShellInfo;
|
||||
UNICODE_STRING RuntimeData;
|
||||
RTL_DRIVE_LETTER_CURDIR CurrentDirectories[32];
|
||||
ULONG_PTR EnvironmentSize;
|
||||
ULONG_PTR EnvironmentVersion;
|
||||
PVOID PackageDependencyData;
|
||||
ULONG ProcessGroupId;
|
||||
ULONG LoaderThreads;
|
||||
UNICODE_STRING RedirectionDllName;
|
||||
UNICODE_STRING HeapPartitionName;
|
||||
ULONG_PTR DefaultThreadpoolCpuSetMasks;
|
||||
ULONG DefaultThreadpoolCpuSetMaskCount;
|
||||
} RTL_USER_PROCESS_PARAMETERS_EXTENDED;
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#pragma pack(pop)
|
||||
#else
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
BOOST_PROCESS_V2_DECL std::wstring cwd_cmd_from_proc(HANDLE proc, int type, boost::system::error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL HANDLE open_process_with_debug_privilege(boost::process::v2::pid_type pid, boost::system::error_code & ec);
|
||||
#endif
|
||||
|
||||
} // namespace ext
|
||||
|
||||
} // namespace detail
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
#include <boost/process/v2/ext/detail/impl/proc_info.ipp>
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PROCESS_V2_DETAIL_PROC_INFO_HPP
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_ENV_HPP
|
||||
#define BOOST_PROCESS_V2_ENV_HPP
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/process_handle.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#include <boost/process/v2/environment.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace ext
|
||||
{
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
using native_env_handle_type = wchar_t *;
|
||||
using native_env_iterator = wchar_t *;
|
||||
#elif defined(__FreeBSD__)
|
||||
using native_env_handle_type = char **;
|
||||
using native_env_iterator = char **;
|
||||
#else
|
||||
using native_env_handle_type = char *;
|
||||
using native_env_iterator = char *;
|
||||
#endif
|
||||
|
||||
struct native_env_handle_deleter
|
||||
{
|
||||
BOOST_PROCESS_V2_DECL void operator()(native_env_handle_type) const;
|
||||
};
|
||||
|
||||
BOOST_PROCESS_V2_DECL native_env_iterator next(native_env_iterator nh);
|
||||
BOOST_PROCESS_V2_DECL native_env_iterator find_end(native_env_iterator nh);
|
||||
BOOST_PROCESS_V2_DECL const environment::char_type * dereference(native_env_iterator iterator);
|
||||
|
||||
} // namespace ext
|
||||
} // namespace detail
|
||||
|
||||
namespace ext {
|
||||
|
||||
/// The view of an environment
|
||||
struct env_view
|
||||
{
|
||||
using native_handle_type = detail::ext::native_env_handle_type;
|
||||
using value_type = environment::key_value_pair_view;
|
||||
|
||||
env_view() = default;
|
||||
env_view(env_view && nt) = default;
|
||||
|
||||
native_handle_type native_handle() { return handle_.get(); }
|
||||
|
||||
|
||||
struct iterator
|
||||
{
|
||||
using value_type = environment::key_value_pair_view;
|
||||
using difference_type = int;
|
||||
using reference = environment::key_value_pair_view;
|
||||
using pointer = environment::key_value_pair_view;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
iterator() = default;
|
||||
iterator(const iterator & ) = default;
|
||||
iterator(const detail::ext::native_env_iterator &native_handle) : iterator_(native_handle) {}
|
||||
|
||||
iterator & operator++()
|
||||
{
|
||||
iterator_ = detail::ext::next(iterator_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
auto last = *this;
|
||||
iterator_ = detail::ext::next(iterator_);
|
||||
return last;
|
||||
}
|
||||
environment::key_value_pair_view operator*() const
|
||||
{
|
||||
return detail::ext::dereference(iterator_);
|
||||
}
|
||||
|
||||
friend bool operator==(const iterator & l, const iterator & r) {return l.iterator_ == r.iterator_;}
|
||||
friend bool operator!=(const iterator & l, const iterator & r) {return l.iterator_ != r.iterator_;}
|
||||
|
||||
private:
|
||||
detail::ext::native_env_iterator iterator_;
|
||||
};
|
||||
|
||||
iterator begin() const {return iterator(handle_.get());}
|
||||
iterator end() const {return iterator(detail::ext::find_end(handle_.get()));}
|
||||
|
||||
private:
|
||||
friend BOOST_PROCESS_V2_DECL env_view env(pid_type pid, error_code & ec);
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
friend BOOST_PROCESS_V2_DECL env_view env(HANDLE handle, error_code & ec);
|
||||
#endif
|
||||
|
||||
std::unique_ptr<typename remove_pointer<detail::ext::native_env_handle_type>::type,
|
||||
detail::ext::native_env_handle_deleter> handle_;
|
||||
};
|
||||
|
||||
/// @{
|
||||
/// Get the environment of another process.
|
||||
BOOST_PROCESS_V2_DECL env_view env(pid_type pid, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL env_view env(pid_type pid);
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL env_view env(basic_process_handle<Executor> & handle, error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return env(handle.native_handle(), ec);
|
||||
#else
|
||||
return env(handle.id(), ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
BOOST_PROCESS_V2_DECL env_view env(basic_process_handle<Executor> & handle)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return env(handle.native_handle());
|
||||
#else
|
||||
return env(handle.id());
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
BOOST_PROCESS_V2_DECL env_view env(HANDLE handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL env_view env(HANDLE handle);
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
#include <boost/process/v2/ext/impl/env.ipp>
|
||||
|
||||
#endif
|
||||
#endif // BOOST_PROCESS_V2_ENV_HPP
|
||||
@@ -1,62 +0,0 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_EXE_HPP
|
||||
#define BOOST_PROCESS_V2_EXE_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
|
||||
#include <boost/process/v2/process_handle.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace ext {
|
||||
|
||||
/// @{
|
||||
/// Return the executable of another process by pid or handle.
|
||||
BOOST_PROCESS_V2_DECL filesystem::path exe(pid_type pid, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL filesystem::path exe(pid_type pid);
|
||||
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
filesystem::path exe(basic_process_handle<Executor> & handle, error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return exe(handle.native_handle(), ec);
|
||||
#else
|
||||
return exe(handle.id(), ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
filesystem::path exe(basic_process_handle<Executor> & handle)
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
return exe(handle.native_handle());
|
||||
#else
|
||||
return exe(handle.id());
|
||||
#endif
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
BOOST_PROCESS_V2_DECL filesystem::path exe(HANDLE handle, error_code & ec);
|
||||
BOOST_PROCESS_V2_DECL filesystem::path exe(HANDLE handle);
|
||||
#endif
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
#include <boost/process/v2/ext/impl/exe.ipp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PROCESS_V2_EXE_HPP
|
||||
|
||||
@@ -1,460 +0,0 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_IMPL_CMD_IPP
|
||||
#define BOOST_PROCESS_V2_IMPL_CMD_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
#include <boost/process/v2/ext/cmd.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if (defined(__linux__) || defined(__ANDROID__))
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/user.h>
|
||||
#include <libprocstat.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__DragonFly__) || defined(__OpenBSD__))
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
#include <kvm.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <kvm.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__sun)
|
||||
#include <sys/types.h>
|
||||
#include <kvm.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/proc.h>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
struct make_cmd_shell_
|
||||
{
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
static shell make(std::wstring data)
|
||||
{
|
||||
shell res;
|
||||
res.input_ = res.buffer_ = std::move(data);
|
||||
res.parse_();
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
static shell make(std::string data,
|
||||
int argc, char ** argv,
|
||||
void(*free_func)(int, char**))
|
||||
{
|
||||
shell res;
|
||||
res.argc_ = argc;
|
||||
res.input_ = res.buffer_ = std::move(data);
|
||||
res.argv_ = argv;
|
||||
res.free_argv_ = free_func;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static shell clone(char ** cmd)
|
||||
{
|
||||
shell res;
|
||||
res.argc_ = 0;
|
||||
std::size_t str_lengths = 0;
|
||||
for (auto c = cmd; *c != nullptr; c++)
|
||||
{
|
||||
res.argc_++;
|
||||
str_lengths += (std::strlen(*c) + 1);
|
||||
}
|
||||
// yes, not the greatest solution.
|
||||
res.buffer_.resize(str_lengths);
|
||||
|
||||
res.argv_ = new char*[res.argc_ + 1];
|
||||
res.free_argv_ = +[](int argc, char ** argv) {delete[] argv;};
|
||||
res.argv_[res.argc_] = nullptr;
|
||||
auto p = &*res.buffer_.begin();
|
||||
|
||||
for (int i = 0; i < res.argc_; i++)
|
||||
{
|
||||
const auto ln = std::strlen(cmd[i]);
|
||||
res.argv_[i] = std::strcpy(p, cmd[i]);
|
||||
p += (ln + 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace ext {
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
shell cmd(HANDLE proc, error_code & ec)
|
||||
{
|
||||
std::wstring buffer = boost::process::v2::detail::ext::cwd_cmd_from_proc(proc, 0/*=MEMCMD*/, ec);
|
||||
|
||||
if (!ec)
|
||||
return make_cmd_shell_::make(std::move(buffer));
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
shell cmd(HANDLE proc)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = cmd(proc, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "cmd");
|
||||
return res;
|
||||
}
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
struct del
|
||||
{
|
||||
void operator()(HANDLE h)
|
||||
{
|
||||
::CloseHandle(h);
|
||||
};
|
||||
};
|
||||
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
|
||||
if (proc == nullptr)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
else
|
||||
return cmd(proc.get(), ec);
|
||||
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
int mib[3] = {CTL_KERN, KERN_ARGMAX, 0};
|
||||
int argmax = 0;
|
||||
auto size = sizeof(argmax);
|
||||
if (sysctl(mib, 2, &argmax, &size, nullptr, 0) == -1)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string procargs;
|
||||
procargs.resize(argmax - 1);
|
||||
mib[1] = KERN_PROCARGS;
|
||||
mib[2] = pid;
|
||||
|
||||
size = argmax;
|
||||
|
||||
if (sysctl(mib, 3, &*procargs.begin(), &size, nullptr, 0) != 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
int argc = *reinterpret_cast<const int*>(procargs.data());
|
||||
auto itr = procargs.begin() + sizeof(argc);
|
||||
|
||||
std::unique_ptr<char*[]> argv{new char*[argc + 1]};
|
||||
const auto end = procargs.end();
|
||||
|
||||
argv[argc] = nullptr; //args is a null-terminated list
|
||||
|
||||
for (auto n = 0u; n <= argc; n++)
|
||||
{
|
||||
auto e = std::find(itr, end, '\0');
|
||||
if (e == end && n < argc) // something off
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, EINVAL, system_category())
|
||||
return {};
|
||||
}
|
||||
argv[n] = &*itr;
|
||||
itr = e + 1; // start searching start
|
||||
}
|
||||
|
||||
auto fr_func = +[](int argc, char ** argv) {delete [] argv;};
|
||||
|
||||
return make_cmd_shell_::make(std::move(procargs), argc, argv.release(), fr_func);
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__))
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::string procargs;
|
||||
procargs.resize(4096);
|
||||
int f = ::open(("/proc/" + std::to_string(pid) + "/cmdline").c_str(), O_RDONLY);
|
||||
|
||||
while (procargs.back() != EOF)
|
||||
{
|
||||
auto r = ::read(f, &*(procargs.end() - 4096), 4096);
|
||||
if (r < 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
::close(f);
|
||||
return {};
|
||||
}
|
||||
if (r < 4096) // done!
|
||||
{
|
||||
procargs.resize(procargs.size() - 4096 + r);
|
||||
break;
|
||||
}
|
||||
procargs.resize(procargs.size() + 4096);
|
||||
}
|
||||
::close(f);
|
||||
|
||||
if (procargs.back() == EOF)
|
||||
procargs.pop_back();
|
||||
|
||||
auto argc = std::count(procargs.begin(), procargs.end(), '\0');
|
||||
|
||||
auto itr = procargs.begin();
|
||||
|
||||
std::unique_ptr<char*[]> argv{new char*[argc + 1]};
|
||||
const auto end = procargs.end();
|
||||
|
||||
argv[argc] = nullptr; //args is a null-terminated list
|
||||
|
||||
|
||||
for (auto n = 0u; n <= argc; n++)
|
||||
{
|
||||
auto e = std::find(itr, end, '\0');
|
||||
if (e == end && n < argc) // something off
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, EINVAL, system_category())
|
||||
return {};
|
||||
}
|
||||
argv[n] = &*itr;
|
||||
itr = e + 1; // start searching start
|
||||
}
|
||||
|
||||
auto fr_func = +[](int argc, char ** argv) {delete [] argv;};
|
||||
|
||||
return make_cmd_shell_::make(std::move(procargs), argc, argv.release(), fr_func);
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
struct cl_proc_stat
|
||||
{
|
||||
void operator()(struct procstat *proc_stat)
|
||||
{
|
||||
procstat_close(proc_stat);
|
||||
}
|
||||
};
|
||||
std::unique_ptr<struct procstat, cl_proc_stat> proc_stat{procstat_open_sysctl()};
|
||||
if (!proc_stat)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
struct proc_info_close
|
||||
{
|
||||
struct procstat * proc_stat;
|
||||
|
||||
void operator()(struct kinfo_proc * proc_info)
|
||||
{
|
||||
procstat_freeprocs(proc_stat, proc_info);
|
||||
}
|
||||
};
|
||||
|
||||
unsigned cntp;
|
||||
std::unique_ptr<struct kinfo_proc, proc_info_close> proc_info{
|
||||
procstat_getprocs(proc_stat.get(), KERN_PROC_PID, pid, &cntp),
|
||||
proc_info_close{proc_stat.get()}};
|
||||
|
||||
if (!proc_info)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
char **cmd = procstat_getargv(proc_stat.get(), proc_info.get(), 0);
|
||||
if (!cmd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
auto res = make_cmd_shell_::clone(cmd);
|
||||
procstat_freeargv(proc_stat.get());
|
||||
return res;
|
||||
}
|
||||
|
||||
#elif defined(__DragonFly__)
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
const char *nlistf, *memf;
|
||||
nlistf = memf = "/dev/null";
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return {};}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, &cntp)))
|
||||
{
|
||||
char **cmd = kvm_getargv(kd.get(), proc_info, 0);
|
||||
if (cmd)
|
||||
return make_cmd_shell_::clone(cmd);
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
|
||||
std::vector<std::string> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc2 *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
|
||||
if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return vec;}
|
||||
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc2), &cntp)))
|
||||
{
|
||||
char **cmd = kvm_getargv2(kd.get(), proc_info, 0);
|
||||
if (cmd)
|
||||
return make_cmd_shell_::clone(cmd);
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<std::string> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return vec;}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &cntp)))
|
||||
{
|
||||
char **cmd = kvm_getargv(kd.get(), proc_info, 0);
|
||||
if (cmd)
|
||||
return make_cmd_shell_::clone(cmd);
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
kvm_close(kd);
|
||||
return {};
|
||||
}
|
||||
|
||||
#elif defined(__sun)
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
char **cmd = nullptr;
|
||||
proc *proc_info = nullptr;
|
||||
user *proc_user = nullptr;
|
||||
kd = kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr);
|
||||
if (!kd) {BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) return {};}
|
||||
if ((proc_info = kvm_getproc(kd, pid)))
|
||||
{
|
||||
if ((proc_user = kvm_getu(kd, proc_info)))
|
||||
{
|
||||
if (!kvm_getcmd(kd, proc_info, proc_user, &cmd, nullptr))
|
||||
{
|
||||
int argc = 0;
|
||||
for (int i = 0; cmd[i] != nullptr; i++)
|
||||
argc ++;
|
||||
return make_cmd_shell_::make(
|
||||
{}, argc, cmd,
|
||||
+[](int, char ** argv) {::free(argv);})
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
|
||||
kvm_close(kd);
|
||||
return {};
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
|
||||
shell cmd(boost::process::v2::pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = cmd(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "cmd");
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_IMPL_CMD_IPP
|
||||
|
||||
@@ -1,234 +0,0 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_IMPL_CWD_IPP
|
||||
#define BOOST_PROCESS_V2_IMPL_CWD_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
#include <boost/process/v2/ext/cwd.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <climits>
|
||||
#endif
|
||||
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <sys/proc_info.h>
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
||||
#if (defined(BOOST_PROCESS_V2_WINDOWS) || defined(__linux__) || defined(__ANDROID__) || defined(__sun))
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/user.h>
|
||||
#include <libprocstat.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__NetBSD__) || defined(__OpenBSD__))
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__DragonFly__)
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_PROCESS_USE_STD_FS
|
||||
namespace filesystem = std::filesystem;
|
||||
#else
|
||||
namespace filesystem = boost::filesystem;
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace ext {
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
filesystem::path cwd(HANDLE proc, boost::system::error_code & ec)
|
||||
{
|
||||
auto buffer = boost::process::v2::detail::ext::cwd_cmd_from_proc(proc, 1/*=MEMCWD*/, ec);
|
||||
if (!buffer.empty())
|
||||
return filesystem::canonical(buffer, ec);
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return "";
|
||||
}
|
||||
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
struct del
|
||||
{
|
||||
void operator()(HANDLE h)
|
||||
{
|
||||
::CloseHandle(h);
|
||||
};
|
||||
};
|
||||
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
|
||||
if (proc == nullptr)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
else
|
||||
return cwd(proc.get(), ec);
|
||||
return {};
|
||||
}
|
||||
|
||||
filesystem::path cwd(HANDLE proc)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = cwd(proc, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "cwd");
|
||||
return res;
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
proc_vnodepathinfo vpi;
|
||||
if (proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi)) > 0)
|
||||
return filesystem::canonical(vpi.pvi_cdir.vip_path, ec);
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return "";
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__) || defined(__sun))
|
||||
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
return filesystem::canonical(
|
||||
filesystem::path("/proc") / std::to_string(pid) / "cwd", ec);
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
// FIXME: Add error handling.
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
filesystem::path path;
|
||||
unsigned cntp = 0;
|
||||
procstat *proc_stat = procstat_open_sysctl();
|
||||
if (proc_stat) {
|
||||
kinfo_proc *proc_info = procstat_getprocs(proc_stat, KERN_PROC_PID, pid, &cntp);
|
||||
if (proc_info) {
|
||||
filestat_list *head = procstat_getfiles(proc_stat, proc_info, 0);
|
||||
if (head) {
|
||||
filestat *fst = nullptr;
|
||||
STAILQ_FOREACH(fst, head, next) {
|
||||
if (fst->fs_uflags & PS_FST_UFLAG_CDIR)
|
||||
{
|
||||
path = filesystem::canonical(fst->fs_path, ec);
|
||||
}
|
||||
}
|
||||
procstat_freefiles(proc_stat, head);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
procstat_freeprocs(proc_stat, proc_info);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
procstat_close(proc_stat);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return path;
|
||||
}
|
||||
|
||||
#elif defined(__DragonFly__)
|
||||
|
||||
// FIXME: Add error handling.
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
filesystem::path path;
|
||||
/* Probably the hackiest thing ever we are doing here, because the "official" API is broken OS-level. */
|
||||
FILE *fp = popen(("pos=`ans=\\`/usr/bin/fstat -w -p " + std::to_string(pid) + " | /usr/bin/sed -n 1p\\`; " +
|
||||
"/usr/bin/awk -v ans=\"$ans\" 'BEGIN{print index(ans, \"INUM\")}'`; str=`/usr/bin/fstat -w -p " +
|
||||
std::to_string(pid) + " | /usr/bin/sed -n 3p`; /usr/bin/awk -v str=\"$str\" -v pos=\"$pos\" " +
|
||||
"'BEGIN{print substr(str, 0, pos + 4)}' | /usr/bin/awk 'NF{NF--};1 {$1=$2=$3=$4=\"\"; print" +
|
||||
" substr($0, 5)'}").c_str(), "r");
|
||||
if (fp)
|
||||
{
|
||||
char buffer[PATH_MAX];
|
||||
if (fgets(buffer, sizeof(buffer), fp))
|
||||
{
|
||||
std::string str = buffer;
|
||||
std::size_t pos = str.find("\n", strlen(buffer) - 1);
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
str.replace(pos, 1, "");
|
||||
}
|
||||
path = filesystem::canonical(str.c_str(), ec);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
pclose(fp);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return path;
|
||||
}
|
||||
|
||||
#elif (defined(__NetBSD__) || defined(__OpenBSD__))
|
||||
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::string path;
|
||||
#if defined(__NetBSD__)
|
||||
int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_CWD};
|
||||
const std::size_t sz = 4;
|
||||
#elif defined(__OpenBSD__)
|
||||
int mib[3] = {CTL_KERN, KERN_PROC_CWD, pid};
|
||||
const std::size_t sz = 3;
|
||||
#endif
|
||||
std::size_t len = 0;
|
||||
if (sysctl(mib, sz, nullptr, &len, nullptr, 0) == 0)
|
||||
{
|
||||
std::string strbuff;
|
||||
strbuff.resize(len);
|
||||
if (sysctl(mib, 4, &strbuff[0], &len, nullptr, 0) == 0)
|
||||
{
|
||||
filesystem::canonical(strbuff, ec);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
|
||||
filesystem::path cwd(boost::process::v2::pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = cwd(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "cwd");
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_IMPL_CWD_IPP
|
||||
|
||||
@@ -1,389 +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_EXT_IMPL_ENV_IPP
|
||||
#define BOOST_PROCESS_V2_EXT_IMPL_ENV_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
#include <boost/process/v2/ext/env.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <shellapi.h>
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if (defined(__linux__) || defined(__ANDROID__))
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
namespace ext {
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
void native_env_handle_deleter::operator()(native_env_handle_type h) const
|
||||
{
|
||||
delete [] h;
|
||||
}
|
||||
|
||||
native_env_iterator next(native_env_iterator nh)
|
||||
{
|
||||
while (*nh != L'\0')
|
||||
nh ++;
|
||||
return ++nh ;
|
||||
}
|
||||
native_env_iterator find_end(native_env_iterator nh)
|
||||
{
|
||||
while (*nh - 1 != L'\0' && *nh != L'\0')
|
||||
nh ++;
|
||||
return nh ;
|
||||
}
|
||||
|
||||
const environment::char_type * dereference(native_env_iterator iterator)
|
||||
{
|
||||
return iterator;
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__))
|
||||
//linux stores this as a blob with an EOF at the end
|
||||
|
||||
void native_env_handle_deleter::operator()(native_env_handle_type h) const
|
||||
{
|
||||
delete [] h;
|
||||
}
|
||||
|
||||
native_env_iterator next(native_env_iterator nh)
|
||||
{
|
||||
while (*nh != '\0')
|
||||
nh ++;
|
||||
return ++nh ;
|
||||
}
|
||||
native_env_iterator find_end(native_env_iterator nh)
|
||||
{
|
||||
while (*nh != EOF)
|
||||
nh ++;
|
||||
return nh ;
|
||||
}
|
||||
|
||||
const environment::char_type * dereference(native_env_iterator iterator)
|
||||
{
|
||||
return iterator;
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE___) || defined(__MACH__))
|
||||
|
||||
void native_env_handle_deleter::operator()(native_env_handle_type h) const
|
||||
{
|
||||
delete [] h;
|
||||
}
|
||||
|
||||
native_env_iterator next(native_env_iterator nh)
|
||||
{
|
||||
while (*nh != '\0')
|
||||
nh ++;
|
||||
return ++nh ;
|
||||
}
|
||||
native_env_iterator find_end(native_env_iterator nh)
|
||||
{
|
||||
while (*nh - 1 != '\0' && *nh != '\0')
|
||||
nh ++;
|
||||
return nh ;
|
||||
}
|
||||
|
||||
const environment::char_type * dereference(native_env_iterator iterator)
|
||||
{
|
||||
return iterator;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
void native_env_handle_deleter::operator()(native_env_handle_type h) const
|
||||
{
|
||||
delete [] h;
|
||||
}
|
||||
|
||||
native_env_iterator next(native_env_iterator nh)
|
||||
{
|
||||
return ++nh ;
|
||||
}
|
||||
native_env_iterator find_end(native_env_iterator nh)
|
||||
{
|
||||
while (*nh != nullptr)
|
||||
nh++;
|
||||
|
||||
return nh ;
|
||||
}
|
||||
|
||||
const environment::char_type * dereference(native_env_iterator iterator)
|
||||
{
|
||||
return *iterator;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace ext
|
||||
{
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
env_view env(HANDLE proc, boost::system::error_code & ec)
|
||||
{
|
||||
wchar_t *buffer = nullptr;
|
||||
PEB peb;
|
||||
SIZE_T nRead = 0;
|
||||
ULONG len = 0;
|
||||
PROCESS_BASIC_INFORMATION pbi;
|
||||
detail::ext::RTL_USER_PROCESS_PARAMETERS_EXTENDED upp;
|
||||
|
||||
NTSTATUS status = 0;
|
||||
PVOID buf = nullptr;
|
||||
status = NtQueryInformationProcess(proc, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
|
||||
ULONG error = RtlNtStatusToDosError(status);
|
||||
|
||||
if (error)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, error, boost::system::system_category())
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(proc, pbi.PebBaseAddress, &peb, sizeof(peb), &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(proc, peb.ProcessParameters, &upp, sizeof(upp), &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
env_view ev;
|
||||
buf = upp.Environment;
|
||||
len = (ULONG)upp.EnvironmentSize;
|
||||
ev.handle_.reset(new wchar_t[len / 2 + 1]());
|
||||
|
||||
if (!ReadProcessMemory(proc, buf, ev.handle_.get(), len, &nRead))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
ev.handle_.get()[len / 2] = L'\0';
|
||||
return ev;
|
||||
}
|
||||
|
||||
env_view env(HANDLE handle)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = env(handle, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "env");
|
||||
return res;
|
||||
}
|
||||
|
||||
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
struct del
|
||||
{
|
||||
void operator()(HANDLE h)
|
||||
{
|
||||
::CloseHandle(h);
|
||||
};
|
||||
};
|
||||
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
|
||||
if (proc == nullptr)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
else
|
||||
return env(proc.get(), ec);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE___) || defined(__MACH__))
|
||||
|
||||
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
int mib[3] = {CTL_KERN, KERN_ARGMAX, 0};
|
||||
int argmax = 0;
|
||||
auto size = sizeof(argmax);
|
||||
if (sysctl(mib, 2, &argmax, &size, nullptr, 0) == -1)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string procargs;
|
||||
procargs.resize(argmax - 1);
|
||||
mib[1] = KERN_PROCARGS2;
|
||||
mib[2] = pid;
|
||||
|
||||
size = argmax;
|
||||
|
||||
if (sysctl(mib, 3, &*procargs.begin(), &size, nullptr, 0) != 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
std::uint32_t nargs;
|
||||
memcpy(&nargs, &*procargs.begin(), sizeof(nargs));
|
||||
char *cp = &*procargs.begin() + sizeof(nargs);
|
||||
|
||||
for (; cp < &*procargs.end(); cp++)
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
|
||||
|
||||
if (cp == &procargs[size])
|
||||
return {};
|
||||
|
||||
|
||||
for (; cp < &*procargs.end(); cp++)
|
||||
if (*cp != '\0') break;
|
||||
|
||||
|
||||
if (cp == &*procargs.end())
|
||||
return {};
|
||||
|
||||
|
||||
int i = 0;
|
||||
char *sp = cp;
|
||||
std::vector<char> vec;
|
||||
|
||||
while ((*sp != '\0' || i < nargs) && sp < &*procargs.end()) {
|
||||
if (i >= nargs)
|
||||
vec.push_back(*sp);
|
||||
|
||||
sp += 1;
|
||||
}
|
||||
|
||||
env_view ev;
|
||||
ev.handle_.reset(new char[vec.size()]());
|
||||
std::copy(vec.begin(), vec.end(), ev.handle_.get());
|
||||
return ev;
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__))
|
||||
|
||||
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::size_t size = 0;
|
||||
std::unique_ptr<char, detail::ext::native_env_handle_deleter> procargs{};
|
||||
|
||||
int f = ::open(("/proc/" + std::to_string(pid) + "/environ").c_str(), O_RDONLY);
|
||||
|
||||
while (!procargs || procargs.get()[size - 1] != EOF)
|
||||
{
|
||||
std::unique_ptr<char, detail::ext::native_env_handle_deleter> buf{new char[size + 4096]};
|
||||
if (size > 0)
|
||||
std::memmove(buf.get(), procargs.get(), size);
|
||||
auto r = ::read(f, buf.get() + size, 4096);
|
||||
if (r < 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
::close(f);
|
||||
return {};
|
||||
}
|
||||
procargs = std::move(buf);
|
||||
size += r;
|
||||
if (r < 4096) // done!
|
||||
{
|
||||
procargs.get()[size] = EOF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
::close(f);
|
||||
|
||||
env_view ev;
|
||||
ev.handle_ = std::move(procargs);
|
||||
return ev;
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
env_view env(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
env_view ev;
|
||||
|
||||
unsigned cntp = 0;
|
||||
procstat *proc_stat = procstat_open_sysctl();
|
||||
if (proc_stat != nullptr)
|
||||
{
|
||||
kinfo_proc *proc_info = procstat_getprocs(proc_stat, KERN_PROC_PID, pid, &cntp);
|
||||
if (proc_info != nullptr)
|
||||
{
|
||||
char **env = procstat_getenvv(proc_stat, proc_info, 0);
|
||||
if (env != nullptr)
|
||||
{
|
||||
auto e = env;
|
||||
std::size_t n = 0u, len = 0u;
|
||||
while (e && *e != nullptr)
|
||||
{
|
||||
n ++;
|
||||
len += std::strlen(*e);
|
||||
e++;
|
||||
}
|
||||
std::size_t mem_needed =
|
||||
// environ - nullptr - strlen + null terminators
|
||||
(n * sizeof(char*)) + sizeof(char*) + len + n;
|
||||
|
||||
char * out = new (std::nothrow) char[mem_needed];
|
||||
if (out != nullptr)
|
||||
{
|
||||
auto eno = reinterpret_cast<char**>(out);
|
||||
auto eeo = eno;
|
||||
auto str = out + (n * sizeof(char*)) + sizeof(char*);
|
||||
e = env;
|
||||
while (*e != nullptr)
|
||||
{
|
||||
auto len = std::strlen(*e) + 1u;
|
||||
std::memcpy(str, *e, len);
|
||||
*eno = str;
|
||||
str += len;
|
||||
eno ++;
|
||||
e++;
|
||||
}
|
||||
*eno = nullptr;
|
||||
|
||||
ev.handle_.reset(eeo);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
|
||||
}
|
||||
procstat_freeprocs(proc_stat, proc_info);
|
||||
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
procstat_close(proc_stat);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ev;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
env_view env(boost::process::v2::pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = env(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "env");
|
||||
return res;
|
||||
}
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_V2_EXT_IMPL_ENV_IPP
|
||||
@@ -1,193 +0,0 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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_IMPL_EXE_IPP
|
||||
#define BOOST_PROCESS_V2_IMPL_EXE_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/ext/detail/proc_info.hpp>
|
||||
#include <boost/process/v2/ext/exe.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <climits>
|
||||
#endif
|
||||
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <sys/proc_info.h>
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
||||
#if (defined(BOOST_PROCESS_V2_WINDOWS) || defined(__linux__) || defined(__ANDROID__) || defined(__sun))
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__))
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#if !defined(__FreeBSD__)
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
#include <boost/process/v2/ext/cwd.hpp>
|
||||
#include <boost/process/v2/ext/cmd.hpp>
|
||||
#include <boost/process/v2/ext/env.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <kvm.h>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace ext {
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
filesystem::path exe(HANDLE process_handle)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = exe(process_handle, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "exe");
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
filesystem::path exe(HANDLE proc, boost::system::error_code & ec)
|
||||
{
|
||||
wchar_t buffer[MAX_PATH];
|
||||
// On input, specifies the size of the lpExeName buffer, in characters.
|
||||
DWORD size = MAX_PATH;
|
||||
if (QueryFullProcessImageNameW(proc, 0, buffer, &size))
|
||||
{
|
||||
return filesystem::canonical(buffer, ec);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
if (pid == GetCurrentProcessId())
|
||||
{
|
||||
wchar_t buffer[MAX_PATH];
|
||||
if (GetModuleFileNameW(nullptr, buffer, sizeof(buffer)))
|
||||
{
|
||||
return filesystem::canonical(buffer, ec);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct del
|
||||
{
|
||||
void operator()(HANDLE h)
|
||||
{
|
||||
::CloseHandle(h);
|
||||
};
|
||||
};
|
||||
std::unique_ptr<void, del> proc{detail::ext::open_process_with_debug_privilege(pid, ec)};
|
||||
if (proc == nullptr)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
else
|
||||
return exe(proc.get(), ec);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
char buffer[PROC_PIDPATHINFO_MAXSIZE];
|
||||
if (proc_pidpath(pid, buffer, sizeof(buffer)) > 0)
|
||||
{
|
||||
return filesystem::canonical(buffer, ec);
|
||||
}
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return "";
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__) || defined(__sun))
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
#if (defined(__linux__) || defined(__ANDROID__))
|
||||
return filesystem::canonical(
|
||||
filesystem::path("/proc") / std::to_string(pid) / "exe", ec
|
||||
);
|
||||
#elif defined(__sun)
|
||||
return fileystem::canonical(
|
||||
filesystem::path("/proc") / std::to_string(pid) / "path/a.out"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__))
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
#if (defined(__FreeBSD__) || defined(__DragonFly__))
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid};
|
||||
#elif defined(__NetBSD__)
|
||||
int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_PATHNAME};
|
||||
#endif
|
||||
std::size_t len = 0;
|
||||
if (sysctl(mib, 4, nullptr, &len, nullptr, 0) == 0)
|
||||
{
|
||||
std::string strbuff;
|
||||
strbuff.resize(len);
|
||||
if (sysctl(mib, 4, &strbuff[0], &len, nullptr, 0) == 0)
|
||||
{
|
||||
strbuff.resize(len - 1);
|
||||
return filesystem::canonical(strbuff, ec);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return "";
|
||||
}
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, boost::system::system_category())
|
||||
return "";
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
|
||||
filesystem::path exe(boost::process::v2::pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = exe(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "exe");
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ext
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_IMPL_EXE_IPP
|
||||
|
||||
321
include/boost/process/v2/group.hpp
Normal file
321
include/boost/process/v2/group.hpp
Normal file
@@ -0,0 +1,321 @@
|
||||
// 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_GROUP_HPP
|
||||
#define BOOST_PROCESS_V2_GROUP_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/default_launcher.hpp>
|
||||
#include <boost/process/v2/exit_code.hpp>
|
||||
#include <boost/process/v2/process_handle.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <boost/process/v2/detail/group_impl_windows.hpp>
|
||||
#else
|
||||
#include <boost/process/v2/detail/group_impl_posix.hpp>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
/** A process handle is an unmanaged version of a process.
|
||||
* This means it does not terminate the proces on destruction and
|
||||
* will not keep track of the exit-code.
|
||||
*
|
||||
* Note that the exit code might be discovered early, during a call to `running`.
|
||||
* Thus it can only be discovered that process has exited already.
|
||||
*/
|
||||
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor,
|
||||
typename Launcher = default_process_launcher>
|
||||
struct basic_group
|
||||
{
|
||||
/// The native handle of the process.
|
||||
/** This might be undefined on posix systems that only support signals */
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
using native_handle_type = implementation_defined;
|
||||
#else
|
||||
using native_handle_type = typename detail::basic_group_impl<Executor>::native_handle_type;
|
||||
#endif
|
||||
/// The executor_type of the group
|
||||
using executor_type = Executor;
|
||||
|
||||
/// The launcher used by the group for emplacing
|
||||
using launcher_type = Launcher;
|
||||
|
||||
// Get the native group handle
|
||||
native_handle_type native_handle() {return impl_.native_handle();}
|
||||
|
||||
/// Getter for the executor
|
||||
executor_type get_executor() { return impl_.get_executor();}
|
||||
|
||||
/// Rebinds the group to another executor.
|
||||
template<typename Executor1>
|
||||
struct rebind_executor
|
||||
{
|
||||
/// The socket type when rebound to the specified executor.
|
||||
typedef basic_group<Executor1, Launcher> other;
|
||||
};
|
||||
|
||||
|
||||
/// Construct a basic_group from an execution_context.
|
||||
/**
|
||||
* @tparam ExecutionContext The context must fulfill the asio::execution_context requirements
|
||||
*/
|
||||
template<typename ExecutionContext>
|
||||
basic_group(ExecutionContext &context,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext&,
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
launcher_type>::type launcher = launcher_type())
|
||||
: basic_group(context.get_executor(), std::move(launcher))
|
||||
{}
|
||||
|
||||
/// Construct an empty group from an executor.
|
||||
basic_group(executor_type executor, launcher_type launcher = launcher_type())
|
||||
: impl_(std::move(executor)), launcher_(std::move(launcher)) {}
|
||||
|
||||
/// Construct an empty group from an executor and bind it to a pid and the native-handle
|
||||
/** On some non-linux posix systems this overload is not present.
|
||||
*/
|
||||
basic_group(executor_type executor, native_handle_type group,
|
||||
launcher_type launcher = launcher_type())
|
||||
: impl_(std::move(executor), group), , launcher_(std::move(launcher)) {}
|
||||
|
||||
/// Move construct and rebind the executor.
|
||||
template<typename Executor1>
|
||||
basic_group(basic_group<Executor1> &&handle)
|
||||
: procs_(std::move(handle.procs_)), impl_(std::move(handle.impl_)),
|
||||
launcher_(std::move(handle.launcher_)) {}
|
||||
|
||||
/// wait for one process to exit and store the exit code in exit_status.
|
||||
single_process_exit wait_one(error_code &ec)
|
||||
{
|
||||
single_process_exit res;
|
||||
impl_.wait_one(res.pid, res.exit_code, ec);
|
||||
return res;
|
||||
}
|
||||
/// Throwing @overload wait_one(error_code & ec)
|
||||
single_process_exit wait_one()
|
||||
{
|
||||
error_code ec;
|
||||
auto res = wait_one(ec);
|
||||
detail::throw_error(ec, "wait_one");
|
||||
return res;
|
||||
}
|
||||
|
||||
/// wait for all processes to exit. Returns the number of processes exited
|
||||
void wait_all(error_code &ec)
|
||||
{
|
||||
impl_.wait_all(ec);
|
||||
}
|
||||
/// Throwing @overload wait_all(error_code & ec)
|
||||
void wait_all()
|
||||
{
|
||||
error_code ec;
|
||||
wait_all(ec);
|
||||
detail::throw_error(ec, "wait_all");
|
||||
}
|
||||
|
||||
/// Sends the processes a signal to ask for an interrupt, which the process may interpret as a shutdown.
|
||||
/** Maybe be ignored by the subprocess. */
|
||||
void interrupt(error_code &ec)
|
||||
{
|
||||
impl_.interrupt(ec);
|
||||
}
|
||||
|
||||
/// Throwing @overload void interrupt()
|
||||
void interrupt()
|
||||
{
|
||||
error_code ec;
|
||||
interrupt(ec);
|
||||
detail::throw_error(ec, "interrupt");
|
||||
}
|
||||
|
||||
/// Sends the processes a signal to ask for a graceful shutdown. Maybe be ignored by the subprocess.
|
||||
void request_exit(error_code &ec)
|
||||
{
|
||||
impl_.request_exit(ec);
|
||||
}
|
||||
|
||||
/// Throwing @overload void request_exit(error_code & ec)
|
||||
void request_exit()
|
||||
{
|
||||
error_code ec;
|
||||
auto res = request_exit(ec);
|
||||
detail::throw_error(ec, "request_exit");
|
||||
}
|
||||
|
||||
/// Unconditionally terminates the processes and stores the exit code in exit_status.
|
||||
void terminate(error_code &ec)
|
||||
{
|
||||
impl_.terminate(ec);
|
||||
}
|
||||
/// Throwing @overload void terminate(native_exit_code_type &exit_code, error_code & ec)
|
||||
void terminate()
|
||||
{
|
||||
error_code ec;
|
||||
terminate(ec);
|
||||
detail::throw_error(ec, "terminate");
|
||||
}
|
||||
|
||||
/// Check if the process handle is referring to an existing process.
|
||||
bool is_open() const
|
||||
{
|
||||
return impl_.is_open();
|
||||
}
|
||||
|
||||
/// Asynchronously wait for one process to exit and deliver the exit-code in the completion handler.
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, single_process_exit))
|
||||
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, single_process_exit))
|
||||
async_wait_one(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
|
||||
{
|
||||
return impl_.async_wait_one(std::forward<WaitHandler>(handler));
|
||||
}
|
||||
|
||||
/// Asynchronously wait for all processes to exit and the gorup to be empty.
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code))
|
||||
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code))
|
||||
async_wait_all(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
|
||||
{
|
||||
return impl_.async_wait_all(std::forward<WaitHandler>(handler));
|
||||
}
|
||||
/// Throwing overload of @overload contains(pid_type pid, error_code & ec)
|
||||
bool contains(pid_type pid)
|
||||
{
|
||||
error_code ec;
|
||||
auto res = contains(ec);
|
||||
detail::throw_error(ec, "contains");
|
||||
return res;
|
||||
}
|
||||
/// Check if the pid is in the group
|
||||
bool contains(pid_type pid, error_code & ec)
|
||||
{
|
||||
impl_.contains(std::move(proc), ec);
|
||||
}
|
||||
|
||||
template<typename Executor_>
|
||||
void add(basic_process_handle<Executor_> proc)
|
||||
{
|
||||
error_code ec;
|
||||
add(proc.id(), proc.native_handle(), ec);
|
||||
detail::throw_error(ec, "add");
|
||||
}
|
||||
|
||||
template<typename Executor_>
|
||||
void add(basic_process_handle<Executor_> proc, error_code & ec)
|
||||
{
|
||||
impl_.add(std::move(proc), ec);
|
||||
}
|
||||
|
||||
template<typename ... Inits>
|
||||
pid_type emplace(
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits)
|
||||
{
|
||||
error_code ec;
|
||||
auto ph = launcher_(impl_.get_executor(), exe, std::move(args),
|
||||
std::forward<Inits>(inits)..., impl_.get_initializer(ec));
|
||||
if (ec)
|
||||
detail::throw_error(ec);
|
||||
return ph.detach().id();
|
||||
}
|
||||
|
||||
template<typename ... Inits>
|
||||
pid_type emplace(
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<wstring_view> args,
|
||||
Inits&&... inits)
|
||||
{
|
||||
error_code ec;
|
||||
auto ph = launcher_(impl_.get_executor(), exe, std::move(args),
|
||||
std::forward<Inits>(inits)..., impl_.get_initializer(ec));
|
||||
if (ec)
|
||||
detail::throw_error(ec);
|
||||
return ph.detach().id();
|
||||
}
|
||||
|
||||
template<typename Args, typename ... Inits>
|
||||
pid_type emplace(
|
||||
const filesystem::path& exe,
|
||||
Args && args,
|
||||
Inits&&... inits)
|
||||
{
|
||||
error_code ec;
|
||||
auto ph = launcher_(impl_.get_executor(), exe, std::move(args),
|
||||
std::forward<Inits>(inits)..., impl_.get_initializer(ec));
|
||||
if (ec)
|
||||
detail::throw_error(ec);
|
||||
return ph.detach().id();
|
||||
}
|
||||
|
||||
template<typename ... Inits>
|
||||
pid_type emplace(
|
||||
error_code & ec,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits)
|
||||
{
|
||||
auto ph = launcher_(impl_.get_executor(), ec, exe, std::move(args),
|
||||
std::forward<Inits>(inits)..., impl_.get_initializer(ec));
|
||||
if (ec)
|
||||
return pid_type{-1};
|
||||
return ph.detach().id();
|
||||
}
|
||||
|
||||
template<typename ... Inits>
|
||||
pid_type emplace(
|
||||
error_code & ec,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<wstring_view> args,
|
||||
Inits&&... inits)
|
||||
{
|
||||
auto ph = launcher_(impl_.get_executor(), ec, exe, std::move(args),
|
||||
std::forward<Inits>(inits)..., impl_.get_initializer(ec));
|
||||
if (ec)
|
||||
return pid_type{-1};
|
||||
return ph.detach().id();
|
||||
}
|
||||
|
||||
template<typename Args, typename ... Inits>
|
||||
pid_type emplace(
|
||||
error_code & ec,
|
||||
const filesystem::path& exe,
|
||||
Args && args,
|
||||
Inits&&... inits)
|
||||
{
|
||||
auto ph = launcher_(impl_.get_executor(), ec, exe, std::move(args),
|
||||
std::forward<Inits>(inits)..., impl_.get_initializer(ec));
|
||||
if (ec)
|
||||
return pid_type{-1};
|
||||
return ph.detach().id();
|
||||
}
|
||||
|
||||
void detach() { impl_.detach(); }
|
||||
private:
|
||||
detail::basic_group_impl<Executor> impl_;
|
||||
launcher_type launcher_;
|
||||
};
|
||||
|
||||
/// Process group with the default executor.
|
||||
using group = basic_group<>;
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
extern template struct basic_group<BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor, default_process_launcher>;
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
|
||||
#include <boost/process/v2/impl/group.ipp>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_GROUP_HPP
|
||||
25
include/boost/process/v2/impl/group.ipp
Normal file
25
include/boost/process/v2/impl/group.ipp
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// boost/process/v2/windows/impl/job_object_service.ipp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_IMPL_GROUP_IPP
|
||||
#define BOOST_PROCESS_V2_IMPL_GROUP_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/group.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
template struct basic_group_impl<BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor, default_process_launcher>;
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_IMPL_GROUP_IPP
|
||||
@@ -1,5 +1,4 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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)
|
||||
@@ -7,56 +6,14 @@
|
||||
#define BOOST_PROCESS_V2_IMPL_PID_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <sys/proc_info.h>
|
||||
#include <libproc.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__linux__) || defined(__ANDROID__))
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <libutil.h>
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#if (defined(__DragonFly__) || defined(__OpenBSD__))
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
#include <kvm.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <kvm.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__sun)
|
||||
#include <sys/types.h>
|
||||
#include <kvm.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/proc.h>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
@@ -65,698 +22,6 @@ pid_type current_pid() {return ::GetCurrentProcessId();}
|
||||
pid_type current_pid() {return ::getpid();}
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (!hp)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
PROCESSENTRY32 pe;
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
if (Process32First(hp, &pe))
|
||||
{
|
||||
do
|
||||
{
|
||||
vec.push_back(pe.th32ProcessID);
|
||||
} while (Process32Next(hp, &pe));
|
||||
}
|
||||
CloseHandle(hp);
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (!hp)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
PROCESSENTRY32 pe;
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
if (Process32First(hp, &pe))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (pe.th32ProcessID == pid)
|
||||
{
|
||||
ppid = pe.th32ParentProcessID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (Process32Next(hp, &pe));
|
||||
}
|
||||
CloseHandle(hp);
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (!hp)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
PROCESSENTRY32 pe;
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
if (Process32First(hp, &pe))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (pe.th32ParentProcessID == pid)
|
||||
{
|
||||
vec.push_back(pe.th32ProcessID);
|
||||
}
|
||||
}
|
||||
while (Process32Next(hp, &pe));
|
||||
}
|
||||
CloseHandle(hp);
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif (defined(__APPLE__) && defined(__MACH__))
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
vec.resize(proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0) / sizeof(pid_type));
|
||||
const auto sz = proc_listpids(PROC_ALL_PIDS, 0, &vec[0], sizeof(pid_type) * vec.size());
|
||||
if (sz < 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
vec.resize(sz);
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
proc_bsdinfo proc_info;
|
||||
if (proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &proc_info, sizeof(proc_info)) <= 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
else
|
||||
ppid = proc_info.pbi_ppid;
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
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());
|
||||
if (sz < 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return {};
|
||||
}
|
||||
vec.resize(sz);
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif (defined(__linux__) || defined(__ANDROID__))
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
DIR *proc = opendir("/proc");
|
||||
if (!proc)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
struct dirent *ent = nullptr;
|
||||
while ((ent = readdir(proc)))
|
||||
{
|
||||
if (!isdigit(*ent->d_name))
|
||||
continue;
|
||||
vec.push_back(atoi(ent->d_name));
|
||||
}
|
||||
closedir(proc);
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
char buffer[BUFSIZ];
|
||||
sprintf(buffer, "/proc/%d/stat", pid);
|
||||
FILE *stat = fopen(buffer, "r");
|
||||
if (!stat)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t size = fread(buffer, sizeof(char), sizeof(buffer), stat);
|
||||
if (size > 0)
|
||||
{
|
||||
char *token = nullptr;
|
||||
if ((token = strtok(buffer, " ")))
|
||||
{
|
||||
if ((token = strtok(nullptr, " ")))
|
||||
{
|
||||
if ((token = strtok(nullptr, " ")))
|
||||
{
|
||||
if ((token = strtok(nullptr, " ")))
|
||||
{
|
||||
ppid = (pid_type)strtoul(token, nullptr, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!token)
|
||||
{
|
||||
fclose(stat);
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
}
|
||||
fclose(stat);
|
||||
}
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
std::vector<pid_type> pids = all_pids(ec);
|
||||
if (!pids.empty())
|
||||
vec.reserve(pids.size());
|
||||
for (std::size_t i = 0; i < pids.size(); i++)
|
||||
{
|
||||
pid_type ppid = parent_pid(pids[i], ec);
|
||||
if (ppid != -1 && ppid == pid)
|
||||
{
|
||||
vec.push_back(pids[i]);
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = kinfo_getallproc(&cntp);
|
||||
if (proc_info)
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = 0; i < cntp; i++)
|
||||
vec.push_back(proc_info[i].ki_pid);
|
||||
free(proc_info);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
kinfo_proc *proc_info = kinfo_getproc(pid);
|
||||
if (proc_info)
|
||||
{
|
||||
ppid = proc_info->ki_ppid;
|
||||
free(proc_info);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = kinfo_getallproc(&cntp);
|
||||
if (proc_info)
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = 0; i < cntp; i++)
|
||||
{
|
||||
if (proc_info[i].ki_ppid == pid)
|
||||
{
|
||||
vec.push_back(proc_info[i].ki_pid);
|
||||
}
|
||||
}
|
||||
free(proc_info);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__DragonFly__)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
const char *nlistf, *memf;
|
||||
nlistf = memf = "/dev/null";
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = 0; i < cntp; i++)
|
||||
if (proc_info[i].kp_pid >= 0)
|
||||
vec.push_back(proc_info[i].kp_pid);
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
const char *nlistf, *memf;
|
||||
nlistf = memf = "/dev/null";
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, &cntp)))
|
||||
{
|
||||
if (proc_info->kp_ppid >= 0)
|
||||
{
|
||||
ppid = proc_info->kp_ppid;
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
const char *nlistf, *memf;
|
||||
nlistf = memf = "/dev/null";
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nlistf, memf, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = 0; i < cntp; i++)
|
||||
{
|
||||
if (proc_info[i].kp_pid >= 0 && proc_info[i].kp_ppid >= 0 && proc_info[i].kp_ppid == pid)
|
||||
{
|
||||
vec.push_back(proc_info[i].kp_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc2 *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = cntp - 1; i >= 0; i--)
|
||||
{
|
||||
vec.push_back(proc_info[i].p_pid);
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
int cntp = 0;
|
||||
kinfo_proc2 *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc2), &cntp)))
|
||||
{
|
||||
ppid = proc_info->p_ppid;
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc2 *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getproc2(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = cntp - 1; i >= 0; i--)
|
||||
{
|
||||
if (proc_info[i].p_ppid == pid)
|
||||
{
|
||||
vec.push_back(proc_info[i].p_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = cntp - 1; i >= 0; i--)
|
||||
{
|
||||
if (proc_info[i].kp_pid >= 0)
|
||||
{
|
||||
vec.push_back(proc_info[i].kp_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &cntp)))
|
||||
{
|
||||
ppid = proc_info->p_ppid;
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
int cntp = 0;
|
||||
kinfo_proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
if ((proc_info = kvm_getprocs(kd.get(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cntp)))
|
||||
{
|
||||
vec.reserve(cntp);
|
||||
for (int i = cntp - 1; i >= 0; i--)
|
||||
{
|
||||
if (proc_info[i].p_ppid == pid)
|
||||
{
|
||||
vec.push_back(proc_info[i].p_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(__sun)
|
||||
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
struct pid cur_pid;
|
||||
proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
while ((proc_info = kvm_nextproc(kd)))
|
||||
{
|
||||
if (kvm_kread(kd, (std::uintptr_t)proc_info->p_pidp, &cur_pid, sizeof(cur_pid)) != -1)
|
||||
{
|
||||
vec.insert(vec.begin(), cur_pid.pid_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
pid_type ppid = static_cast<pid_type>(-1);
|
||||
proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr)};
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
if ((proc_info = kvm_getproc(kd, pid)))
|
||||
{
|
||||
ppid = proc_info->p_ppid;
|
||||
}
|
||||
else
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return ppid;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec)
|
||||
{
|
||||
std::vector<pid_type> vec;
|
||||
struct pid cur_pid;
|
||||
proc *proc_info = nullptr;
|
||||
struct closer
|
||||
{
|
||||
void operator()(kvm_t * kd)
|
||||
{
|
||||
kvm_close(kd);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<kvm_t, closer> kd{kvm_open(nullptr, nullptr, nullptr, O_RDONLY, nullptr);
|
||||
if (!kd)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
return vec;
|
||||
}
|
||||
while ((proc_info = kvm_nextproc(kd)))
|
||||
{
|
||||
if (proc_info->p_ppid == pid)
|
||||
{
|
||||
if (kvm_kread(kd, (std::uintptr_t)proc_info->p_pidp, &cur_pid, sizeof(cur_pid)) != -1)
|
||||
{
|
||||
vec.insert(vec.begin(), cur_pid.pid_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
|
||||
std::vector<pid_type> all_pids()
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = all_pids(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "all_pids");
|
||||
return res;
|
||||
}
|
||||
|
||||
pid_type parent_pid(pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = parent_pid(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "parent_pid");
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<pid_type> child_pids(pid_type pid)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto res = child_pids(pid, ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "child_pids");
|
||||
return res;
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_IMPL_PID_IPP
|
||||
|
||||
#endif //BOOST_PROCESS_V2_IMPL_PID_IPP
|
||||
|
||||
@@ -69,11 +69,7 @@ void shell::parse_()
|
||||
{
|
||||
argv_ = ::CommandLineToArgvW(input_.c_str(), &argc_);
|
||||
if (argv_ == nullptr)
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
|
||||
throw system_error(ec, "shell::parse");
|
||||
}
|
||||
detail::throw_last_error();
|
||||
}
|
||||
|
||||
shell::~shell()
|
||||
@@ -100,23 +96,21 @@ void shell::parse_()
|
||||
{
|
||||
argc_ = static_cast<int>(we.we_wordc);
|
||||
argv_ = we.we_wordv;
|
||||
reserved_ = static_cast<int>(we.we_offs);
|
||||
}
|
||||
|
||||
free_argv_ = +[](int argc, char ** argv)
|
||||
{
|
||||
wordexp_t we{
|
||||
.we_wordc = static_cast<std::size_t>(argc),
|
||||
.we_wordv = argv,
|
||||
.we_offs = 0
|
||||
};
|
||||
wordfree(&we);
|
||||
};
|
||||
}
|
||||
|
||||
shell::~shell()
|
||||
{
|
||||
if (argv_ != nullptr && free_argv_ != nullptr)
|
||||
free_argv_(argc_, argv_);
|
||||
if (argv_ != nullptr)
|
||||
{
|
||||
wordexp_t we{
|
||||
.we_wordc = static_cast<std::size_t>(argc_),
|
||||
.we_wordv = argv_,
|
||||
.we_offs = static_cast<std::size_t>(reserved_)
|
||||
};
|
||||
wordfree(&we);
|
||||
}
|
||||
}
|
||||
|
||||
auto shell::args() const -> args_type
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// 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)
|
||||
@@ -7,7 +6,6 @@
|
||||
#define BOOST_PROCESS_V2_PID_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/throw_error.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
@@ -16,6 +14,7 @@ BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
//An integral type representing a process id.
|
||||
typedef implementation_defined pid_type;
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
@@ -29,38 +28,14 @@ typedef int pid_type;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined(BOOST_PROCESS_V2_WINDOWS) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__sun))
|
||||
constexpr static pid_type root_pid = 0;
|
||||
#elif (defined(__APPLE__) && defined(__MACH__) || defined(__linux__) || defined(__ANDROID__) || defined(__OpenBSD__))
|
||||
constexpr static pid_type root_pid = 1;
|
||||
#endif
|
||||
|
||||
/// Get the process id of the current process.
|
||||
BOOST_PROCESS_V2_DECL pid_type current_pid();
|
||||
|
||||
/// List all available pids.
|
||||
BOOST_PROCESS_V2_DECL std::vector<pid_type> all_pids(boost::system::error_code & ec);
|
||||
|
||||
/// List all available pids.
|
||||
BOOST_PROCESS_V2_DECL std::vector<pid_type> all_pids();
|
||||
|
||||
// return parent pid of pid.
|
||||
BOOST_PROCESS_V2_DECL pid_type parent_pid(pid_type pid, boost::system::error_code & ec);
|
||||
|
||||
// return parent pid of pid.
|
||||
BOOST_PROCESS_V2_DECL pid_type parent_pid(pid_type pid);
|
||||
|
||||
// return child pids of pid.
|
||||
BOOST_PROCESS_V2_DECL std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec);
|
||||
|
||||
// return child pids of pid.
|
||||
BOOST_PROCESS_V2_DECL std::vector<pid_type> child_pids(pid_type pid);
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
#include <boost/process/v2/impl/pid.ipp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_PROCESS_V2_PID_HPP
|
||||
|
||||
#endif //BOOST_PROCESS_V2_PID_HPP
|
||||
|
||||
@@ -74,6 +74,8 @@ struct basic_popen : basic_process<Executor>
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename ... Inits>
|
||||
explicit basic_popen(
|
||||
@@ -83,66 +85,30 @@ struct basic_popen : basic_process<Executor>
|
||||
Inits&&... inits)
|
||||
: basic_process<Executor>(executor)
|
||||
{
|
||||
this->basic_process<Executor>::operator=(
|
||||
*static_cast<basic_process<Executor>*>(this) =
|
||||
default_process_launcher()(
|
||||
this->get_executor(), exe, args,
|
||||
std::forward<Inits>(inits)...,
|
||||
process_stdio{stdin_, stdout_}
|
||||
));
|
||||
}
|
||||
);
|
||||
|
||||
/// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename Launcher, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
Launcher && launcher,
|
||||
executor_type executor,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits)
|
||||
: basic_process<Executor>(executor)
|
||||
{
|
||||
this->basic_process<Executor>::operator=(
|
||||
std::forward<Launcher>(launcher)(
|
||||
this->get_executor(), exe, args,
|
||||
std::forward<Inits>(inits)...,
|
||||
process_stdio{stdin_, stdout_}
|
||||
));
|
||||
}
|
||||
|
||||
/// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename ... Inits>
|
||||
explicit basic_popen(
|
||||
executor_type executor,
|
||||
const filesystem::path& exe,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<wstring_view> args,
|
||||
Inits&&... inits)
|
||||
: basic_process<Executor>(executor)
|
||||
{
|
||||
this->basic_process<Executor>::operator=(
|
||||
*static_cast<basic_process<Executor>*>(this) =
|
||||
default_process_launcher()(
|
||||
this->get_executor(), exe, args,
|
||||
std::forward<Inits>(inits)...,
|
||||
process_stdio{stdin_, stdout_}
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename Launcher, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
Launcher && launcher,
|
||||
executor_type executor,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<wstring_view> args,
|
||||
Inits&&... inits)
|
||||
: basic_process<Executor>(executor)
|
||||
{
|
||||
this->basic_process<Executor>::operator=(
|
||||
std::forward<Launcher>(launcher)(
|
||||
this->get_executor(), exe, args,
|
||||
std::forward<Inits>(inits)...,
|
||||
process_stdio{stdin_, stdout_}
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
/// Construct a child from a property list and launch it using the default process launcher.
|
||||
@@ -153,112 +119,53 @@ struct basic_popen : basic_process<Executor>
|
||||
Args&& args, Inits&&... inits)
|
||||
: basic_process<Executor>(executor)
|
||||
{
|
||||
this->basic_process<Executor>::operator=(
|
||||
*static_cast<basic_process<Executor>*>(this) =
|
||||
default_process_launcher()(
|
||||
std::move(executor), exe, args,
|
||||
std::forward<Inits>(inits)...,
|
||||
process_stdio{stdin_, stdout_}
|
||||
));
|
||||
}
|
||||
|
||||
/// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename Launcher, typename Args, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
Launcher && launcher,
|
||||
executor_type executor,
|
||||
const filesystem::path& exe,
|
||||
Args&& args, Inits&&... inits)
|
||||
: basic_process<Executor>(executor)
|
||||
{
|
||||
this->basic_process<Executor>::operator=(
|
||||
std::forward<Launcher>(launcher)(
|
||||
std::move(executor), exe, args,
|
||||
std::forward<Inits>(inits)...,
|
||||
process_stdio{stdin_, stdout_}
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
/// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename ExecutionContext, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
ExecutionContext & context,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext&,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext&,
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
const filesystem::path&>::type exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits)
|
||||
Inits&&... inits)
|
||||
: basic_process<Executor>(context)
|
||||
{
|
||||
this->basic_process<Executor>::operator=(
|
||||
*static_cast<basic_process<Executor>*>(this) =
|
||||
default_process_launcher()(
|
||||
this->get_executor(), exe, args,
|
||||
std::forward<Inits>(inits)...,
|
||||
process_stdio{stdin_, stdout_}
|
||||
));
|
||||
}
|
||||
|
||||
/// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename Launcher, typename ExecutionContext, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
Launcher && launcher,
|
||||
ExecutionContext & context,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext&,
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
const filesystem::path&>::type exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits)
|
||||
: basic_process<Executor>(context)
|
||||
{
|
||||
this->basic_process<Executor>::operator=(
|
||||
std::forward<Launcher>(launcher)(
|
||||
this->get_executor(), exe, args,
|
||||
std::forward<Inits>(inits)...,
|
||||
process_stdio{stdin_, stdout_}
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
/// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename ExecutionContext, typename Args, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
ExecutionContext & context,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext&,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext&,
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
const filesystem::path&>::type exe,
|
||||
Args&& args, Inits&&... inits)
|
||||
: basic_process<Executor>(context)
|
||||
{
|
||||
this->basic_process<Executor>::operator=(
|
||||
*static_cast<basic_process<Executor>*>(this) =
|
||||
default_process_launcher()(
|
||||
this->get_executor(), exe, args,
|
||||
std::forward<Inits>(inits)...,
|
||||
process_stdio{stdin_, stdout_}
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
/// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename Launcher, typename ExecutionContext, typename Args, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
Launcher && launcher,
|
||||
ExecutionContext & context,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<ExecutionContext&,
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
const filesystem::path&>::type exe,
|
||||
Args&& args, Inits&&... inits)
|
||||
: basic_process<Executor>(context)
|
||||
{
|
||||
this->basic_process<Executor>::operator=(
|
||||
std::forward<Launcher>(launcher)(
|
||||
this->get_executor(), exe, args,
|
||||
std::forward<Inits>(inits)...,
|
||||
process_stdio{stdin_, stdout_}
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/// The type used for stdin on the parent process side.
|
||||
using stdin_type = BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor>;
|
||||
/// The type used for stdout on the parent process side.
|
||||
|
||||
@@ -61,7 +61,7 @@ struct bind_fd
|
||||
*/
|
||||
bind_fd(int target, FILE * f) : bind_fd(target, fileno(f)) {}
|
||||
|
||||
/// Inherit a file descriptor with as a different value.
|
||||
/// Inherit a file descriptor with as a differnet value.
|
||||
/**
|
||||
* This will pass 24 as 42 to the child process:
|
||||
* @code
|
||||
@@ -79,7 +79,7 @@ struct bind_fd
|
||||
*/
|
||||
bind_fd(int target, std::nullptr_t) : bind_fd(target, filesystem::path("/dev/null")) {}
|
||||
|
||||
/// Inherit a newly opened-file as a set descriptor.
|
||||
/// Inherit a newly openedfile as a set descriptor.
|
||||
/**
|
||||
* This will pass 24 as 42 to the child process:
|
||||
* @code
|
||||
@@ -94,7 +94,6 @@ struct bind_fd
|
||||
error_code on_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *)
|
||||
{
|
||||
launcher.fd_whitelist.push_back(target);
|
||||
return {};
|
||||
}
|
||||
|
||||
/// Implementation of the initialization function.
|
||||
|
||||
@@ -364,12 +364,12 @@ struct default_launcher
|
||||
pipe_guard pg;
|
||||
if (::pipe(pg.p))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
ec.assign(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())
|
||||
ec.assign(errno, system_category());
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
ec = detail::on_setup(*this, executable, argv, inits ...);
|
||||
@@ -390,7 +390,7 @@ struct default_launcher
|
||||
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())
|
||||
ec.assign(errno, system_category());
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
else if (pid == 0)
|
||||
@@ -406,7 +406,7 @@ struct default_launcher
|
||||
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
|
||||
|
||||
ignore_unused(::write(pg.p[1], &errno, sizeof(int)));
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
ec.assign(errno, system_category());
|
||||
detail::on_exec_error(*this, executable, argv, ec, inits...);
|
||||
::exit(EXIT_FAILURE);
|
||||
return basic_process<Executor>{exec};
|
||||
@@ -422,12 +422,12 @@ struct default_launcher
|
||||
int err = errno;
|
||||
if ((err != EAGAIN) && (err != EINTR))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
|
||||
ec.assign(err, system_category());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count != 0)
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category())
|
||||
ec.assign(child_error, system_category());
|
||||
|
||||
if (ec)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// boost/process/v2/posix/detail/close_handles.hpp
|
||||
// boost/process/v2/poxix/detail/close_handles.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
|
||||
@@ -94,7 +94,7 @@ struct fork_and_forget_launcher : default_launcher
|
||||
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())
|
||||
ec.assign(errno, system_category());
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
else if (pid == 0)
|
||||
@@ -107,7 +107,7 @@ struct fork_and_forget_launcher : default_launcher
|
||||
if (!ec)
|
||||
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
|
||||
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
ec.assign(errno, system_category());
|
||||
detail::on_exec_error(*this, executable, argv, ec, inits...);
|
||||
::exit(EXIT_FAILURE);
|
||||
return basic_process<Executor>{exec};
|
||||
|
||||
@@ -85,12 +85,12 @@ struct pdfork_launcher : default_launcher
|
||||
pipe_guard pg;
|
||||
if (::pipe(pg.p))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
ec.assign(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())
|
||||
ec.assign(errno, system_category());
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
ec = detail::on_setup(*this, executable, argv, inits ...);
|
||||
@@ -111,7 +111,7 @@ struct pdfork_launcher : default_launcher
|
||||
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())
|
||||
ec.assign(errno, system_category());
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
else if (pid == 0)
|
||||
@@ -128,7 +128,7 @@ struct pdfork_launcher : default_launcher
|
||||
::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())
|
||||
ec.assign(errno, system_category());
|
||||
detail::on_exec_error(*this, executable, argv, ec, inits...);
|
||||
::exit(EXIT_FAILURE);
|
||||
return basic_process<Executor>{exec};
|
||||
@@ -143,12 +143,12 @@ struct pdfork_launcher : default_launcher
|
||||
int err = errno;
|
||||
if ((err != EAGAIN) && (err != EINTR))
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
|
||||
ec.assign(err, system_category());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count != 0)
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, child_error, system_category())
|
||||
ec.assign(child_error, system_category());
|
||||
|
||||
if (ec)
|
||||
{
|
||||
|
||||
@@ -96,7 +96,7 @@ struct vfork_launcher : default_launcher
|
||||
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())
|
||||
ec.assign(errno, system_category());
|
||||
return basic_process<Executor>{exec};
|
||||
}
|
||||
else if (pid == 0)
|
||||
@@ -108,7 +108,7 @@ struct vfork_launcher : default_launcher
|
||||
if (!ec)
|
||||
::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env));
|
||||
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category())
|
||||
ec.assign(errno, system_category());
|
||||
detail::on_exec_error(*this, executable, argv, ec, inits...);
|
||||
::exit(EXIT_FAILURE);
|
||||
return basic_process<Executor>{exec};
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <boost/process/v2/default_launcher.hpp>
|
||||
#include <boost/process/v2/exit_code.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
#include <boost/process/v2/ext/exe.hpp>
|
||||
#include <boost/process/v2/process_handle.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
@@ -215,37 +214,6 @@ struct basic_process
|
||||
process_handle_.request_exit(ec);
|
||||
}
|
||||
|
||||
/// Send the process a signal requesting it to stop. This may rely on undocumented functions.
|
||||
void suspend(error_code &ec)
|
||||
{
|
||||
process_handle_.suspend(ec);
|
||||
}
|
||||
|
||||
/// Send the process a signal requesting it to stop. This may rely on undocumented functions.
|
||||
void suspend()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "suspend");
|
||||
}
|
||||
|
||||
|
||||
/// Send the process a signal requesting it to resume. This may rely on undocumented functions.
|
||||
void resume(error_code &ec)
|
||||
{
|
||||
process_handle_.resume(ec);
|
||||
}
|
||||
|
||||
/// Send the process a signal requesting it to resume. This may rely on undocumented functions.
|
||||
void resume()
|
||||
{
|
||||
error_code ec;
|
||||
suspend(ec);
|
||||
if (ec)
|
||||
detail::throw_error(ec, "resume");
|
||||
}
|
||||
|
||||
/// Throwing @overload void terminate(native_exit_code_type &exit_code, error_code & ec)
|
||||
void terminate()
|
||||
{
|
||||
@@ -270,7 +238,7 @@ struct basic_process
|
||||
detail::throw_error(ec, "wait failed");
|
||||
return exit_code();
|
||||
}
|
||||
/// Waits for the process to exit, store the exit code internally and return it.
|
||||
/// Waits for the process to exit, store the exit code internall and return it.
|
||||
int wait(error_code & ec)
|
||||
{
|
||||
if (running(ec))
|
||||
@@ -400,4 +368,4 @@ typedef basic_process<> process;
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_PROCESS_HPP
|
||||
#endif //BOOST_PROCESS_V2_PROCESS_HPP
|
||||
@@ -27,8 +27,8 @@ static const error_category& shell_category = get_shell_category();
|
||||
* In v1, this was possible directly when starting a process,
|
||||
* but has been removed based on the security risks associated with this.
|
||||
*
|
||||
* By making the shell parsing explicitly, it encourages
|
||||
* a user to run a sanity check on the executable before launching it.
|
||||
* By making the shell parsing explicity, it is encouraged
|
||||
* that a user runs a sanity check on the executable before launching it.
|
||||
*
|
||||
* @par Example
|
||||
* @code {.cpp}
|
||||
@@ -79,10 +79,8 @@ struct shell
|
||||
: buffer_(std::move(lhs.buffer_)),
|
||||
input_(std::move(lhs.input_)),
|
||||
argc_(boost::exchange(lhs.argc_, 0)),
|
||||
argv_(boost::exchange(lhs.argv_, nullptr))
|
||||
#if defined(BOOST_PROCESS_V2_POSIX)
|
||||
, free_argv_(boost::exchange(lhs.free_argv_, nullptr))
|
||||
#endif
|
||||
argv_(boost::exchange(lhs.argv_, nullptr)),
|
||||
reserved_(boost::exchange(lhs.reserved_, 0))
|
||||
{
|
||||
}
|
||||
shell& operator=(shell && lhs) noexcept
|
||||
@@ -92,9 +90,7 @@ struct shell
|
||||
input_ = std::move(lhs.input_);
|
||||
argc_ = boost::exchange(lhs.argc_, 0);
|
||||
argv_ = boost::exchange(lhs.argv_, nullptr);
|
||||
#if defined(BOOST_PROCESS_V2_POSIX)
|
||||
free_argv_ = boost::exchange(lhs.free_argv_, nullptr);
|
||||
#endif
|
||||
reserved_ = boost::exchange(lhs.reserved_, 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -120,9 +116,6 @@ struct shell
|
||||
BOOST_PROCESS_V2_DECL ~shell();
|
||||
|
||||
private:
|
||||
|
||||
friend struct make_cmd_shell_;
|
||||
|
||||
BOOST_PROCESS_V2_DECL void parse_();
|
||||
|
||||
// storage in case we need a conversion
|
||||
@@ -131,10 +124,7 @@ struct shell
|
||||
// impl details
|
||||
int argc_ = 0;
|
||||
char_type ** argv_ = nullptr;
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_POSIX)
|
||||
void(*free_argv_)(int, char **);
|
||||
#endif
|
||||
int reserved_ = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -10,16 +10,11 @@
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
# error Do not compile Process V2 library source with BOOST_PROCESS_V2_HEADER_ONLY defined. You should probably define BOOST_PROCESS_V2_SEPARATE_COMPILATION
|
||||
# error Do not compile Beast library source with BOOST_BEAST_HEADER_ONLY defined
|
||||
#endif
|
||||
|
||||
#include <boost/process/v2/impl/error.ipp>
|
||||
#include <boost/process/v2/impl/pid.ipp>
|
||||
#include <boost/process/v2/ext/impl/exe.ipp>
|
||||
#include <boost/process/v2/ext/impl/cwd.ipp>
|
||||
#include <boost/process/v2/ext/impl/cmd.ipp>
|
||||
#include <boost/process/v2/ext/impl/env.ipp>
|
||||
#include <boost/process/v2/ext/detail/impl/proc_info.ipp>
|
||||
#include <boost/process/v2/detail/impl/environment.ipp>
|
||||
#include <boost/process/v2/detail/impl/last_error.ipp>
|
||||
#include <boost/process/v2/detail/impl/throw_error.ipp>
|
||||
@@ -29,4 +24,8 @@
|
||||
#include <boost/process/v2/impl/process_handle.ipp>
|
||||
#include <boost/process/v2/impl/shell.ipp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <boost/process/v2/detail/impl/group_impl_windows.ipp>
|
||||
#endif
|
||||
|
||||
#endif //BOOST_PROCESS_V2_SRC_HPP
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#define BOOST_PROCESS_v2_START_DIR_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/default_launcher.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#define BOOST_PROCESS_V2_STDIO_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/default_launcher.hpp>
|
||||
#include <cstddef>
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
@@ -69,11 +68,7 @@ struct process_io_binding
|
||||
{
|
||||
DWORD res;
|
||||
if (!::GetHandleInformation(h, &res))
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
|
||||
throw system_error(ec, "get_flags");
|
||||
}
|
||||
detail::throw_last_error("get_flags");
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -180,7 +175,7 @@ struct process_io_binding
|
||||
fd = p[1];
|
||||
if (::fcntl(p[0], F_SETFD, FD_CLOEXEC) == -1)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
return ;
|
||||
}
|
||||
fd_needs_closing = true;
|
||||
@@ -199,7 +194,7 @@ struct process_io_binding
|
||||
fd = p[0];
|
||||
if (::fcntl(p[1], F_SETFD, FD_CLOEXEC) == -1)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
return ;
|
||||
}
|
||||
fd_needs_closing = true;
|
||||
@@ -265,7 +260,7 @@ typedef process_io_binding<STDERR_FILENO> process_error_binding;
|
||||
* - `FILE*` any open file, including `stdin`, `stdout` and `stderr`
|
||||
* - a filesystem::path, which will open a readable or writable depending on the direction of the stream
|
||||
* - `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
|
||||
* - any io-object with a .native_handle() function that is comptaiblie 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.
|
||||
*
|
||||
*
|
||||
|
||||
@@ -107,7 +107,7 @@ struct as_user_launcher : default_launcher
|
||||
|
||||
if (ok == 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
detail::on_error(*this, executable, command_line, ec, inits...);
|
||||
|
||||
if (process_information.hProcess != INVALID_HANDLE_VALUE)
|
||||
|
||||
@@ -36,7 +36,7 @@ struct process_creation_flags
|
||||
};
|
||||
};
|
||||
|
||||
/// A flag to create a new process group. Necessary to allow interrupts for the subprocess.
|
||||
/// A flag to create a new process group. Necessary to allow interupts for the subproces.
|
||||
constexpr static process_creation_flags<CREATE_NEW_PROCESS_GROUP> create_new_process_group;
|
||||
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
#ifndef BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP
|
||||
#define BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP
|
||||
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/detail/utf8.hpp>
|
||||
#include <boost/process/v2/error.hpp>
|
||||
@@ -314,7 +315,7 @@ struct default_launcher
|
||||
auto ec__ = detail::get_last_error();
|
||||
if (ok == 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
detail::on_error(*this, executable, command_line, ec, inits...);
|
||||
|
||||
if (process_information.hProcess != INVALID_HANDLE_VALUE)
|
||||
|
||||
23
include/boost/process/v2/windows/impl/job_object_service.ipp
Normal file
23
include/boost/process/v2/windows/impl/job_object_service.ipp
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// boost/process/v2/windows/impl/job_object_service.ipp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_WINDOWS_IMPL_JOB_OBJECT_SERVICE_IPP
|
||||
#define BOOST_PROCESS_V2_WINDOWS_IMPL_JOB_OBJECT_SERVICE_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/windows/job_object_service.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
namespace windows
|
||||
{
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
|
||||
#endif //BOOST_PROCESS_V2_WINDOWS_IMPL_JOB_OBJECT_SERVICE_IPP
|
||||
@@ -111,7 +111,7 @@ struct with_logon_launcher : default_launcher
|
||||
|
||||
if (ok == 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
detail::on_error(*this, executable, command_line, ec, inits...);
|
||||
|
||||
if (process_information.hProcess != INVALID_HANDLE_VALUE)
|
||||
|
||||
@@ -106,7 +106,7 @@ struct with_token_launcher : default_launcher
|
||||
|
||||
if (ok == 0)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
ec = detail::get_last_error();
|
||||
detail::on_error(*this, executable, command_line, ec, inits...);
|
||||
|
||||
if (process_information.hProcess != INVALID_HANDLE_VALUE)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"key": "process",
|
||||
"name": "Process",
|
||||
"name": "process",
|
||||
"authors": [
|
||||
"Merino Vidal", "Ilya Sokolov", "Felipe Tanus",
|
||||
"Jeff Flinn", "Thomas Jarosch", "Boris Schaeling", "Klemens D. Morgenstern"
|
||||
|
||||
@@ -100,8 +100,8 @@ test-suite with-valgrind :
|
||||
[ run env.cpp program_options system filesystem : [ test-options env ] : sparring_partner ]
|
||||
[ run group.cpp system thread filesystem : [ test-options group ] : sub_launch ]
|
||||
[ run group.cpp system thread filesystem : [ test-options group ] : sub_launch : <build>no <target-os>windows:<build>yes <define>BOOST_USE_WINDOWS_H=1 : group-windows-h ]
|
||||
[ run group_wait.cpp system thread filesystem : [ test-options group_wait ] : sparring_partner : <target-os>darwin:<build>no <target-os>freebsd:<build>no ]
|
||||
[ run limit_fd.cpp program_options system filesystem : [ test-options limit_fd ] : sparring_partner : <target-os>freebsd:<build>no ]
|
||||
[ run group_wait.cpp system thread filesystem : [ test-options group_wait ] : sparring_partner : <target-os>darwin:<build>no ]
|
||||
[ run limit_fd.cpp program_options system filesystem : [ test-options limit_fd ] : sparring_partner ]
|
||||
[ run run_exe.cpp filesystem : : sparring_partner ]
|
||||
[ run run_exe_path.cpp filesystem : [ test-options run_exe_path ] : sparring_partner ]
|
||||
[ run search_path.cpp filesystem system : [ test-options search_path ] : : <target-os>windows:<source>shell32 ]
|
||||
@@ -111,7 +111,7 @@ test-suite with-valgrind :
|
||||
[ run system_test2.cpp filesystem system : [ test-options system_test2 ] : sparring_partner ]
|
||||
[ run spawn.cpp filesystem system : [ test-options spawn ] : sparring_partner ]
|
||||
[ run start_dir.cpp filesystem system : [ test-options start_dir ] : sparring_partner ]
|
||||
[ run terminate.cpp system filesystem : [ test-options terminate ] : sparring_partner : <target-os>freebsd:<build>no ]
|
||||
[ run terminate.cpp system filesystem : [ test-options terminate ] : sparring_partner ]
|
||||
[ run throw_on_error.cpp system filesystem : [ test-options throw_on_error ] : sparring_partner ]
|
||||
[ run wait.cpp system filesystem : [ test-options wait ] : sparring_partner ]
|
||||
[ run wait_for.cpp system filesystem : [ test-options wait_for ] : sparring_partner ]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// 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)
|
||||
// Created by kleme on 26.02.2018.
|
||||
//
|
||||
|
||||
#define BOOST_ASIO_NO_DEPRECATED 1
|
||||
#include <boost/process.hpp>
|
||||
|
||||
@@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(multithreaded_async_pipe)
|
||||
asio::io_context ioc;
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
for (auto i = 0u; i < std::thread::hardware_concurrency(); i++)
|
||||
for (int i = 0; i < std::thread::hardware_concurrency(); i++)
|
||||
{
|
||||
threads.emplace_back([&ioc]
|
||||
{
|
||||
@@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(move_pipe)
|
||||
}
|
||||
/*
|
||||
{
|
||||
//copy a closed pipe
|
||||
//copy an a closed pipe
|
||||
BOOST_TEST_CHECKPOINT("Copy assign");
|
||||
BOOST_TEST_CHECKPOINT("Fourth move, from closed");
|
||||
bp::async_pipe ap_inv{ios};
|
||||
@@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(move_pipe)
|
||||
}
|
||||
|
||||
{
|
||||
//copy a closed pipe
|
||||
//copy an a closed pipe
|
||||
BOOST_TEST_CHECKPOINT("Copy assign");
|
||||
BOOST_TEST_CHECKPOINT("Fourth move, from closed");
|
||||
bp::async_pipe ap_inv{ios};
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace bp = boost::process;
|
||||
namespace fs = boost::process::filesystem;
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(explicit_)
|
||||
BOOST_AUTO_TEST_CASE(excplicit)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
@@ -83,24 +83,3 @@ BOOST_AUTO_TEST_CASE(implicit)
|
||||
BOOST_TEST_MESSAGE(ec.message());
|
||||
BOOST_CHECK_EQUAL(ret, 21);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(empty_cmd)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
fs::path pth = master_test_suite().argv[1];
|
||||
auto env = boost::this_process::environment();
|
||||
|
||||
auto itr = std::find_if(env.begin(), env.end(),
|
||||
[](const bp::native_environment::entry_type & e){return boost::to_upper_copy(e.get_name()) == "PATH";});
|
||||
|
||||
BOOST_REQUIRE(itr != env.end());
|
||||
|
||||
(*itr) += fs::canonical(fs::absolute(pth.parent_path())).string();
|
||||
BOOST_REQUIRE(itr != env.end());
|
||||
|
||||
bp::system("sparring_partner \"\" ", ec);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#include <boost/process/error.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/extend.hpp>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/scope_exit.hpp>
|
||||
|
||||
#include <boost/process/error.hpp>
|
||||
#include <boost/process/io.hpp>
|
||||
#include <boost/process/args.hpp>
|
||||
@@ -45,10 +45,6 @@ BOOST_AUTO_TEST_CASE(wait_group_test, *boost::unit_test::timeout(5))
|
||||
BOOST_REQUIRE(done.load());
|
||||
}};
|
||||
|
||||
BOOST_SCOPE_EXIT_ALL(&) {
|
||||
done.store(true);
|
||||
thr.join();
|
||||
};
|
||||
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
@@ -78,10 +74,13 @@ BOOST_AUTO_TEST_CASE(wait_group_test, *boost::unit_test::timeout(5))
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
BOOST_REQUIRE(c2.in_group(ec));
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
g.wait(ec);
|
||||
g.wait();
|
||||
|
||||
BOOST_CHECK(!c1.running());
|
||||
BOOST_CHECK(!c2.running());
|
||||
|
||||
done.store(true);
|
||||
thr.join();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,19 +40,12 @@ BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5))
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
const auto get_handle = [](FILE * f) {return reinterpret_cast<bt::native_handle_type>(_get_osfhandle(_fileno(f)));};
|
||||
const auto socket_to_handle = [](::boost::winapi::UINT_PTR_ sock){return reinterpret_cast<::boost::winapi::HANDLE_>(sock);};
|
||||
#else
|
||||
const auto get_handle = [](FILE * f) {return fileno(f);};
|
||||
const auto socket_to_handle = [](int i){ return i;};
|
||||
|
||||
#if !defined(__linux__)
|
||||
return ;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
enable_testing()
|
||||
|
||||
add_library(boost_process_v2_test_impl test_impl.cpp)
|
||||
target_link_libraries(boost_process_v2_test_impl Boost::process Boost::unit_test_framework Boost::process)
|
||||
target_compile_definitions(boost_process_v2_test_impl PUBLIC -DBOOST_PROCESS_V2_SEPARATE_COMPILATION=1)
|
||||
|
||||
if (WIN32)
|
||||
target_compile_definitions(boost_process_v2_test_impl PUBLIC WIN32_LEAN_AND_MEAN=1)
|
||||
target_link_libraries(boost_process_v2_test_impl Boost::process Boost::unit_test_framework Boost::process Ntdll)
|
||||
else()
|
||||
target_link_libraries(boost_process_v2_test_impl Boost::process Boost::unit_test_framework Boost::process)
|
||||
endif()
|
||||
|
||||
function(boost_process_v2_standalone_test name)
|
||||
@@ -33,9 +31,7 @@ function(boost_process_v2_test_with_target name)
|
||||
add_dependencies(boost_process_v2_${name} boost_process_v2_test_target)
|
||||
add_test(NAME boost_process_v2_${name} COMMAND $<TARGET_FILE:boost_process_v2_${name}>
|
||||
-- $<TARGET_FILE:boost_process_v2_test_target>)
|
||||
|
||||
|
||||
endfunction()
|
||||
|
||||
boost_process_v2_test_with_target(process)
|
||||
boost_process_v2_test_with_target(ext)
|
||||
boost_process_v2_test_with_target(group)
|
||||
@@ -21,12 +21,7 @@ project : requirements
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
|
||||
<toolset>msvc:<cxxflags>/bigobj
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<target-os>windows:<define>_WIN32_WINNT=0x0601
|
||||
<target-os>linux:<linkflags>-lpthread
|
||||
<target-os>freebsd:<linkflags>-lutil
|
||||
<target-os>freebsd:<linkflags>-lkvm
|
||||
<target-os>freebsd:<linkflags>-lprocstat
|
||||
<target-os>bsd:<linkflags>-lkvm
|
||||
<os>NT,<toolset>cw:<library>ws2_32
|
||||
<os>NT,<toolset>gcc:<library>ws2_32
|
||||
<define>BOOST_PROCESS_V2_SEPARATE_COMPILATION=1
|
||||
@@ -51,21 +46,19 @@ lib test_impl : test_impl.cpp filesystem :
|
||||
<link>static
|
||||
<target-os>windows:<source>shell32
|
||||
<target-os>windows:<source>user32
|
||||
<target-os>windows:<source>Ntdll
|
||||
<target-os>windows:<source>Advapi32
|
||||
;
|
||||
|
||||
test-suite standalone :
|
||||
[ run utf8.cpp test_impl ]
|
||||
[ run cstring_ref.cpp test_impl ]
|
||||
[ run environment.cpp test_impl ]
|
||||
[ run pid.cpp test_impl ]
|
||||
[ run shell.cpp test_impl ]
|
||||
;
|
||||
|
||||
test-suite with_target :
|
||||
[ run pid.cpp test_impl : --log_level=all --catch_system_errors=no -- : target ]
|
||||
[ run process.cpp test_impl : --log_level=all --catch_system_errors=no -- : target ]
|
||||
[ run windows.cpp test_impl : --log_level=all --catch_system_errors=no -- : target : <build>no <target-os>windows:<build>yes <target-os>windows:<source>Advapi32 ]
|
||||
[ run ext.cpp test_impl : --log_level=all --catch_system_errors=no -- : target : <target-os>darwin:<build>no ]
|
||||
[ run group.cpp test_impl : --log_level=all --catch_system_errors=no -- : target ]
|
||||
;
|
||||
|
||||
|
||||
180
test/v2/ext.cpp
180
test/v2/ext.cpp
@@ -1,180 +0,0 @@
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern
|
||||
// Copyright (c) 2022 Samuel Venable
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process/v2/ext/cmd.hpp>
|
||||
#include <boost/process/v2/ext/cwd.hpp>
|
||||
#include <boost/process/v2/ext/env.hpp>
|
||||
#include <boost/process/v2/ext/exe.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
#include <boost/process/v2/process.hpp>
|
||||
#include <boost/process/v2/start_dir.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(ext)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_exe)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
namespace bp2 = boost::process::v2;
|
||||
auto pth = bp2::ext::exe(bp2::current_pid());
|
||||
BOOST_CHECK(!pth.empty());
|
||||
BOOST_CHECK_EQUAL(bp2::filesystem::canonical(master_test_suite().argv[0]).string(),
|
||||
bp2::filesystem::canonical(pth).string());
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_child_exe)
|
||||
{
|
||||
namespace bp2 = boost::process::v2;
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
const auto pth = bp2::filesystem::canonical(master_test_suite().argv[0]);
|
||||
|
||||
boost::asio::io_context ctx;
|
||||
bp2::process proc(ctx, pth, {"sleep", "10000"});
|
||||
BOOST_CHECK_EQUAL(bp2::ext::exe(proc.handle()), pth);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cmd)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
|
||||
namespace bp2 = boost::process::v2;
|
||||
auto cmd = bp2::ext::cmd(bp2::current_pid());
|
||||
|
||||
// the test framework drops a bunch of args.
|
||||
bp2::basic_cstring_ref<typename bp2::shell::char_type> ref(cmd.argv()[0]);
|
||||
BOOST_CHECK_EQUAL(
|
||||
bp2::detail::conv_string<char>(
|
||||
ref.data(), ref.size()
|
||||
), master_test_suite().argv[0]);
|
||||
|
||||
auto cm = cmd.argv() + (cmd.argc() - master_test_suite().argc);
|
||||
for (auto i = 1; i < master_test_suite().argc; i++)
|
||||
{
|
||||
bp2::basic_cstring_ref<typename bp2::shell::char_type> ref(cm[i]);
|
||||
|
||||
BOOST_CHECK_EQUAL(bp2::detail::conv_string<char>(ref.data(), ref.size()),
|
||||
master_test_suite().argv[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cmd_exe)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
const auto pth = master_test_suite().argv[0];
|
||||
|
||||
namespace bp2 = boost::process::v2;
|
||||
|
||||
boost::asio::io_context ctx;
|
||||
std::vector<std::string> args = {"sleep", "10000", "moar", "args", " to test "};
|
||||
bp2::process proc(ctx, pth, args);
|
||||
auto cm = bp2::ext::cmd(proc.handle());
|
||||
|
||||
bp2::basic_cstring_ref<typename bp2::shell::char_type> ref(cm.argv()[0]);
|
||||
BOOST_CHECK_EQUAL(bp2::detail::conv_string<char>(ref.data(), ref.size()), pth);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(cm.argc(), args.size() + 1);
|
||||
for (auto i = 0u; i < args.size(); i++)
|
||||
{
|
||||
ref = cm.argv()[i + 1];
|
||||
|
||||
BOOST_CHECK_EQUAL(bp2::detail::conv_string<char>(ref.data(), ref.size()), args[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_cwd)
|
||||
{
|
||||
namespace bp2 = boost::process::v2;
|
||||
auto pth = bp2::ext::cwd(bp2::current_pid()).string();
|
||||
if (pth.back() == '\\')
|
||||
pth.pop_back();
|
||||
BOOST_CHECK_EQUAL(pth, bp2::filesystem::current_path());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_cwd_exe)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
namespace bp2 = boost::process::v2;
|
||||
const auto pth = bp2::filesystem::absolute(master_test_suite().argv[0]);
|
||||
|
||||
auto tmp = bp2::filesystem::temp_directory_path();
|
||||
|
||||
boost::asio::io_context ctx;
|
||||
bp2::process proc(ctx, pth, {"sleep", "10000"},
|
||||
bp2::process_start_dir{tmp});
|
||||
auto tt = bp2::ext::cwd(proc.handle()).string();
|
||||
if (tt.back() == '\\')
|
||||
tt.pop_back();
|
||||
BOOST_CHECK_EQUAL(tt, tmp);
|
||||
bp2::error_code ec;
|
||||
bp2::filesystem::remove(tmp, ec);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_env)
|
||||
{
|
||||
namespace bp2 = boost::process::v2;
|
||||
auto env = bp2::ext::env(bp2::current_pid());
|
||||
|
||||
std::size_t e = 0;
|
||||
|
||||
for (const auto & kp : bp2::environment::current())
|
||||
{
|
||||
auto itr = std::find_if(env.begin(), env.end(),
|
||||
[&](bp2::environment::key_value_pair_view kp_)
|
||||
{
|
||||
return kp.key() == kp_.key();
|
||||
});
|
||||
if (itr != env.end())
|
||||
{
|
||||
BOOST_CHECK_EQUAL(kp.value(), (*itr).value());
|
||||
e++;
|
||||
}
|
||||
|
||||
}
|
||||
BOOST_CHECK_GT(e, 0u);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_env_exe)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
const auto pth = master_test_suite().argv[0];
|
||||
namespace bp2 = boost::process::v2;
|
||||
|
||||
auto tmp = bp2::filesystem::temp_directory_path();
|
||||
|
||||
boost::asio::io_context ctx;
|
||||
|
||||
std::vector<bp2::environment::key_value_pair> new_env;
|
||||
{
|
||||
auto cr = bp2::environment::current();
|
||||
new_env.assign(cr.begin(), cr.end());
|
||||
}
|
||||
|
||||
new_env.push_back("FOO=42");
|
||||
new_env.push_back("BAR=FOO");
|
||||
|
||||
bp2::process proc(ctx, pth, {"sleep", "10000"},
|
||||
bp2::process_environment(new_env));
|
||||
|
||||
auto env = bp2::ext::env(proc.handle());
|
||||
for (const auto & kp : new_env)
|
||||
{
|
||||
auto itr = std::find_if(env.begin(), env.end(),
|
||||
[&](bp2::environment::key_value_pair_view kp_)
|
||||
{
|
||||
return kp.key() == kp_.key();
|
||||
});
|
||||
BOOST_REQUIRE(itr != env.end());
|
||||
BOOST_CHECK_EQUAL(kp.value(), (*itr).value());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
179
test/v2/group.cpp
Normal file
179
test/v2/group.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
// 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)
|
||||
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/process/v2/group.hpp>
|
||||
#include <boost/process/v2.hpp>
|
||||
|
||||
namespace bp2 = boost::process::v2;
|
||||
namespace bpw = boost::process::v2::windows;
|
||||
namespace bpd = boost::process::v2::detail;
|
||||
namespace asio = boost::asio;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(wait_one)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
asio::io_context ctx;
|
||||
const auto pth = master_test_suite().argv[1];
|
||||
|
||||
bp2::error_code ec;
|
||||
bp2::group grp{ctx};
|
||||
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
|
||||
auto pid1 = grp.emplace(pth, {"sleep", "100"});
|
||||
auto pid2 = grp.emplace(pth, {"sleep", "300"});
|
||||
auto pid3 = grp.emplace(pth, {"sleep", "500"});
|
||||
|
||||
auto res1 = grp.wait_one(ec); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
auto res2 = grp.wait_one(ec); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
auto res3 = grp.wait_one(ec); BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
|
||||
|
||||
grp.wait_all(); //
|
||||
|
||||
BOOST_CHECK_EQUAL(res1.exit_code, 0);
|
||||
BOOST_CHECK_EQUAL(res2.exit_code, 0);
|
||||
BOOST_CHECK_EQUAL(res3.exit_code, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(res1.pid, pid1);
|
||||
BOOST_CHECK_EQUAL(res2.pid, pid2);
|
||||
BOOST_CHECK_EQUAL(res3.pid, pid3);
|
||||
|
||||
BOOST_CHECK(grp.is_open());
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(wait_all)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
asio::io_context ctx;
|
||||
const auto pth = master_test_suite().argv[1];
|
||||
|
||||
bp2::group grp{ctx};
|
||||
|
||||
|
||||
auto pid1 = grp.emplace(pth, {"sleep", "10"});
|
||||
auto pid2 = grp.emplace(pth, {"sleep", "30"});
|
||||
auto pid3 = grp.emplace(pth, {"sleep", "50"});
|
||||
|
||||
grp.wait_all(); //
|
||||
|
||||
BOOST_CHECK(grp.is_open());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(terminate_)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
asio::io_context ctx;
|
||||
const auto pth = master_test_suite().argv[1];
|
||||
|
||||
bp2::error_code ec;
|
||||
bp2::group grp{ctx};
|
||||
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
|
||||
const auto pid1 = grp.emplace(pth, {"sleep", "10000000"});
|
||||
const auto pid2 = grp.emplace(pth, {"sleep", "10000000"});
|
||||
const auto pid3 = grp.emplace(pth, {"sleep", "10000000"});
|
||||
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
|
||||
grp.terminate();
|
||||
grp.wait_all();
|
||||
|
||||
const auto end = std::chrono::steady_clock::now();
|
||||
BOOST_CHECK((start + std::chrono::milliseconds(5000)) > end);
|
||||
|
||||
BOOST_CHECK(grp.is_open());
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(async_wait_one)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
asio::io_context ctx;
|
||||
const auto pth = master_test_suite().argv[1];
|
||||
|
||||
bp2::error_code ec;
|
||||
bp2::group grp{ctx};
|
||||
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
|
||||
auto pid1 = grp.emplace(pth, {"sleep", "100"});
|
||||
auto pid2 = grp.emplace(pth, {"sleep", "300"});
|
||||
auto pid3 = grp.emplace(pth, {"sleep", "500"});
|
||||
|
||||
std::vector<bp2::pid_type> res;
|
||||
|
||||
grp.async_wait_one(
|
||||
[&](bp2::error_code ec, bp2::single_process_exit sp)
|
||||
{
|
||||
res.push_back(sp.pid);
|
||||
BOOST_CHECK_EQUAL(sp.exit_code, 0u);
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
});
|
||||
grp.async_wait_one(
|
||||
[&](bp2::error_code ec, bp2::single_process_exit sp)
|
||||
{
|
||||
res.push_back(sp.pid);
|
||||
BOOST_CHECK_EQUAL(sp.exit_code, 0u);
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
});
|
||||
grp.async_wait_one(
|
||||
[&](bp2::error_code ec, bp2::single_process_exit sp)
|
||||
{
|
||||
res.push_back(sp.pid);
|
||||
BOOST_CHECK_EQUAL(sp.exit_code, 0u);
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
});
|
||||
|
||||
BOOST_CHECK_GE(ctx.run(), 0u);
|
||||
|
||||
BOOST_CHECK_EQUAL(res.at(0), pid1);
|
||||
BOOST_CHECK_EQUAL(res.at(1), pid2);
|
||||
BOOST_CHECK_EQUAL(res.at(2), pid3);
|
||||
|
||||
|
||||
BOOST_CHECK(grp.is_open());
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(async_wait_all)
|
||||
{
|
||||
using boost::unit_test::framework::master_test_suite;
|
||||
asio::io_context ctx;
|
||||
const auto pth = master_test_suite().argv[1];
|
||||
|
||||
bp2::error_code ec;
|
||||
bp2::group grp{ctx};
|
||||
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
|
||||
auto pid1 = grp.emplace(pth, {"sleep", "10"});
|
||||
auto pid2 = grp.emplace(pth, {"sleep", "30"});
|
||||
auto pid3 = grp.emplace(pth, {"sleep", "50"});
|
||||
|
||||
grp.async_wait_all(
|
||||
[](bp2::error_code ec)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
});
|
||||
|
||||
ctx.run();
|
||||
|
||||
|
||||
BOOST_CHECK(grp.is_open());
|
||||
BOOST_CHECK_MESSAGE(!ec, ec.message());
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user