2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-20 04:42:24 +00:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Klemens David Morgenstern
83c2a986cb trait & fwd decl fixes 2019-04-10 13:41:08 +08:00
Klemens David Morgenstern
41fff78e00 Trying to add dynamic_buffer with sfinae as proposed in boostorg/process#56 2019-04-10 12:51:46 +08:00
331 changed files with 6904 additions and 24424 deletions

View File

@@ -70,6 +70,7 @@ jobs:
python <(curl -s https://report.ci/annotate.py) --tool gcc --input test.log
python <(curl -s https://report.ci/annotate.py) --tool gcc --input no-valgrind.log
bash <(curl -s https://codecov.io/bash) -x gcov > /dev/null || true
python <(curl -s https://report.ci/upload.py) --name "Circle CI Gcc Tests" --framework boost
bash <(curl -s https://codecov.io/bash) -x gcov || true
echo "BUILD_RESULT: $FAILED"
exit $FAILED

View File

@@ -1,38 +0,0 @@
# Use, modification, and distribution are
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE.txt)
#
# Copyright Rene Rivera 2020.
# For Drone CI we use the Starlark scripting language to reduce duplication.
# As the yaml syntax for Drone CI is rather limited.
#
#
globalenv={'B2_CI_VERSION': '1', 'B2_VARIANT': 'release'}
linuxglobalimage="cppalliance/droneubuntu1804:1"
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),
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",
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("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),
linux_cxx("coverity", "g++", packages="", buildtype="coverity", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'Coverity Scan', 'B2_TOOLSET': 'clang', 'DRONE_JOB_UUID': '472b07b9fc'}, globalenv=globalenv),
windows_cxx("msvc-14.1", "", image="cppalliance/dronevs2017", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "msvc-14.1", "CXXSTD": "11", "DEFINE" : "BOOST_BEAST_USE_STD_STRING_VIEW", "ADDRESS_MODEL": "64"}),
windows_cxx("msvc-14.3", "", image="cppalliance/dronevs2022:1", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "msvc-14.3", "CXXSTD": "11", "DEFINE" : "BOOST_BEAST_USE_STD_STRING_VIEW", "ADDRESS_MODEL": "64"}),
]
# from https://github.com/boostorg/boost-ci
load("@boost_ci//ci/drone/:functions.star", "linux_cxx","windows_cxx","osx_cxx","freebsd_cxx")

View File

@@ -1,34 +0,0 @@
@ECHO ON
setlocal enabledelayedexpansion
if "%DRONE_JOB_BUILDTYPE%" == "boost" (
echo '==================================> INSTALL'
git clone https://github.com/boostorg/boost-ci.git boost-ci-cloned --depth 1
cp -prf boost-ci-cloned/ci .
rm -rf boost-ci-cloned
REM source ci/travis/install.sh
REM The contents of install.sh below:
for /F %%i in ("%DRONE_REPO%") do @set SELF=%%~nxi
SET BOOST_CI_TARGET_BRANCH=%DRONE_COMMIT_BRANCH%
SET BOOST_CI_SRC_FOLDER=%cd%
call ci\common_install.bat
echo '==================================> COMPILE'
REM set B2_TARGETS=libs/!SELF!/test libs/!SELF!/example
set B2_TARGETS=libs/!SELF!/test
cd !BOOST_ROOT!
call bootstrap.bat
b2 headers
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/test libs/!SELF!/example -j3
) else if "%DRONE_JOB_BUILDTYPE%" == "standalone-windows" (
REM not used
)

View File

@@ -1,199 +0,0 @@
#!/bin/bash
# Copyright 2020 Rene Rivera, Sam Darwin
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt)
set -xe
export TRAVIS_BUILD_DIR=$(pwd)
export DRONE_BUILD_DIR=$(pwd)
export TRAVIS_BRANCH=$DRONE_BRANCH
export TRAVIS_EVENT_TYPE=$DRONE_BUILD_EVENT
export VCS_COMMIT_ID=$DRONE_COMMIT
export GIT_COMMIT=$DRONE_COMMIT
export REPO_NAME=$DRONE_REPO
export USER=$(whoami)
export CC=${CC:-gcc}
export PATH=~/.local/bin:/usr/local/bin:$PATH
common_install () {
git clone https://github.com/boostorg/boost-ci.git boost-ci-cloned --depth 1
cp -prf boost-ci-cloned/ci .
rm -rf boost-ci-cloned
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
unset -f cd
fi
export SELF=`basename $REPO_NAME`
export BOOST_CI_TARGET_BRANCH="$TRAVIS_BRANCH"
export BOOST_CI_SRC_FOLDER=$(pwd)
. ./ci/common_install.sh
}
if [ "$DRONE_JOB_BUILDTYPE" == "boost" ]; then
echo '==================================> INSTALL'
common_install
echo '==================================> SCRIPT'
$BOOST_ROOT/libs/$SELF/ci/travis/build.sh
elif [ "$DRONE_JOB_BUILDTYPE" == "docs" ]; then
echo '==================================> INSTALL'
export SELF=`basename $REPO_NAME`
pwd
cd ..
mkdir -p $HOME/cache && cd $HOME/cache
if [ ! -d doxygen ]; then git clone -b 'Release_1_8_15' --depth 1 https://github.com/doxygen/doxygen.git && echo "not-cached" ; else echo "cached" ; fi
cd doxygen
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release
cd build
sudo make install
cd ../..
if [ ! -f saxonhe.zip ]; then wget -O saxonhe.zip https://sourceforge.net/projects/saxon/files/Saxon-HE/9.9/SaxonHE9-9-1-4J.zip/download && echo "not-cached" ; else echo "cached" ; fi
unzip -o saxonhe.zip
sudo rm /usr/share/java/Saxon-HE.jar
sudo cp saxon9he.jar /usr/share/java/Saxon-HE.jar
cd ..
BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
git clone -b $BOOST_BRANCH https://github.com/boostorg/boost.git boost-root --depth 1
cd boost-root
export BOOST_ROOT=$(pwd)
git submodule update --init libs/context
git submodule update --init tools/boostbook
git submodule update --init tools/boostdep
git submodule update --init tools/docca
git submodule update --init tools/quickbook
rsync -av $TRAVIS_BUILD_DIR/ libs/$SELF
python tools/boostdep/depinst/depinst.py ../tools/quickbook
./bootstrap.sh
./b2 headers
echo '==================================> SCRIPT'
echo "using doxygen ; using boostbook ; using saxonhe ;" > tools/build/src/user-config.jam
./b2 -j3 libs/$SELF/doc//boostrelease
elif [ "$DRONE_JOB_BUILDTYPE" == "codecov" ]; then
echo '==================================> INSTALL'
common_install
echo '==================================> SCRIPT'
cd $BOOST_ROOT/libs/$SELF
ci/travis/codecov.sh
elif [ "$DRONE_JOB_BUILDTYPE" == "valgrind" ]; then
echo '==================================> INSTALL'
common_install
echo '==================================> SCRIPT'
cd $BOOST_ROOT/libs/$SELF
ci/travis/valgrind.sh
elif [ "$DRONE_JOB_BUILDTYPE" == "standalone" ]; then
echo '==================================> INSTALL'
# Installing cmake with apt-get, so not required here:
# pip install --user cmake
echo '==================================> SCRIPT'
export CXXFLAGS="-Wall -Wextra -Werror -std=c++17"
mkdir __build_17
cd __build_17
cmake -DBOOST_JSON_STANDALONE=1 ..
cmake --build .
ctest -V .
export CXXFLAGS="-Wall -Wextra -Werror -std=c++2a"
mkdir ../__build_2a
cd ../__build_2a
cmake -DBOOST_JSON_STANDALONE=1 ..
cmake --build .
ctest -V .
elif [ "$DRONE_JOB_BUILDTYPE" == "coverity" ]; then
echo '==================================> INSTALL'
common_install
echo '==================================> SCRIPT'
if [ $VARIANT = "process_valgrind" ];
then export USE_VALGRIND="testing.launcher=valgrind valgrind=on";
fi ;
if [ -n "${COVERITY_SCAN_NOTIFICATION_EMAIL}" -a \( "$TRAVIS_BRANCH" = "develop" -o "$TRAVIS_BRANCH" = "master" \) -a \( "$DRONE_BUILD_EVENT" = "push" -o "$DRONE_BUILD_EVENT" = "cron" \) ] ; then
cd $BOOST_ROOT/libs/$SELF
ci/travis/coverity.sh
fi
elif [ "$DRONE_JOB_BUILDTYPE" == "cmake-superproject" ]; then
echo '==================================> INSTALL'
common_install
echo '==================================> COMPILE'
export CXXFLAGS="-Wall -Wextra -Werror"
mkdir __build_static
cd __build_static
cmake -DBOOST_ENABLE_CMAKE=1 -DBUILD_TESTING=ON -DBoost_VERBOSE=1 \
-DBOOST_INCLUDE_LIBRARIES=$SELF ..
cmake --build .
ctest --output-on-failure -R boost_$SELF
cd ..
mkdir __build_shared
cd __build_shared
cmake -DBOOST_ENABLE_CMAKE=1 -DBUILD_TESTING=ON -DBoost_VERBOSE=1 \
-DBOOST_INCLUDE_LIBRARIES=$SELF -DBUILD_SHARED_LIBS=ON ..
cmake --build .
ctest --output-on-failure -R boost_$SELF
elif [ "$DRONE_JOB_BUILDTYPE" == "cmake1" ]; then
echo '==================================> INSTALL'
pip install --user cmake
echo '==================================> SCRIPT'
export SELF=`basename $REPO_NAME`
BOOST_BRANCH=develop && [ "$DRONE_BRANCH" == "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
mkdir -p libs/$SELF
cp -r $DRONE_BUILD_DIR/* libs/$SELF
# git submodule update --init tools/boostdep
git submodule update --init --recursive
cd libs/$SELF
../../../b2 -sBOOST_BUILD_PATH=.
../../../b2 $MULTITHREAD with-valgrind address-model=64 architecture=x86 $USE_VALGRIND toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
fi

View File

@@ -1,201 +0,0 @@
name: CI
on:
pull_request:
push:
branches:
- master
- develop
- feature/**
env:
UBSAN_OPTIONS: print_stacktrace=1
jobs:
posix:
strategy:
fail-fast: false
matrix:
include:
- toolset: gcc-5
cxxstd: "11,14,1z"
os: ubuntu-18.04
install: g++-5
- toolset: gcc-6
cxxstd: "11,14,1z"
os: ubuntu-18.04
install: g++-6
- toolset: gcc-7
cxxstd: "11,14,17"
os: ubuntu-18.04
- toolset: gcc-10
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-10
- toolset: gcc-12
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: g++-12
- toolset: clang
compiler: clang++-3.9
cxxstd: "11,14"
os: ubuntu-18.04
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "11,14"
os: ubuntu-18.04
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "11,14,1z"
os: ubuntu-18.04
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
cxxstd: "11,14,17"
os: ubuntu-18.04
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "11,14,17"
os: ubuntu-18.04
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "11,14,17"
os: ubuntu-20.04
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-10
- toolset: clang
compiler: clang++-11
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-11
- toolset: clang
compiler: clang++-12
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-12
- toolset: clang
compiler: clang++-13
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: clang-13
- toolset: clang
compiler: clang++-14
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: clang-14
- toolset: clang
cxxstd: "11,14,17,2a"
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
./bootstrap.sh
./b2 -d0 headers
- name: Create user-config.jam
if: matrix.compiler
run: |
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
- name: Run tests
run: |
cd ../boost-root
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release
windows:
strategy:
fail-fast: false
matrix:
include:
- toolset: msvc-14.0
cxxstd: "14,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.2
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.3
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2022
- toolset: clang-win
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2022
- toolset: gcc
cxxstd: "11,14,17,2a"
addrmd: 64
os: windows-2019
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
- name: Run tests
shell: cmd
run: |
cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker

1
.gitignore vendored
View File

@@ -31,5 +31,4 @@
/notes.cpp
/notes_p.txt
.settings
.DS_Store

View File

@@ -23,6 +23,8 @@ os:
- linux
- osx
secure: "vs7qgXb0lQg8CTyDPSi3RQtOIOtssaCkBIx86UoEvTXwJCTOLPe7ZufQ0lobn0OVWo261AMx9GbumBBzqfsvJc1G6ixGBVwymiGli/R8DZDvvg9UdljsEk65s/XbujE/9qh97zKGGioFyCn1Bmf5+SdDAxsuXTZm/cBny5VxYaaCR7s2cFUmp4up/djqg1GI7uwBh3ceodT3OL1X3dlMV59gOJWWNsB+RO9b9DPhTW7nOlMNRiEFik4rweecQB0JS8LaHDjYwzIRrGYHX+lR9cE/O8GCCHcUOmq9jCozDdxx+HZRu4rb1ST1RiDbvYaoeTif0Df1fVXHWOoO2D4NlXB6tJPXw2mkop00j6zkcydUJYid6T1lwfEpXAhd5A9FvOIXO5hoju1wlqfkU2eFQ9Na8z8bCIX2niZmveZWp4Ag52gEPzJMFx9hHGT8J4FWMvkqTWezux1sPZrjZjc0kXdJrIp84D9MsBc1sKrxOAOb5ekSfIK5n4JDkgUtuwMSTvEdWqNJXFPZq1rEu4GTwX99z3/XF+pM5XaCDQtZ/zUA5SPHhy0dKLH/BvceUqLJt53+lMcpsltJDB+XxQ/CFL7IdgR91OKGus/z4dbVWiSdkoNvcuZqjQLFLOMVNxoqC6PRvDAEhpy21j/5GUPvM5baQS7IEin0NF7bOTtXJdY="
env:
matrix:
- BADGE=linux
@@ -71,7 +73,7 @@ before_install:
# Set this to the name of the library
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
- echo "Testing $PROJECT_TO_TEST"
- if [ $TRAVIS_OS_NAME = "osx" ]; then brew install gcc5; brew install valgrind; brew install llvm; TOOLSET=clang; BOOST_TEST_CATCH_SYSTEM_ERRORS=no; MULTITHREAD=-j8; else TOOLSET=gcc-5; REPORT_CI=--boost-process-report-ci USE_VALGRIND="testing.launcher=valgrind valgrind=on"; fi
- if [ $TRAVIS_OS_NAME = "osx" ]; then brew install gcc5; brew install valgrind; brew install llvm; TOOLSET=clang; BOOST_TEST_CATCH_SYSTEM_ERRORS=no; MULTITHREAD=-j8; else TOOLSET=gcc-5; USE_VALGRIND="testing.launcher=valgrind valgrind=on"; fi
# Cloning Boost libraries (fast nondeep cloning)
- BOOST=$HOME/boost-local
- git init $BOOST
@@ -85,7 +87,7 @@ before_install:
- git checkout $BOOST_BRANCH
- git submodule update --init --merge
- git remote set-branches --add origin $BOOST_BRANCH
- git pull --recurse-submodules || true
- git pull --recurse-submodules
- git submodule update --init
- git checkout $BOOST_BRANCH
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
@@ -101,8 +103,8 @@ before_install:
- echo BOOST_TEST_CATCH_SYSTEM_ERRORS $BOOST_TEST_CATCH_SYSTEM_ERRORS
script:
# `--coverage` flags required to generate coverage info for Coveralls
- ../../../b2 $MULTITHREAD with-valgrind address-model=64 architecture=x86 $USE_VALGRIND toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
- ../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
- ../../../b2 $MULTITHREAD with-valgrind address-model=64 architecture=x86 $USE_VALGRIND toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
- ../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
after_success:
# Copying Coveralls data to a separate folder
- mkdir -p $TRAVIS_BUILD_DIR/coverals
@@ -131,6 +133,6 @@ after_success:
- coveralls-lcov coverals/coverage.info
after_script:
- curl -s https://report.ci/upload.py | python - --token=$REPORT_CI_TOKEN --name="$BADGE test run"
- bash <(curl -s https://codecov.io/bash)
- cd $BOOST/libs/$PROJECT_TO_TEST/test
- curl -s https://report.ci/report.py | python - --name="$BADGE test run"

View File

@@ -1,72 +0,0 @@
# Generated by `boostdep --cmake process`
# Copyright 2020 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.16)
project(boost_process VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
add_library(boost_process
src/detail/environment_posix.cpp
src/detail/environment_win.cpp
src/detail/last_error.cpp
src/detail/process_handle_windows.cpp
src/detail/throw_error.cpp
src/detail/utf8.cpp
src/ext/cmd.cpp
src/ext/cwd.cpp
src/ext/env.cpp
src/ext/exe.cpp
src/ext/proc_info.cpp
src/posix/close_handles.cpp
src/windows/default_launcher.cpp
src/environment.cpp
src/error.cpp
src/pid.cpp
src/shell.cpp)
add_library(Boost::process ALIAS boost_process)
target_include_directories(boost_process PUBLIC include)
target_link_libraries(boost_process
PUBLIC
Boost::algorithm
Boost::asio
Boost::config
Boost::core
Boost::filesystem
Boost::fusion
Boost::iterator
Boost::move
Boost::optional
Boost::system
Boost::tokenizer
Boost::type_index
Boost::winapi
)
target_compile_definitions(boost_process
PRIVATE BOOST_PROCESS_SOURCE=1
)
if (BOOST_PROCESS_USE_STD_FS)
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_USE_STD_FS=1 )
else()
target_link_libraries(boost_process PUBLIC Boost::filesystem)
endif()
if (WIN32)
target_link_libraries(boost_process PUBLIC ntdll shell32 Advapi32 user32)
endif()
if(BUILD_SHARED_LIBS)
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_DYN_LINK)
else()
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_STATIC_LINK)
endif()
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()

View File

@@ -1,21 +1,18 @@
# [Boost Process (Boost.Process)](https://github.com/boostorg/process)
# [Boost Process (Boost.Process)](https://github.com/klemens-morgenstern/boost-process)
Boost.process is a library for comfortable management of processes, released with boost 1.64.0.
### Test results
| Branches | Linux / Windows | Code coverage | Matrix |
|----------|----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| Develop: | [![Build Status](https://drone.cpp.al/api/badges/boostorg/process/status.svg)](https://drone.cpp.al/boostorg/process) | [![codecov](https://codecov.io/gh/boostorg/process/branch/develop/graph/badge.svg?token=AhunMqTSpA)](https://codecov.io/gh/boostorg/process) | [![Matrix](https://img.shields.io/badge/matrix-develop-lightgray.svg)](http://www.boost.org/development/tests/develop/developer/process.html) |
| Master: | [![Build Status](https://drone.cpp.al/api/badges/boostorg/process/status.svg?ref=refs/heads/develop)](https://drone.cpp.al/boostorg/process) | [![codecov](https://codecov.io/gh/boostorg/process/branch/master/graph/badge.svg?token=AhunMqTSpA)](https://codecov.io/gh/boostorg/process) | [![Matrix](https://img.shields.io/badge/matrix-master-lightgray.svg)](http://www.boost.org/development/tests/master/developer/process.html) |
Branches | Linux | OSX | Windows | Code coverage | Matrix |
----------------|-------|-----|---------| ------------- |--------|
Develop: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=develop&env=BADGE=linux)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=develop&build=linux)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=linux) | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=develop&env=BADGE=osx)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=develop&build=osx)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=osx) | [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba/branch/develop?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/develop) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=develop&build=windows)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=windows) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=develop)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=develop) | [![Matrix](https://img.shields.io/badge/matrix-develop-lightgray.svg)](http://www.boost.org/development/tests/develop/developer/process.html)
Master: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=master&env=BADGE=linux)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=master&build=linux)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=linux) | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=master&env=BADGE=osx)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=master&build=osx)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=osx) | [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba/branch/master?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=master&build=windows)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=windows) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=master)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) | [![Matrix](https://img.shields.io/badge/matrix-master-lightgray.svg)](http://www.boost.org/development/tests/master/developer/process.html)
[Open Issues](https://github.com/klemens-morgenstern/boost-process/issues)
[Open Issues](https://github.com/boostorg/process/issues)
[Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/process.html)
[Latest developer documentation](http://klemens-morgenstern.github.io/process/)
### About
This C++11 library is the current result of a long attempt to get a boost.process library, which is going on since 2006.

View File

@@ -1,65 +0,0 @@
# Copyright (c) 2024 Klemens D. Morgenstern
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
import os ;
import feature ;
import ../../config/checks/config : requires ;
project : requirements
<define>BOOST_ASIO_NO_DEPRECATED
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
<toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
<toolset>msvc:<cxxflags>/bigobj
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
<target-os>linux:<linkflags>-lpthread
: source-location ../src
;
feature.feature boost.process.fs : boost std : propagated composite ;
feature.compose <boost.process.fs>std : <define>BOOST_PROCESS_USE_STD_FS=1 ;
alias process_sources
: detail/environment_posix.cpp
detail/environment_win.cpp
detail/last_error.cpp
detail/process_handle_windows.cpp
detail/throw_error.cpp
detail/utf8.cpp
ext/cmd.cpp
ext/cwd.cpp
ext/env.cpp
ext/exe.cpp
ext/proc_info.cpp
posix/close_handles.cpp
windows/default_launcher.cpp
environment.cpp
error.cpp
pid.cpp
shell.cpp
;
if [ os.name ] = NT
{
lib shell32 ;
lib Advapi32 ;
lib Ntdll ;
lib user32 ;
}
lib boost_process
: process_sources
: requirements <define>BOOST_PROCESS_SOURCE=1
<link>shared:<define>BOOST_PROCESS_DYN_LINK=1
<boost.process.fs>boost:<library>/boost//filesystem
<target-os>windows:<library>shell32
<target-os>windows:<library>user32
<target-os>windows:<library>Ntdll
<target-os>windows:<library>Advapi32
: usage-requirements
<link>shared:<define>BOOST_PROCESS_DYN_LINK=1
<boost.process.fs>boost:<library>/boost//filesystem
;
boost-install boost_process ;

View File

@@ -14,28 +14,24 @@ using doxygen ;
local images = [ glob images/*.svg ] ;
install images : $(images) : <location>html/boost_process ;
install images_glob : $(images) : <location>$(BOOST_ROOT)/doc/html/boost_process ;
install images_glob : $(images) : <location>$(BOOST_ROOT)/doc/html/boost_process ;
import type ;
type.register XMLPROCESSWORKAROUND : : XML ;
import generators ;
generators.register-standard common.copy : XML : XMLPROCESSWORKAROUND ;
xmlprocessworkaround posix_pseudocode : v1/posix_pseudocode.xml ;
xmlprocessworkaround windows_pseudocode : v1/windows_pseudocode.xml ;
xmlprocessworkaround posix_pseudocode : posix_pseudocode.xml ;
xmlprocessworkaround windows_pseudocode : windows_pseudocode.xml ;
path-constant INCLUDES : ../../.. ;
doxygen reference_v1
doxygen autodoc
:
../../../boost/process.hpp
[ glob ../../../boost/process/*.hpp ]
:
$(INCLUDES)/boost/process/v1.hpp
[ glob $(INCLUDES)/boost/process/v1/*.hpp ]
:
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
<doxygen:param>"PREDEFINED=\\
BOOST_PROCESS_DOXYGEN=1 \\
BOOST_PROCESS_V1_INLINE=
"
<doxygen:param>PREDEFINED=BOOST_PROCESS_DOXYGEN
<doxygen:param>HIDE_UNDOC_CLASSES=YES
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
<doxygen:param>EXAMPLE_PATH=.
@@ -46,50 +42,11 @@ doxygen reference_v1
doxygen reference_v2
:
$(INCLUDES)/boost/process/v2.hpp
[ glob $(INCLUDES)/boost/process/v2/*.hpp ]
:
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
<doxygen:param>PROJECT_NAME="Process V2"
<doxygen:param>PROJECT_BRIEF="The process library"
<doxygen:param>MACRO_EXPANSION=YES
<doxygen:param>EXPAND_ONLY_PREDEF=YES
<doxygen:param>"PREDEFINED=\\
GENERATING_DOCUMENTATION=1 \\
BOOST_PROCESS_V2_ASIO_NAMESPACE=boost::asio \\
\"BOOST_PROCESS_V2_BEGIN_NAMESPACE=namespace boost { namespace process { namespace v2 { \" \\
\"BOOST_PROCESS_V2_END_NAMESPACE= } } }\" \\
BOOST_PROCESS_V2_NAMESPACE=boost::process::v2 \\
BOOST_PROCESS_V2_DECL \\
BOOST_PROCESS_V2_SOURCE \\
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(x,y)=deduced \\
BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(X)=Token \\
BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(E)=DEFAULT_TYPE \\
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN=DEFAULT \\
BOOST_CONSTEXPR=constexpr \\
BOOST_CXX14_CONSTEXPR=constexpr \\
BOOST_PROCESS_V2_INLINE= \\
BOOST_ATTRIBUTE_NODISCARD=[[nodiscard]]
"
<doxygen.doxproc.id>reference_v2
<doxygen:param>SHOW_USED_FILES=NO
<doxygen:param>SHOW_FILES=NO
<doxygen:param>SHOW_NAMESPACES=YES
<doxygen:param>CLASS_DIAGRAMS=NO
<doxygen:param>SORT_MEMBERS_CTORS_1ST=YES
<doxygen:param>HIDE_UNDOC_CLASSES=NO
<xsl:path>.
;
boostbook standalone
:
process.qbk
:
<dependency>reference_v1
<dependency>reference_v2
<dependency>autodoc
<dependency>images
<dependency>images_glob
<xsl:param>boost.root=../../../..

View File

@@ -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]

View File

@@ -16,11 +16,11 @@ In that it is different than other facilities (like sockets) and provides anothe
Pipes are typically used for interprocess communication. The main reason is, that pipes can be directly assigned to the process stdio, i.e. stderr, stdin and stdout.
Additionally, half of the pipe can be inherited to the child process and closed in the father process. This will cause the pipe to be broken when the child process exits.
Though please note, that if the same thread reads and writes to a pipe, it will only talk to itself.
Though please not, that if the the same thread reads and write to a pipe, it will only talk to itself.
[section:anonymous Anonymous Pipes]
The most common pipes are anonymous. Since they have no name,
The usual type of pipes, are the anonymous ones. Since the have no name,
a handle to them can only be obtained from duplicating either handle.
In this library the following functions are used for the creation of unnamed pipes:
@@ -35,13 +35,13 @@ In this library the following functions are used for the creation of unnamed pip
As the name suggests, named pipes have a string identifier. This means that a
handle to them can be obtained with the identifier, too.
The implementation on posix uses [@http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html fifos],
The implementation on posix uses [@(http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html fifos],
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]
@@ -57,12 +57,12 @@ Every process is identified by a unique number[footnote it is unique as long as
[section:exit_code Exit code]
A process will return an integer value indicating whether it was successful. On posix
there are more codes associated with that, but not so on windows. Therefore there is no such encoding currently in the library.
there are more codes associated with that, but not so on windows. Therefore there is not such encoding currently in the library.
However an exit code of zero means the process was successful, while one different than zero indicates an error.
[endsect]
[section:termination Termination]
Processes can also be forced to exit. There are two ways to do this, signal the process to do so and wait, and just terminate the process without conditions.
Processes can also be forced to exit. There are two ways to do this, signal the process to so and wait, and just terminate the process without conditions.
Usually the first approach is to signal an exit request, but windows - unlike posix - does not provide a consistent way to do this. Hence this is not part of the
library and only the hard terminate is.
@@ -79,4 +79,4 @@ The environment is a map of variables local to every process. The most significa
[endsect]
[endsect]
[endsect]

View File

@@ -1,12 +1,12 @@
[section:design Design Rationale]
[section Scope]
This library is meant to give a wrapper around the different OS-specific methods
This library is meant to give an wrapper around the different OS-specific methods
to launch processes. Its aim is to provide all functionality that is available on
those systems and allow the user to do all related things, which require using the OS APIs.
[*This library does not try to provide a full library for everything process related.]
[*This library does not try to provide a full library for everything process related]
In many discussions the proposal was made to build boost.process into a DSEL [footnote Domain Specific Embedded Language] of some sort.
This is not the goal, it rather provides the facilities to build such a DSEL-library on top of it.
This is not the goal, it rather provides the facilities to build such a DSEL-Library on top of it.
Therefore the library also does [*not] force any particular use (such as only asynchronous communication) on its user.
It rather could be integrated with such a library.
@@ -33,7 +33,7 @@ Both styles can also be mixed in some cases.
system("gcc", "-c", args+={"main.cpp"});
```
In the following section the available styles will be described. Note that the
In the following section the avaible styles will be described. Note that the
overload style is implemented via type traits, so the types will be listed.
[caution There is no guarantee in which order the arguments will be applied!
@@ -54,7 +54,7 @@ interpret each string as an argument.
]
When using the overloading variant, a single string will result in a cmd interpretation,
several strings will yield a exe-args interpretation. Both versions can be set explicitly:
several strings will yield a exe-args interpretation. Both version can be set explicitly:
```
system("grep -c false /etc/passwd"); //cmd style
@@ -65,7 +65,7 @@ system(exe="grep", args={"-c", "false", "/etc/passwd"}); //exe-/args-
```
[note If a '"' sign is used in the argument style, it will be passed as part of the argument.
If the same effect is wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
If the same effect it wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
[note The `PATH` variable will automatically be searched in the command style,
but the one of the launching process, not the one passed to the child process.]
[endsect]
@@ -75,15 +75,15 @@ but the one of the launching process, not the one passed to the child process.]
The simplest form to extend functionality is to provide another handler, which
will be called on the respective events on process launching. The names are:
*`boost::process::v1::on_setup`
*`boost::process::v1::on_error`
*`boost::process::v1::on_success`
*`boost::process::on_setup`
*`boost::process::on_error`
*`boost::process::on_success`
As an example:
```
child c("ls", on_setup([](){cout << "On Setup" << endl;}));
child c("ls", on_setup([](){cout << "On Setup" << endl;});
```

View File

@@ -1,32 +1,32 @@
[def __on_exit__ [globalref boost::process::v1::on_exit on_exit]]
[def __on_success__ [globalref boost::process::v1::extend::on_success ex::on_success]]
[def __child__ [classref boost::process::v1::child child]]
[def __handler__ [classref boost::process::v1::extend::handler handler]]
[def __on_success__ [memberref boost::process::v1::extend::handler::on_success on_success]]
[def __posix_executor__ [classref boost::process::v1::extend::posix_executor ex::posix_executor]]
[def __windows_executor__ [classref boost::process::v1::extend::windows_executor ex::windows_executor]]
[def __on_exit__ [globalref boost::process::on_exit on_exit]]
[def __on_success__ [globalref boost::process::extend::on_success ex::on_success]]
[def __child__ [classref boost::process::child child]]
[def __handler__ [classref boost::process::extend::handler handler]]
[def __on_success__ [memberref boost::process::extend::handler::on_success on_success]]
[def __posix_executor__ [classref boost::process::extend::posix_executor ex::posix_executor]]
[def __windows_executor__ [classref boost::process::extend::windows_executor ex::windows_executor]]
[def __io_context__ [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_context.html boost::asio::io_context]]
[def __require_io_context__ [classref boost::process::v1::extend::require_io_context ex::require_io_context]]
[def __async_handler__ [classref boost::process::v1::extend::async_handler ex::async_handler]]
[def __get_io_context__ [funcref boost::process::v1::extend::get_io_context ex::get_io_context]]
[def __require_io_context__ [classref boost::process::extend::require_io_context ex::require_io_context]]
[def __async_handler__ [classref boost::process::extend::async_handler ex::async_handler]]
[def __get_io_context__ [funcref boost::process::extend::get_io_context ex::get_io_context]]
[section:extend Extensions]
To extend the library, the header [headerref boost/process/extend.hpp extend] is provided.
It only provides the explicit style for custom properties, but no implicit style.
What this means is, that a custom initializer can be implemented, a reference which can be passed to one of the launching functions.
If a class inherits [classref boost::process::v1::extend::handler] it will be regarded as an initializer and thus directly put into the sequence
What this means is, that a custom initializer can be implemented, a reference to which can be passed to one of the launching functions.
If a class inherits [classref boost::process::extend::handler] it will be regarded as a initializer and thus directly put into the sequence
the executor gets passed.
[section:structure Structure]
The executor calls different handlers of the initializers during the process launch.
The basic structure consists of three functions, as given below:
The basic structure is consists of three functions, as given below:
* [globalref boost::process::v1::extend::on_setup on_setup]
* [globalref boost::process::v1::extend::on_error on_error]
* [globalref boost::process::v1::extend::on_success on_success]
* [globalref boost::process::extend::on_setup on_setup]
* [globalref boost::process::extend::on_error on_error]
* [globalref boost::process::extend::on_success on_success]
'''
<imagedata fileref="boost_process/windows_exec.svg"/>
@@ -34,11 +34,11 @@ The basic structure consists of three functions, as given below:
Additionally posix provides three more handlers, listed below:
* [globalref boost::process::v1::extend::on_fork_error on_fork_error]
* [globalref boost::process::v1::extend::on_exec_setup on_exec_setup]
* [globalref boost::process::v1::extend::on_exec_error on_exec_error]
* [globalref boost::process::extend::on_fork_error on_fork_error]
* [globalref boost::process::extend::on_exec_setup on_exec_setup]
* [globalref boost::process::extend::on_exec_error on_exec_error]
For more information see the reference of [classref boost::process::v1::extend::posix_executor posix_executor].
For more information see the reference of [classref boost::process::extend::posix_executor posix_executor].
[endsect]
[section:simple Simple extensions]
@@ -53,10 +53,10 @@ namespace ex = bp::extend;
__child__ c("foo", __on_success__=[](auto & exec) {std::cout << "hello world" << std::endl;});
```
Considering that lambdas can also capture values, data can easily be shared between handlers.
Considering that lambda can also capture values, data can easily be shared between handlers.
To see which members the executor has, refer to [classref boost::process::v1::extend::windows_executor windows_executor]
and [classref boost::process::v1::extend::posix_executor posix_executor].
To see which members the executor has, refer to [classref boost::process::extend::windows_executor windows_executor]
and [classref boost::process::extend::posix_executor posix_executor].
[note Combined with __on_exit__ this can also handle the process exit.]
@@ -67,7 +67,7 @@ and [classref boost::process::v1::extend::posix_executor posix_executor].
[section:handler Handler Types]
Since the previous example is in a functional style, it is not very reusable.
To solve that problem, the [classref boost::process::v1::extend::handler handler] has an alias in the `boost::process::v1::extend` namespace, to be inherited.
To solve that problem, the [classref boost::process::extend::handler handler] has an alias in the `boost::process::extend` namespace, to be inherited.
So let's implement the hello world example in a class.
```
@@ -86,7 +86,7 @@ __child__ c("foo", hello_world());
[note The implementation is done via overloading, not overriding.]
Every handler not implemented defaults to [classref boost::process::v1::extend::handler handler], where an empty handler is defined for each event.
Every handler not implemented dafaults to [classref boost::process::extend::handler handler], where an empty handler is defined for each event.
[endsect]
@@ -100,7 +100,7 @@ this functionality is also available for extensions. If the class needs the __io
```
struct async_foo : __handler__, __require_io_context__
{
template<typename Executor>
tempalte<typename Executor>
void on_setup(Executor & exec)
{
__io_context__ & ios = __get_io_context__(exec.seq); //gives us a reference and a compiler error if not present.
@@ -108,11 +108,11 @@ struct async_foo : __handler__, __require_io_context__
}
};
```
[note Inheriting [globalref boost::process::v1::extend::require_io_context require_io_context] is necessary, so [funcref boost::process::v1::system system] provides one.]
[note Inheriting [globalref boost::process::extend::require_io_context require_io_context] is necessary, so [funcref boost::process::system system] provides one.]
Additionally the handler can provide a function that is invoked when the child process exits. This is done through __async_handler__.
[note [globalref boost::process::v1::extend::async_handler async_handler] implies [globalref boost::process::v1::extend::require_io_context require_io_context] .]
[note [globalref boost::process::extend::async_handler async_handler] implies [globalref boost::process::extend::require_io_context require_io_context] .]
```
struct async_bar : __handler, __async_handler__
@@ -131,7 +131,7 @@ struct async_bar : __handler, __async_handler__
```
[caution `on_exit_handler` does not default and is always required when [classref boost::process::v1::extend::async_handler async_handler] is inherited. ]
[caution `on_exit_handler` does not default and is always required when [classref boost::process::extend::async_handler async_handler] is inherited. ]
[caution `on_exit_handler` uses `boost::asio::signal_set` to listen for SIGCHLD on posix. The application must not also register a signal handler for SIGCHLD using functions such as `signal()` or `sigaction()` (but using `boost::asio::signal_set` is fine). ]
@@ -139,10 +139,10 @@ struct async_bar : __handler, __async_handler__
[section:error Error handling]
If an error occurs in the initializers it shall be told to the executor and not handled directly. This is because
the behaviour can be changed through arguments passed to the launching function. Hence the executor
If an error occurs in the initializers it shall be told to the executor and not handles directly. This is because
the behaviour can be changed through arguments passed to the launching function. Hence the the executor
has the function `set_error`, which takes an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code] and a string.
Depending on the configuration of the executor, this may either throw, set an internal `error_code`, or do nothing.
Depending on the cofiguration of the executor, this may either throw, set an internal `error_code`, or do nothing.
So let's take a simple example, where we set a randomly chosen `error_code`.
@@ -156,7 +156,7 @@ auto set_error = [](auto & exec)
__child__ c("foo", on_setup=set_error);
```
Since we do not specify the error-handling mode in this example, this will throw [classref boost::process::v1::process_error process_error].
Since we do not specify the error-handling mode in this example, this will throw [classref boost::process::process_error process_error].
[endsect]
@@ -202,8 +202,8 @@ struct hello_exe : __handler__
};
```
So given our example, the definitions with the non-native executor are still a template so that they will not be evaluated if not used. Hence this provides a
way to implement system-specific code without using the preprocessor.
So given our example, the definitions with the non-native exectur are still a template so that they will not be evaluated if not used. Hence this provides a
way to implement systems-specific code without using the preprocessor.
[note If you only write a partial implementation, e.g. only for __posix_executor__, the other variants will default to __handler__].

View File

@@ -47,7 +47,7 @@ while (is >> file)
This will also deadlock, because the pipe does not close when the subprocess exits.
So the `ipstream` will still look for data even though the process has ended.
[note It is not possible to use automatic pipe-closing in this library, because
[note It is not possible to use automatically pipe-closing in this library, because
a pipe might be a file-handle (as for async pipes on windows).]
But, since pipes are buffered, you might get incomplete data if you do this:
@@ -64,7 +64,7 @@ while (c.running())
}
```
It is therefore highly recommended that you use the asynchronous API if you are
It is therefore highly recommended that you use the asynchronous api if you are
not absolutely sure how the output will look.
[endsect]

View File

@@ -10,15 +10,15 @@ Boost.Process is a library to manage system processes. It can be used to:
Here's a simple example of how to start a program with Boost.Process:
[def ipstream [classref boost::process::v1::ipstream ipstream]]
[def system [funcref boost::process::v1::system system]]
[def std_out [globalref boost::process::v1::std_out std_out]]
[def child [globalref boost::process::v1::child child]]
[def ipstream [classref boost::process::ipstream ipstream]]
[def system [funcref boost::process::system system]]
[def std_out [globalref boost::process::std_out std_out]]
[def child [globalref boost::process::child child]]
[def boost/process.hpp [headerref boost/process.hpp boost/process.hpp]]
[def std::string [@http://en.cppreference.com/w/cpp/string/basic_string std::string]]
[def std::getline [@http://en.cppreference.com/w/cpp/string/basic_string/getline std::getline]]
[import ../../example/intro.cpp]
[import ../example/intro.cpp]
[intro]
[endsect]

60
doc/posix_pseudocode.xml Normal file
View File

@@ -0,0 +1,60 @@
<?xml version="1.0" standalone="yes"?>
<programlisting>
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_setup">on_setup</methodname>(*this);
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
{
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
return <classname alt="boost::process::child">child</classname>();
}
pid = <ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html">fork()</ulink>
<methodname alt="boost::process::extend::handler::on_setup">on_setup</methodname>(*this);
if (pid == -1) //fork error
{
<methodname alt="boost::process::extend::posix_executor::set_error">set_error</methodname>(<functionname alt="boost::process::extend::get_last_error">get_last_error</functionname>());
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_fork_error">on_fork_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
return <classname alt="boost::process::child">child</classname>()
}
else if (pid == 0) //child process
{
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_exec_setup">on_exec_setup</methodname>(*this);
<ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html">execve</ulink>(exe, cmd_line, env);
auto ec = <functionname alt="boost::process::extend::get_last_error">get_last_error</functionname>();
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_exec_error">on_exec_error</methodname>(*this);
<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
}
<classname alt="boost::process::child">child</classname> c(pid, exit_code);
<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 &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
else
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
//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 &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
return <classname alt="boost::process::child">child</classname>();
}
else
return c;
</programlisting>

View File

@@ -11,8 +11,11 @@
]
]
[note Process v1 will be deprecated in the future. Use v2 for new projects.]
[include v1.qbk]
[include v2.qbk]
[include introduction.qbk]
[include concepts.qbk]
[include tutorial.qbk]
[include design.qbk]
[include extend.qbk]
[include faq.qbk]
[xinclude autodoc.xml]
[include acknowledgements.qbk]

View File

@@ -1,49 +1,49 @@
[def bp::system [funcref boost::process::v1::system bp::system]]
[def bp::async_system [funcref boost::process::v1::async_system bp::async_system]]
[def bp::spawn [funcref boost::process::v1::spawn bp::spawn]]
[def bp::child [classref boost::process::v1::child bp::child]]
[def bp::cmd [classref boost::process::v1::cmd bp::cmd]]
[def bp::group [classref boost::process::v1::group bp::group]]
[def bp::ipstream [classref boost::process::v1::ipstream bp::ipstream]]
[def bp::opstream [classref boost::process::v1::opstream bp::opstream]]
[def bp::pstream [classref boost::process::v1::pstream bp::pstream]]
[def bp::pipe [classref boost::process::v1::pipe bp::pipe]]
[def bp::async_pipe [classref boost::process::v1::async_pipe bp::async_pipe]]
[def bp::search_path [funcref boost::process::v1::search_path bp::search_path]]
[def bp::system [funcref boost::process::system bp::system]]
[def bp::async_system [funcref boost::process::async_system bp::async_system]]
[def bp::spawn [funcref boost::process::spawn bp::spawn]]
[def bp::child [classref boost::process::child bp::child]]
[def bp::cmd [classref boost::process::cmd bp::cmd]]
[def bp::group [classref boost::process::group bp::group]]
[def bp::ipstream [classref boost::process::ipstream bp::ipstream]]
[def bp::opstream [classref boost::process::opstream bp::opstream]]
[def bp::pstream [classref boost::process::pstream bp::pstream]]
[def bp::pipe [classref boost::process::pipe bp::pipe]]
[def bp::async_pipe [classref boost::process::async_pipe bp::async_pipe]]
[def bp::search_path [funcref boost::process::search_path bp::search_path]]
[def boost_org [@www.boost.org "www.boost.org"]]
[def std::system [@http://en.cppreference.com/w/cpp/utility/program/system std::system]]
[def child_running [memberref boost::process::v1::child::running running]]
[def child_wait [memberref boost::process::v1::child::wait wait]]
[def child_wait_for [memberref boost::process::v1::child::wait_for wait_for]]
[def child_exit_code [memberref boost::process::v1::child::exit_code exit_code]]
[def group_wait_for [memberref boost::process::v1::group::wait_for wait_for]]
[def bp::on_exit [globalref boost::process::v1::on_exit bp::on_exit]]
[def bp::null [globalref boost::process::v1::null bp::null]]
[def child_terminate [memberref boost::process::v1::child::terminate terminate]]
[def group_terminate [memberref boost::process::v1::group::terminate terminate]]
[def group_wait [memberref boost::process::v1::group::wait wait]]
[def bp::std_in [globalref boost::process::v1::std_in bp::std_in]]
[def bp::std_out [globalref boost::process::v1::std_out bp::std_out]]
[def bp::std_err [globalref boost::process::v1::std_err bp::std_err]]
[def child_running [memberref boost::process::child::running running]]
[def child_wait [memberref boost::process::child::wait wait]]
[def child_wait_for [memberref boost::process::child::wait_for wait_for]]
[def child_exit_code [memberref boost::process::child::exit_code exit_code]]
[def group_wait_for [memberref boost::process::group::wait_for wait_for]]
[def bp::on_exit [globalref boost::process::on_exit bp::on_exit]]
[def bp::null [globalref boost::process::null bp::null]]
[def child_terminate [memberref boost::process::child::terminate terminate]]
[def group_terminate [memberref boost::process::group::terminate terminate]]
[def group_wait [memberref boost::process::group::wait wait]]
[def bp::std_in [globalref boost::process::std_in bp::std_in]]
[def bp::std_out [globalref boost::process::std_out bp::std_out]]
[def bp::std_err [globalref boost::process::std_err bp::std_err]]
[def io_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]]
[def asio_buffer [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html boost::asio::buffer]]
[def asio_async_read [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_read.html boost::asio::async_read]]
[def bp::environment [classref boost::process::v1::basic_environment bp::environment]]
[def bp::native_environment [classref boost::process::v1::basic_native_environment bp::native_environment]]
[def bp::environment [classref boost::process::basic_environment bp::environment]]
[def bp::native_environment [classref boost::process::basic_native_environment bp::native_environment]]
[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]]
[def std::chrono::seconds [@http://en.cppreference.com/w/cpp/chrono/duration std::chrono::seconds]]
[def std::vector [@http://en.cppreference.com/w/cpp/container/vector std::vector]]
[def __wait_for__ [memberref boost::process::v1::child::wait_for wait_for]]
[def __wait_until__ [memberref boost::process::v1::child::wait_until wait_until]]
[def __detach__ [memberref boost::process::v1::child::detach detach]]
[def __wait_for__ [memberref boost::process::child::wait_for wait_for]]
[def __wait_until__ [memberref boost::process::child::wait_until wait_until]]
[def __detach__ [memberref boost::process::child::detach detach]]
[def __reference__ [link process.reference reference]]
[def __concepts__ [link boost_process.concepts concepts]]
[def boost::asio::yield_context [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/yield_context.html boost::asio::yield_context]]
[def boost::asio::coroutine [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/coroutine.html boost::asio::coroutine]]
[def bp::env [globalref boost::process::v1::env bp::env]]
[def bp::env [globalref boost::process::env bp::env]]
[section:tutorial Tutorial]
@@ -68,12 +68,12 @@ namespace bp = boost::process; //we will assume this for all further examples
int result = bp::system("g++ main.cpp");
```
If a single string is given (or the explicit form bp::cmd), it will be interpreted as a command line.
If a single string (or the explicit form bp::cmd), it will be interpreted as a command line.
That will cause the execution function to search the `PATH` variable to find the executable.
The alternative is the `exe-args` style, where the first string will be interpreted as a filename (including the path),
and the rest as arguments passed to said function.
[note For more details on the `cmd`/`exe-args` style look [link boost_process.design.arg_cmd_style here].]
[note For more details on the `cmd`/`exe-args` style look [link boost_process.design.arg_cmd_style here]]
So as a first step, we'll use the `exe-args` style.
@@ -82,10 +82,10 @@ int result = bp::system("/usr/bin/g++", "main.cpp");
```
With that syntax we still have "g++" hard-coded, so let's assume we get the string
from an external source as `boost::process::v1::filesystem::path`, we can do this too.
from an external source as `boost::filesystem::path`, we can do this too.
```
boost::process::v1::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
boost::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
int result = bp::system(p, "main.cpp");
```
@@ -93,28 +93,28 @@ Now we might want to find the `g++` executable in the `PATH`-variable, as the `c
`Boost.process` provides a function to this end: bp::search_path.
```
boost::process::v1::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else.
boost::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else.
int result = bp::system(p, "main.cpp");
```
[note [funcref boost::process::v1::search_path search_path] will search for any executable with that name.
[note [funcref boost::process::search_path search_path] will search for any executable with that name.
This also includes to add a file suffix on windows, such as `.exe` or `.bat`.]
[endsect]
[section:launch_mode Launch functions]
Given that our example used the [funcref boost::process::v1::system system] function,
Given that our example used the [funcref boost::process::system system] function,
our program will wait until the child process is completed. This may be unwanted,
especially since compiling can take a while.
In order to avoid that, boost.process provides several ways to launch a process.
Besides the already mentioned [funcref boost::process::v1::system system] function and its
asynchronous version [funcref boost::process::v1::async_system async_system],
we can also use the [funcref boost::process::v1::spawn spawn] function or the
[classref boost::process::v1::child child] class.
Besides the already mentioned [funcref boost::process::system system] function and its
asynchronous version [funcref boost::process::async_system async_system],
we can also use the [funcref boost::process::spawn spawn] function or the
[classref boost::process::child child] class.
The [funcref boost::process::v1::spawn spawn] function launches a process and
The [funcref boost::process::spawn spawn] function launches a process and
immediately detaches it, so no handle will be returned and the process will be ignored.
This is not what we need for compiling, but maybe we want to entertain the user,
while compiling:
@@ -124,7 +124,7 @@ bp::spawn(bp::search_path("chrome"), boost_org);
```
Now for the more sensible approach for compiling: a non-blocking execution.
To implement that, we directly call the constructor of [classref boost::process::v1::child child].
To implement that, we directly call the constructor of [classref boost::process::child child].
```
bp::child c(bp::search_path("g++"), "main.cpp");
@@ -141,7 +141,7 @@ things while the process is running and afterwards get the exit code. The call
to child_wait is necessary, to obtain it and tell the operating system, that no
one is waiting for the process anymore.
[note You can also wait for a time span or until a time point with __wait_for__ and __wait_until__.]
[note You can also wait for a time span or a until a time point with __wait_for__ and __wait_until__]
[warning If you don't call wait on a child object, it will be terminated on destruction.
This can be avoided by calling __detach__ beforehand]
@@ -189,9 +189,9 @@ Now, let's take a more visual example for reading data.
which reads the outline, i.e. a list of all entry points, of a binary.
Every entry point will be put into a single line, and we will use a pipe to read it.
At the end an empty line is appended, which we use as the indication to stop reading.
Boost.process provides the pipestream ([classref boost::process::v1::ipstream ipstream],
[classref boost::process::v1::opstream opstream], [classref boost::process::v1::pstream pstream]) to
wrap around the [classref boost::process::v1::pipe pipe] and provide an implementation of the
Boost.process provides the pipestream ([classref boost::process::ipstream ipstream],
[classref boost::process::opstream opstream], [classref boost::process::pstream pstream]) to
wrap around the [classref boost::process::pipe pipe] and provide an implementation of the
[@http://en.cppreference.com/w/cpp/io/basic_istream std::istream],
[@http://en.cppreference.com/w/cpp/io/basic_ostream std::ostream] and
[@http://en.cppreference.com/w/cpp/io/basic_iostream std::iostream] interface.
@@ -217,7 +217,8 @@ std::vector<std::string> read_outline(std::string & file)
What this does is redirect the `stdout` of the process into a pipe and we read this
synchronously.
[note You can do the same thing with [globalref boost::process::v1::std_err std_err].]
[warning The pipe will cause a deadlock if you try to read after nm exited]
[note You can do the same thing with [globalref boost::process::std_err std_err]]
Now we get the name from `nm` and we might want to demangle it, so we use input and output.
`nm` has a demangle option, but for the sake of the example, we'll use
@@ -246,7 +247,7 @@ std::vector<std::string> read_demangled_outline(const std::string & file)
std::vector<std::string> outline;
//we just use the same pipe, so the output of nm is directly passed as input to c++filt
//we just use the same pipe, so the
bp::child nm(bp::search_path("nm"), file, bp::std_out > p);
bp::child filt(bp::search_path("c++filt"), bp::std_in < p, bp::std_out > is);
@@ -267,10 +268,10 @@ This forwards the data from `nm` to `c++filt` without your process needing to do
Boost.process allows the usage of boost.asio to implement asynchronous I/O.
If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] (which we highly recommend),
you can use [classref boost::process::v1::async_pipe async_pipe] which is implemented
as an I/O-Object and can be used like [classref boost::process::v1::pipe pipe] as shown above.
you can use [classref boost::process::async_pipe async_pipe] which is implemented
as an I/O-Object and can be used like [classref boost::process::pipe pipe] as shown above.
Now we get back to our compiling example. For `nm` we might analyze the output line by line,
Now we get back to our compiling example. `nm` we might analyze it line by line,
but the compiler output will just be put into one large buffer.
With [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] this is what it looks like.
@@ -290,7 +291,7 @@ ios.run();
int result = c.exit_code();
```
To make it easier, boost.process provides a simpler interface for that, so that the buffer can be passed directly,
To make it easier, boost.process provides simpler interface for that, so that the buffer can be passed directly,
provided we also pass a reference to an io_service.
```
@@ -304,7 +305,7 @@ int result = c.exit_code();
```
[note Passing an instance of io_service to the launching function automatically cause it to wait asynchronously for the exit, so no call of
[memberref boost::process::v1::child::wait wait] is needed.]
[memberref boost::process::child::wait wait] is needed]
To make it even easier, you can use [@http://en.cppreference.com/w/cpp/thread/future std::future] for asynchronous operations
(you will still need to pass a reference to a io_service) to the launching function, unless you use bp::system or bp::async_system.
@@ -331,7 +332,7 @@ auto err = data.get();
[endsect]
[section:group Groups]
When launching several processes, they can be grouped together.
When launching several processes, processes can be grouped together.
This will also apply for a child process, that launches other processes,
if they do not modify the group membership. E.g. if you call `make` which
launches other processes and call terminate on it,
@@ -342,13 +343,13 @@ The two main reasons to use groups are:
# Being able to terminate child processes of the child process
# Grouping several processes into one, just so they can be terminated at once
If we have a program like `make`, which does launch its own child processes,
If we have program like `make`, which does launch its own child processes,
a call of child_terminate might not suffice. I.e. if we have a makefile launching `gcc`
and use the following code, the `gcc` process will still run afterwards:
```
bp::child c("make");
if (!c.child_wait_for(std::chrono::seconds(10))) //give it 10 seconds
if (!c.child_wait_for(std::chrono::seconds(10)) //give it 10 seconds
c.child_terminate(); //then terminate
```
@@ -357,14 +358,14 @@ So in order to also terminate `gcc` we can use a group.
```
bp::group g;
bp::child c("make", g);
if (!g.group_wait_for(std::chrono::seconds(10)))
if (!g.group_wait_for(std::chrono::seconds(10))
g.group_terminate();
c.child_wait(); //to avoid a zombie process & get the exit code
```
Now given the example, we still call child_wait to avoid a zombie process.
An easier solution for that might be to use [funcref boost::process::v1::spawn spawn].
An easier solution for that might be to use [funcref boost::process::spawn spawn].
To put two processes into one group, the following code suffices. Spawn already
@@ -412,14 +413,14 @@ bp::system("stuff", env_);
```
A more convenient way to modify the environment for the child is the
[globalref boost::process::v1::env env] property, which can be used in the example as following:
[globalref boost::process::env env] property, which the example as following:
```
bp::system("stuff", bp::env["VALUE_1"]="foo", bp::env["VALUE_2"]+={"bar1", "bar2"});
```
Please see the [headerref boost/process/environment.hpp reference] for more information.
Please see to the [headerref boost/process/environment.hpp reference] for more information.
[endsect]
[endsect]

View File

@@ -1,11 +0,0 @@
[section:v1 Process V1]
[include v1/introduction.qbk]
[include v1/concepts.qbk]
[include v1/tutorial.qbk]
[include v1/design.qbk]
[include v1/extend.qbk]
[include v1/faq.qbk]
[xinclude reference_v2.xml]
[endsect]

View File

@@ -1,60 +0,0 @@
<?xml version="1.0" standalone="yes"?>
<programlisting>
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_setup">on_setup</methodname>(*this);
if (<methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>())
{
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
return <classname alt="boost::process::v1::child">child</classname>();
}
pid = <ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html">fork()</ulink>
<methodname alt="boost::process::v1::extend::handler::on_setup">on_setup</methodname>(*this);
if (pid == -1) //fork error
{
<methodname alt="boost::process::v1::extend::posix_executor::set_error">set_error</methodname>(<functionname alt="boost::process::v1::extend::get_last_error">get_last_error</functionname>());
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_fork_error">on_fork_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
return <classname alt="boost::process::v1::child">child</classname>()
}
else if (pid == 0) //child process
{
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_exec_setup">on_exec_setup</methodname>(*this);
<ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html">execve</ulink>(exe, cmd_line, env);
auto ec = <functionname alt="boost::process::v1::extend::get_last_error">get_last_error</functionname>();
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_exec_error">on_exec_error</methodname>(*this);
<emphasis>unspecified();</emphasis>//here the error is sent to the father process internally
<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::v1::child">child</classname>(); //for C++ compliance
}
<classname alt="boost::process::v1::child">child</classname> c(pid, exit_code);
<emphasis>unspecified();</emphasis>//here, we read the error from the child process
if (<methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>())
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
else
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_success</methodname>(*this);
//now we check again, because an on_success handler might've errored.
if (<methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>())
{
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
return <classname alt="boost::process::v1::child">child</classname>();
}
else
return c;
</programlisting>

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" standalone="yes"?>
<programlisting>
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_setup">on_setup</methodname>(*this);
if (<methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>())
{
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>());
return <classname alt="boost::process::v1::child">child</classname>();
}
int err_code = <ulink url="https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425.aspx">CreateProcess</ulink>(
exe,
cmd_line,
proc_attrs,
thread_attrs,
creation_flags,
env,
work_dir,
startup_info,
proc_info);
<classname alt="boost::process::v1::child">child</classname> c(proc_info, exit_code);
if (<methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>())
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>());
else
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_success</methodname>(*this);
//now we check again, because an on_success handler might've errored.
if (<methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>())
{
for (auto &amp; s : seq)
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>());
return <classname alt="boost::process::v1::child">child</classname>();
}
else
return c;
</programlisting>

View File

@@ -1,11 +0,0 @@
[section:v2 Process V2]
[include v2/introduction.qbk]
[include v2/quickstart.qbk]
[include v2/launcher.qbk]
[include v2/start_dir.qbk]
[include v2/stdio.qbk]
[include v2/env.qbk]
[xinclude reference_v2.xml]
[endsect]

View File

@@ -1,48 +0,0 @@
[section:env Environment]
The `environment` namespace provides all sorts of facilities to query and manipulate the environment of the current process.
The api should be straight forward, but one oddity that needs to be pointed out is, that environment names
are not case sensitive on windows. The key_traits class implements the proper traits depending on the current system.
Additionally, environment can be lists separated by `:` or `;`; `environment::value` and
`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,
as to have the right value comparisons.
To note is the `find_executable` functions, which searches in an environment for an executable.
```
// search in the current environment
auto exe = environment::find_executable("g++");
std::unordered_map<environment::key, environment::value> my_env =
{
{"SECRET", "THIS_IS_A_TEST"},
{"PATH", {"/bin", "/usr/bin"}}
};
auto other_exe = environment::find_executable("g++", my_env);
```
[section:process_env Subprocess environment]
The subprocess environment assignment follows the same constraints:
```
asio::io_context ctx;
std::unordered_map<environment::key, environment::value> my_env =
{
{"SECRET", "THIS_IS_A_TEST"},
{"PATH", {"/bin", "/usr/bin"}}
};
auto exe = find_executable("g++");
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env));
```
[endsect]
[endsect]

View File

@@ -1,94 +0,0 @@
[section:introduction Introduction]
Boost.process V2 is an redesign of boost.process, based on previous
design mistakes & improved system APIs.
The major changes are
* Simplified interface
* Reliance on pidfd_open on linux
* Full asio integration
* Removed unreliable functionality
* UTF8 Support
* separate compilation
* fd safe by default
[section:simplified Simplified Interface]
In process v1 one can define partial settings in the constructor of the process,
which has lead to a small DSL.
child c{exe="test", args+="--help", std_in < null(), env["FOO"] += "BAR"};
While this looks fancy at first, it really does not scale well with more parameters.
For process v2, the interfaces is simple:
extern std::unordered_map<std::string, std::string> my_env;
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.
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.
[endsect]
[section:pidfd_open pidfd_open]
Since process v1 came out, linux has moved along and added pidfd_open which allows users to get a
file descriptor for a process. This is much more reliable since it is not as easy to miss as a `SIGCHLD`.
FreeBSD has a similar feature with `pdfork` which is also supported, while windows has provided `HANDLE`s
for processes all along.
Unless the OS doesn't support it, process v2 will use file descriptors and handles to implement waiting
for processes.
[endsect]
[section:asio Full asio integration]
Process v1 aimed to make asio optional, but synchronous IO with subprocesses usually means one is begging
for deadlocks.
Since asio added pipes in boost 1.78, boost process V2 is fully asio based and uses it's pipes and
file-handles for the subprocess.
[endsect]
[section:unreliable Unreliable functionality]
Certain parts of boost.process were not as reliable as they should've been.
This concerns especially the `wait_for` and `wait_until` functions on the process.
The latter are easy to do on windows, but posix does not provide an API for this.
Thus the wait_for used signals or fork, which was all but safe.
Since process v2 is based on asio and thus supports cancellation,
a wait_for can not safely be implemented with an async_wait + timeout.
[endsect]
[section:utf8 UTF-8]
["UTF-8 or GTFO]--Vinnie Falco
Instead of using ascii-APIs on windows, process V2 just assumes UTF-8 everywhere.
[endsect]
[section:src Separate compilation]
Boost.process v2 supports separate compilation similar to other boost libraries.
It can be achieved by defining `BOOST_PROCESS_V2_SEPARATE_COMPILATION` and including
`<process/v2/src.hpp>` in a single compile unit.
[endsect]
[section:limit_fd Fd safe by default]
While not a problem on windows (since HANDLEs get manually enabled for inheritance),
posix systems create a problem with inheriting file handles by default.
Process V2 will automatically close all non-whitelisted descriptors,
without needing any option to enable it.
[endsect]
[endsect]

View File

@@ -1,128 +0,0 @@
[section:launchers Launcher]
The process creation is done by a process_launcher.
The constructor of `process` will use the default_launcher, which varies by system.
There are additional launcher available on most systems.
[table:launchers Launcher overview
[[Name] [Summary] [Default on] [Available on]]
[[`windows::default_launcher`] [Launcher using `CreateProcessW`] [windows] [windows]]
[[`windows::as_user_launcher`] [Launcher using `CreateProcessAsUserW`] [] [windows]]
[[`windows::with_logon_launcher`] [Launcher using `CreateProcessWithLogonW`] [] [windows]]
[[`windows::with_token_launcher`] [Launcher using `CreateProcessWithTokenW`] [] [windows]]
[[`posix::default_launcher`] [Launcher using fork & an error pipe] [most of posix] [posix]]
[[`posix::fork_and_forget`] [Launcher using fork without error pipe] [] [posix]]
[[`posix::pdfork_launcher`] [Launcher using pdfork with an error pipe] [FreeBSD] [FreeBSD]]
[[`posix::vfork_launcher`] [Launcher using vfork] [] [posix]]
]
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;
auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {});
```
The launcher will call certain functions on the initializer if they're present, as documented below.
The initializer are used to modify the process behaviour.
[section:linux Linux Launchers]
The default and pdfork launchers on linux open an internal pipe to communicate errors that occur after forking back to the parent process.
This can be prevented by using the `fork_and_forget_launcher`.
Alternatively, the `vfork_launcher` can report errors directly back to the parent process.
Thus some calls to the initializers occur after forking from the child process.
```
struct custom_initializer
{
// functions called from the parent process:
// called before a call to fork. A returned error will cancel the launch.
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
template<typename Launcher>
void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
const error_code & ec);
// called after successful process creation
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.
template<typename Launcher>
void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
const error_code & ec);
// called before a call to execve. A returned error will cancel the launch. Called from the child process.
template<typename Launcher>
error_code on_exec_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
// called after a failed call to execve from the child process.
template<typename Launcher>
void on_exec_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
};
```
The call sequence on success:
'''
<imagedata fileref="boost_process/posix_success.svg"/>
'''
The call sequence when fork fails:
'''
<imagedata fileref="boost_process/posix_fork_err.svg"/>
'''
The call sequence when exec fails:
'''
<imagedata fileref="boost_process/posix_exec_err.svg"/>
'''
The launcher will close all non-whitelisted file descriptors after `on_exec_setup`.
[endsect]
[section:windows Windows Launchers]
Windows launchers are pretty straight forward, they will call the following functions on the initializer if present.
```
struct custom_initializer
{
// called before a call to CreateProcess. A returned error will cancel the launch.
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
template<typename Launcher>
void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
const error_code & ec);
// called after successful process creation
template<typename Launcher>
void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
};
```
[note All the additional launchers for windows inherit `default_launcher`]
The call sequence is as follows:
'''
<imagedata fileref="boost_process/windows_exec.svg"/>
'''
[endsect]
[endsect]

View File

@@ -1,123 +0,0 @@
[section:quickstart Quickstart]
A process needs four things to be launched:
* an asio execution_context / executor
* a path to an executable
* a list of arguments
* a variadic set of initializers
```
// process(asio::any_io_executor, filesystem::path, range<string> args, AdditionalInitializers...)
asio::io_context ctx;
process proc(ctx, "/usr/bin/cp", {"source.txt", "target.txt"});
```
The started process can then be awaited or terminated.
[section:lifetime Lifetime]
If the process handle goes out of scope, it will terminate the subprocess.
You can prevent this, by calling `proc.detach()`; do however note that this
can lead to zombie processes.
A process that completed will deliver an exit-code,
which can be obtained by calling `.exit_code` on the exited process and which is
also returned from `.wait()`.
```
process proc("/bin/ls", {});
assert(proc.wait() == 0);
```
The normal exit-code is what the subprocess returned from `main`;
posix will however add additional information about the process.
This is called the `native_exit_code`.
The `.running()` function can be used to detect if the process is still active.
[endsect]
[section:signal Signalling the subprocess]
The parent process can signal the subprocess demanding certain actions.
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
This is the only reliable & portable way to end a subprocess.
```
process proc("/bin/totally-not-a-virus", {});
proc.terminate();
```
`.request_exit` will ask the subprocess to shutdown (`SIGTERM` on posix),
which the subprocess might ignore.
```
process proc("/bin/bash", {});
proc.request_exit();
proc.wait();
```
`.interrupt` will send an SIGINT to the subprocess, which a subprocess might
interpret as a signal to shutdown.
[warning interrupt requires the initializer `windows::create_new_process_group` to be set]
```
process proc("/usr/bin/addr2line", {});
proc.request_exit();
proc.wait();
```
[endsect]
[section:execute Execute functions]
Process v2 provides `execute` and `async_execute` functions that can be used for managed executions.
```
assert(execute(process("/bin/ls", {}) == 0));
```
The async version supports cancellation and will forward cancellation types as follows:
- asio::cancellation_type::total -> interrupt
- asio::cancellation_type::partial -> request_exit
- asio::cancellation_type::terminal -> terminate
```
asio::io_context ctx;
asio::steady_timer timeout{ctx, std::chrono::seconds(10)};
asio::cancellation_signal sig;
async_execute(process("/usr/bin/g++", {"hello_world.cpp"}),
asio::bind_cancellation_slot(sig.slot(),
[&](error_code ec, int exit_code)
{
timeout.cancel(); // we're done earlier
}));
timeout.async_wait(
[&](error_code ec)
{
if (ec) // we were cancelled, do nothing
return ;
sig.emit(asio::cancellation_type::partial);
// request exit first, but terminate after another 10 sec
timeout.expires_after(std::chrono::seconds(10));
timeout.async_wait(
[&](error_code ec)
{
if (!ec)
sig.emit(asio::cancellation_type::terminal);
});
});
```
[endsect]
[endsect]

View File

@@ -1,16 +0,0 @@
[section:start_dir process_start_dir]
The easier initializer to use is `process_start_dir`:
```
asio::io_context ctx;
process ls(ctx, "/ls", {}, process_start_dir("/home"));
ls.wait();
```
This will run `ls` in the folder `/home` instead of the current folder.
[warning If your path is relative, it may fail on posix, because the directory is changed before a call to execve.]
[endsect]

View File

@@ -1,89 +0,0 @@
[section:stdio stdio]
When using io with a subprocess, all three standard streams (stdin, stdout, stderr) get set for the child-process.
The default setting is to inherit the parent process.
This feature meant to be flexible, which is why there is little checking on the arguments assigned to one of those streams.
[section:pipe Pipe]
asio pipes can be used for io. When using in process_stdio they will get
automatically connected and the other side will get assigned to the child process:
```
asio::io_context ctx;
asio::readable_pipe rp{ctx};
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }});
std::string output;
system::error_code ec;
rp.read(asio::dynamic_buffer(output), ec);
assert(ec == asio::eof);
proc.wait();
```
readable pipes can be assigned to `out` an `err`, while writable_pipes can be assigned to `in`.
[endsect]
[section:file `FILE*`]
`FILE*` can also be used for either side; this allows the `stdin`, `stderr`, `stdout` macros to be used:
```
asio::io_context ctx;
// forward both stderr & stdout to stdout of the parent process
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, stdout, stdout});
proc.wait();
```
[endsect]
[section:null `nullptr`]
`nullptr` may be used to set a given stream to be opened on the null-device (`/dev/null` on posix, `NUL` on windows).
This is used to ignore output or give only EOF as input.
```
asio::io_context ctx;
// ignore stderr
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, {}, nullptr});
proc.wait();
```
[endsect]
[section:native_handle `native_handle`]
A native handle can be used as well, which means an `int` on posix or a `HANDLE` on windows.
Furthermore, any object that has a `native_handle` returning that native handle type is valid, too.
```
asio::io_context ctx;
// ignore stderr
asio::ip::tcp::socket sock{ctx};
connect_my_socket(sock);
process proc(ctx, "~/not-a-virus", {}, process_stdio{sock, sock, nullptr});
proc.wait();
```
[endsect]
[section:popen popen]
Additionally, process v2 provides a `popen` class.
It starts a process and connects pipes for stdin and stdout, so that the popen object can be used as a stream.
```
popen proc(executor, "/usr/bin/addr2line, {argv[0]});
asio::write(proc, asio::buffer("main\n"));
std::string line;
asio::read_until(proc, asio::dynamic_buffer(line), '\n');
```
[endsect]
[endsect]

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" standalone="yes"?>
<programlisting>
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_setup">on_setup</methodname>(*this);
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
{
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::windows_executor::error">error</methodname>());
return <classname alt="boost::process::child">child</classname>();
}
int err_code = <ulink url="https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425.aspx">CreateProcess</ulink>(
exe,
cmd_line,
proc_attrs,
thread_attrs,
creation_flags,
env,
work_dir,
startup_info,
proc_info);
<classname alt="boost::process::child">child</classname> c(proc_info, exit_code);
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::windows_executor::error">error</methodname>());
else
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
//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 &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::windows_executor::error">error</methodname>());
return <classname alt="boost::process::child">child</classname>();
}
else
return c;
</programlisting>

View File

@@ -10,9 +10,6 @@
//[intro
#include <boost/process.hpp>
#include <string>
#include <iostream>
using namespace boost::process;
int main()

View File

@@ -22,7 +22,7 @@ int main()
bp::std_in < bp::null //null in
);
boost::process::v1::filesystem::path p = "input.txt";
boost::filesystem::path p = "input.txt";
bp::system(
"test.exe",

View File

@@ -8,8 +8,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/process.hpp>
#include <boost/process/v1/posix.hpp>
#include <boost/process/v1/extend.hpp>
#include <boost/process/posix.hpp>
#include <boost/process/extend.hpp>
#include <iostream>
#include <fstream>
#include <unistd.h>

View File

@@ -8,7 +8,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/process.hpp>
#include <boost/process/v1/filesystem.hpp>
#include <boost/filesystem.hpp>
namespace bp = boost::process;
@@ -19,9 +19,9 @@ int main()
bp::start_dir="../foo"
);
boost::process::v1::filesystem::path exe = "test.exe";
boost::filesystem::path exe = "test.exe";
bp::system(
boost::process::v1::filesystem::absolute(exe),
boost::filesystem::absolute(exe),
bp::start_dir="../foo"
);
}

View File

@@ -1,17 +0,0 @@
# Copyright (c) 2022 Klemens 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)
project : requirements
<include>../../..
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
;
import testing ;
alias filesystem : /boost//filesystem : <link>static ;
exe intro : intro.cpp filesystem ;
exe intro_popen : intro_popen.cpp filesystem ;

View File

@@ -1,39 +0,0 @@
// Copyright (c) 2022 Klemens 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)
//[intro
#include <boost/process/v2.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/readable_pipe.hpp>
#include <boost/system/error_code.hpp>
#include <string>
#include <iostream>
namespace proc = boost::process::v2;
namespace asio = boost::asio;
int main()
{
asio::io_context ctx;
asio::readable_pipe p{ctx};
const auto exe = proc::environment::find_executable("gcc");
proc::process c{ctx, exe, {"--version"}, proc::process_stdio{nullptr, p}};
std::string line;
boost::system::error_code ec;
auto sz = asio::read(p, asio::dynamic_buffer(line), ec);
assert(ec == asio::error::eof);
std::cout << "Gcc version: '" << line << "'" << std::endl;
c.wait();
}
//]

View File

@@ -1,36 +0,0 @@
// Copyright (c) 2022Klemens 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)
//[intro
#include <boost/process/v2.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/readable_pipe.hpp>
#include <boost/system/error_code.hpp>
#include <string>
#include <iostream>
namespace proc = boost::process::v2;
namespace asio = boost::asio;
int main()
{
asio::io_context ctx;
const auto exe = proc::environment::find_executable("gcc");
proc::popen c{ctx, exe, {"--version"}};
std::string line;
boost::system::error_code ec;
auto sz = asio::read(c, asio::dynamic_buffer(line), ec);
assert(ec == asio::error::eof);
std::cout << "Gcc version: '" << line << "'" << std::endl;
c.wait();
}
//]

View File

@@ -8,8 +8,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/process.hpp>
#include <boost/process/v1/extend.hpp>
#include <boost/process/v1/windows.hpp>
#include <boost/process/windows.hpp>
#include <iostream>
#include <windows.h>
@@ -23,9 +22,9 @@ int main()
bp::system("test.exe",
bp::extend::on_setup([](auto &e)
bp::on_setup([](auto &e)
{ e.startup_info.dwFlags = STARTF_RUNFULLSCREEN; }),
bp::extend::on_error([](auto&, const std::error_code & ec)
bp::on_error([](auto&, const std::error_code & ec)
{ std::cerr << ec.message() << std::endl; })
);
}

View File

@@ -19,16 +19,23 @@
* boost.process header files.
*/
#if !defined(BOOST_PROCESS_VERSION)
#define BOOST_PROCESS_VERSION 1
#endif
#if BOOST_PROCESS_VERSION == 1
#include <boost/process/v1.hpp>
#elif BOOST_PROCESS_VERSION == 2
#include <boost/process/v2.hpp>
#else
#error "Unknown boost process version"
#endif
#include <boost/process/args.hpp>
#include <boost/process/async.hpp>
#include <boost/process/async_system.hpp>
#include <boost/process/group.hpp>
#include <boost/process/child.hpp>
#include <boost/process/cmd.hpp>
#include <boost/process/env.hpp>
#include <boost/process/environment.hpp>
#include <boost/process/error.hpp>
#include <boost/process/exe.hpp>
#include <boost/process/group.hpp>
#include <boost/process/io.hpp>
#include <boost/process/pipe.hpp>
#include <boost/process/shell.hpp>
#include <boost/process/search_path.hpp>
#include <boost/process/spawn.hpp>
#include <boost/process/system.hpp>
#include <boost/process/start_dir.hpp>
#endif

View File

@@ -1,9 +1,279 @@
// Copyright (c) 2024 Klemens D. Morgenstern
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 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_ARGS_HPP
#define BOOST_PROCESS_ARGS_HPP
#include <boost/config/header_deprecated.hpp>
BOOST_HEADER_DEPRECATED("<boost/process/v1/args.hpp>")
#include <boost/process/v1/args.hpp>
/** \file boost/process/args.hpp
*
* This header provides the \xmlonly <globalname alt="boost::process::args">args</globalname>\endxmlonly property. It also provides the
* alternative name \xmlonly <globalname alt="boost::process::argv">argv</globalname>\endxmlonly .
*
*
\xmlonly
<programlisting>
namespace boost {
namespace process {
<emphasis>unspecified</emphasis> <globalname alt="boost::process::args">args</globalname>;
<emphasis>unspecified</emphasis> <globalname alt="boost::process::argv">argv</globalname>;
}
}
</programlisting>
\endxmlonly
*/
#include <boost/process/detail/basic_cmd.hpp>
#include <iterator>
namespace boost { namespace process { namespace detail {
struct args_
{
template<typename T>
using remove_reference_t = typename std::remove_reference<T>::type;
template<typename T>
using value_type = typename remove_reference_t<T>::value_type;
template<typename T>
using vvalue_type = value_type<value_type<T>>;
template <class Range>
arg_setter_<vvalue_type<Range>, true> operator()(Range &&range) const
{
return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range));
}
template <class Range>
arg_setter_<vvalue_type<Range>, true> operator+=(Range &&range) const
{
return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range));
}
template <class Range>
arg_setter_<vvalue_type<Range>, false> operator= (Range &&range) const
{
return arg_setter_<vvalue_type<Range>, false>(std::forward<Range>(range));
}
template<typename Char>
arg_setter_<Char, true> operator()(std::basic_string<Char> && str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, true> operator+=(std::basic_string<Char> && str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, false> operator= (std::basic_string<Char> && str) const
{
return arg_setter_<Char, false>(str);
}
template<typename Char>
arg_setter_<Char, true> operator()(const std::basic_string<Char> & str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, true> operator+=(const std::basic_string<Char> & str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, false> operator= (const std::basic_string<Char> & str) const
{
return arg_setter_<Char, false>(str);
}
template<typename Char>
arg_setter_<Char, true> operator()(std::basic_string<Char> & str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, true> operator+=(std::basic_string<Char> & str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, false> operator= (std::basic_string<Char> & str) const
{
return arg_setter_<Char, false>(str);
}
template<typename Char>
arg_setter_<Char, true> operator()(const Char* str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, true> operator+=(const Char* str) const
{
return arg_setter_<Char, true> (str);
}
template<typename Char>
arg_setter_<Char, false> operator= (const Char* str) const
{
return arg_setter_<Char, false>(str);
}
// template<typename Char, std::size_t Size>
// arg_setter_<Char, true> operator()(const Char (&str) [Size]) const
// {
// return arg_setter_<Char, true> (str);
// }
// template<typename Char, std::size_t Size>
// arg_setter_<Char, true> operator+=(const Char (&str) [Size]) const
// {
// return arg_setter_<Char, true> (str);
// }
// template<typename Char, std::size_t Size>
// arg_setter_<Char, false> operator= (const Char (&str) [Size]) const
// {
// return arg_setter_<Char, false>(str);
// }
arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const
{
return arg_setter_<char>(range.begin(), range.end());
}
arg_setter_<char, true> operator+=(std::initializer_list<const char*> &&range) const
{
return arg_setter_<char, true>(range.begin(), range.end());
}
arg_setter_<char, false> operator= (std::initializer_list<const char*> &&range) const
{
return arg_setter_<char, true>(range.begin(), range.end());
}
arg_setter_<char, true> operator()(std::initializer_list<std::string> &&range) const
{
return arg_setter_<char>(range.begin(), range.end());
}
arg_setter_<char, true> operator+=(std::initializer_list<std::string> &&range) const
{
return arg_setter_<char, true>(range.begin(), range.end());
}
arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const
{
return arg_setter_<char, true>(range.begin(), range.end());
}
arg_setter_<wchar_t, true> operator()(std::initializer_list<const wchar_t*> &&range) const
{
return arg_setter_<wchar_t>(range.begin(), range.end());
}
arg_setter_<wchar_t, true> operator+=(std::initializer_list<const wchar_t*> &&range) const
{
return arg_setter_<wchar_t, true>(range.begin(), range.end());
}
arg_setter_<wchar_t, false> operator= (std::initializer_list<const wchar_t*> &&range) const
{
return arg_setter_<wchar_t, true>(range.begin(), range.end());
}
arg_setter_<wchar_t, true> operator()(std::initializer_list<std::wstring> &&range) const
{
return arg_setter_<wchar_t>(range.begin(), range.end());
}
arg_setter_<wchar_t, true> operator+=(std::initializer_list<std::wstring> &&range) const
{
return arg_setter_<wchar_t, true>(range.begin(), range.end());
}
arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const
{
return arg_setter_<wchar_t, true>(range.begin(), range.end());
}
};
}
/**
The `args` property allows to explicitly set arguments for the execution. The
name of the executable will always be the first element in the arg-vector.
\section args_details Details
\subsection args_operations Operations
\subsubsection args_set_var Setting values
To set a the argument vector the following syntax can be used.
\code{.cpp}
args = value;
args(value);
\endcode
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
\code{.cpp}
args = {value1, value2};
args({value1, value2});
\endcode
Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`.
\paragraph args_set_var_value value
- `std::basic_string<char_type>`
- `const char_type * `
- `std::initializer_list<const char_type *>`
- `std::vector<std::basic_string<char_type>>`
Additionally any range of `std::basic_string<char_type>` can be passed.
\subsubsection args_append_var Appending values
To append a the argument vector the following syntax can be used.
\code{.cpp}
args += value;
\endcode
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
\code{.cpp}
args += {value1, value2};
\endcode
Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`.
\paragraph args_append_var_value value
- `std::basic_string<char_type>`
- `const char_type * `
- `std::initializer_list<const char_type *>`
- `std::vector<std::basic_string<char_type>>`
Additionally any range of `std::basic_string<char_type>` can be passed.
\subsection args_example Example
The overload form is used when more than one string is passed, from the second one forward.
I.e. the following expressions have the same results:
\code{.cpp}
spawn("gcc", "--version");
spawn("gcc", args ="--version");
spawn("gcc", args+="--version");
spawn("gcc", args ={"--version"});
spawn("gcc", args+={"--version"});
\endcode
\note A string will be parsed and set in quotes if it has none and contains spaces.
*/
constexpr boost::process::detail::args_ args{};
///Alias for \xmlonly <globalname alt="boost::process::args">args</globalname> \endxmlonly .
constexpr boost::process::detail::args_ argv{};
}}
#endif

View File

@@ -1,9 +1,132 @@
// Copyright (c) 2024 Klemens D. Morgenstern
// Copyright (c) 2016 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)
/** \file boost/process/async.hpp
#include <boost/config/header_deprecated.hpp>
BOOST_HEADER_DEPRECATED("<boost/process/v1/async.hpp>")
#include <boost/process/v1/async.hpp>
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.
It also pulls the [boost::asio::buffer](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html)
into the boost::process namespace for convenience.
\xmlonly
<programlisting>
namespace boost {
namespace process {
<emphasis>unspecified</emphasis> <ulink url="http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/buffer.html">buffer</ulink>;
<emphasis>unspecified</emphasis> <globalname alt="boost::process::on_exit">on_exit</globalname>;
}
}
</programlisting>
\endxmlonly
*/
#ifndef BOOST_PROCESS_ASYNC_HPP_
#define BOOST_PROCESS_ASYNC_HPP_
#include <boost/process/detail/traits.hpp>
#include <boost/process/detail/on_exit.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/buffer.hpp>
#include <type_traits>
#include <boost/fusion/iterator/deref.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/io_context_ref.hpp>
#include <boost/process/detail/posix/async_in.hpp>
#include <boost/process/detail/posix/async_out.hpp>
#include <boost/process/detail/posix/on_exit.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/io_context_ref.hpp>
#include <boost/process/detail/windows/async_in.hpp>
#include <boost/process/detail/windows/async_out.hpp>
#include <boost/process/detail/windows/on_exit.hpp>
#endif
namespace boost { namespace process { namespace detail {
struct async_tag;
template<typename T>
struct is_io_context : std::false_type {};
template<>
struct is_io_context<api::io_context_ref> : std::true_type {};
template<typename Tuple>
inline asio::io_context& get_io_context(const Tuple & tup)
{
auto& ref = *boost::fusion::find_if<is_io_context<boost::mpl::_>>(tup);
return ref.get();
}
struct async_builder
{
boost::asio::io_context * ios;
void operator()(boost::asio::io_context & ios_) {this->ios = &ios_;};
typedef api::io_context_ref result_type;
api::io_context_ref get_initializer() {return api::io_context_ref (*ios);};
};
template<>
struct initializer_builder<async_tag>
{
typedef async_builder type;
};
}
using ::boost::asio::buffer;
#if defined(BOOST_PROCESS_DOXYGEN)
/** When an io_context is passed, the on_exit property can be used, to be notified
when the child process exits.
The following syntax is valid
\code{.cpp}
on_exit=function;
on_exit(function);
\endcode
with `function` being a callable object with the signature `(int, const std::error_code&)` or an
`std::future<int>`.
\par Example
\code{.cpp}
io_context ios;
child c("ls", on_exit=[](int exit, const std::error_code& ec_in){});
std::future<int> exit_code;
chlid c2("ls", on_exit=exit_code);
\endcode
\note The handler is not invoked when the launch fails.
\warning When used \ref ignore_error it might get invoked on error.
\warning `on_exit` uses `boost::asio::signal_set` to listen for `SIGCHLD` on posix, and so has the
same restrictions as that class (do not register a handler for `SIGCHLD` except by using
`boost::asio::signal_set`).
*/
constexpr static ::boost::process::detail::on_exit_ on_exit{};
#endif
}}
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ASYNC_HPP_ */

View File

@@ -1,9 +1,215 @@
// Copyright (c) 2024 Klemens D. Morgenstern
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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/config/header_deprecated.hpp>
BOOST_HEADER_DEPRECATED("<boost/process/v1/async_pipe.hpp>")
#include <boost/process/v1/async_pipe.hpp>
#ifndef BOOST_PROCESS_ASYNC_PIPE_HPP
#define BOOST_PROCESS_ASYNC_PIPE_HPP
#include <boost/config.hpp>
#include <boost/process/detail/config.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/async_pipe.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/async_pipe.hpp>
#endif
namespace boost { namespace process {
#if defined(BOOST_PROCESS_DOXYGEN)
/** Class implementing and asnychronous I/O-Object for use with boost.asio.
* It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or
* boost::asio::posix::stream_descriptor.
*
* It can be used directly with boost::asio::async_read or async_write.
*
* \note The object is copyable, but that does invoke a handle duplicate.
*/
class async_pipe
{
public:
/** Typedef for the native handle representation.
* \note This is the handle on the system, not the boost.asio class.
*
*/
typedef platform_specific native_handle_type;
/** Typedef for the handle representation of boost.asio.
*
*/
typedef platform_specific handle_type;
/** Construct a new async_pipe, does automatically open the pipe.
* Initializes source and sink with the same io_context.
* @note Windows creates a named pipe here, where the name is automatically generated.
*/
inline async_pipe(boost::asio::io_context & ios);
/** Construct a new async_pipe, does automatically open the pipe.
* @note Windows creates a named pipe here, where the name is automatically generated.
*/
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink);
/** Construct a new async_pipe, does automatically open.
* Initializes source and sink with the same io_context.
*
* @note Windows restricts possible names.
*/
inline async_pipe(boost::asio::io_context & ios, const std::string & name);
/** Construct a new async_pipe, does automatically open.
*
* @note Windows restricts possible names.
*/
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink, const std::string & name);
/** Copy-Constructor of the async pipe.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
*
*/
async_pipe(const async_pipe& lhs);
/** Move-Constructor of the async pipe.
*/
async_pipe(async_pipe&& lhs);
/** Construct the async-pipe from a pipe.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p);
/** Construct the async-pipe from a pipe, with two different io_context objects.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
const basic_pipe<CharT, Traits> & p);
/** Assign a basic_pipe.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
/** Copy Assign a pipe.
* @note Duplicates the handles.
*/
async_pipe& operator=(const async_pipe& lhs);
/** Move assign a pipe */
async_pipe& operator=(async_pipe&& lhs);
/** Destructor. Closes the pipe handles. */
~async_pipe();
/** Explicit cast to basic_pipe. */
template<class CharT, class Traits = std::char_traits<CharT>>
inline explicit operator basic_pipe<CharT, Traits>() const;
/** Cancel the current asynchronous operations. */
void cancel();
/** Close the pipe handles. */
void close();
/** Close the pipe handles. While passing an error_code
*
*/
void close(std::error_code & ec);
/** Check if the pipes are open. */
bool is_open() const;
/** Async close, i.e. close after current operation is completed.
*
* \note There is no guarantee that this will indeed read the entire pipe-buffer
*/
void async_close();
/** Read some data from the handle.
* See the boost.asio documentation for more details.
*/
template<typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence & buffers);
/** Write some data to the handle.
* See the boost.asio documentation for more details.
*/
template<typename MutableBufferSequence>
std::size_t write_some(const MutableBufferSequence & buffers);
/** Get the native handle of the source. */
native_handle native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();}
/** Get the native handle of the sink. */
native_handle native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();}
/** Start an asynchronous read.
*
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html) for more details.
*/
template<typename MutableBufferSequence,
typename ReadHandler>
detail::dummy async_read_some(
const MutableBufferSequence & buffers,
ReadHandler &&handler);
/** Start an asynchronous write.
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html) for more details.
*/
template<typename ConstBufferSequence,
typename WriteHandler>
detail::dummy async_write_some(
const ConstBufferSequence & buffers,
WriteHandler && handler);
///Get the asio handle of the pipe sink.
const handle_type & sink () const &;
///Get the asio handle of the pipe source.
const handle_type & source() const &;
///Get the asio handle of the pipe sink. Qualified as rvalue
handle_type && sink () &&;
///Get the asio handle of the pipe source. Qualified as rvalue
handle_type && source() &&;
/// Move the source out of this class and change the io_context. Qualified as rvalue. \attention Will always move.
handle_type source(::boost::asio::io_context& ios) &&;
/// Move the sink out of this class and change the io_context. Qualified as rvalue. \attention Will always move
handle_type sink (::boost::asio::io_context& ios) &&;
/// Copy the source out of this class and change the io_context. \attention Will always copy.
handle_type source(::boost::asio::io_context& ios) const &;
/// Copy the sink out of this class and change the io_context. \attention Will always copy
handle_type sink (::boost::asio::io_context& ios) const &;
};
#else
using ::boost::process::detail::api::async_pipe;
#endif
}}
#endif

View File

@@ -1,9 +1,144 @@
// Copyright (c) 2024 Klemens D. Morgenstern
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 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)
/**
* \file boost/process/async_system.hpp
*
* Defines the asynchrounous version of the system function.
*/
#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP
#define BOOST_PROCESS_ASYNC_SYSTEM_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/async.hpp>
#include <boost/process/child.hpp>
#include <boost/process/detail/async_handler.hpp>
#include <boost/process/detail/execute_impl.hpp>
#include <type_traits>
#include <memory>
#include <boost/asio/async_result.hpp>
#include <boost/asio/post.hpp>
#include <boost/system/error_code.hpp>
#include <tuple>
#if defined(BOOST_POSIX_API)
#include <boost/process/posix.hpp>
#endif
namespace boost {
namespace process {
namespace detail
{
template<typename ExitHandler>
struct async_system_handler : ::boost::process::detail::api::async_handler
{
boost::asio::io_context & ios;
boost::asio::async_completion<
ExitHandler, void(boost::system::error_code, int)> init;
#if defined(BOOST_POSIX_API)
bool errored = false;
#endif
template<typename ExitHandler_>
async_system_handler(
boost::asio::io_context & ios,
ExitHandler_ && exit_handler) : ios(ios), init(exit_handler)
{
}
template<typename Exec>
void on_error(Exec&, const std::error_code & ec)
{
#if defined(BOOST_POSIX_API)
errored = true;
#endif
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);
});
}
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&)
{
#if defined(BOOST_POSIX_API)
if (errored)
return [](int , const std::error_code &){};
#endif
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);
};
}
};
template<typename ExitHandler>
struct is_error_handler<async_system_handler<ExitHandler>> : std::true_type {};
}
/** This function provides an asynchronous interface to process launching.
It uses the same properties and parameters as the other launching function,
but is similar to the asynchronous functions in [boost.asio](http://www.boost.org/doc/libs/release/doc/html/boost_asio.html)
It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine
the return value (from the second parameter, `exit_handler`).
\param ios A reference to an [io_context](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html)
\param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)`
\note This function does not allow custom error handling, since those are done through the `exit_handler`.
*/
#if defined(BOOST_PROCESS_DOXYGEN)
template<typename ExitHandler, typename ...Args>
inline boost::process::detail::dummy
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
#endif
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");
child(ios, std::forward<Args>(args)..., async_h ).detach();
return async_h.get_result();
}
}}
#endif
#include <boost/config/header_deprecated.hpp>
BOOST_HEADER_DEPRECATED("<boost/process/v1/async_system.hpp>")
#include <boost/process/v1/async_system.hpp>

View File

@@ -1,9 +1,154 @@
// Copyright (c) 2024 Klemens D. Morgenstern
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 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)
/**
* \file boost/process/child.hpp
*
* Defines a child process class.
*/
#ifndef BOOST_PROCESS_CHILD_HPP
#define BOOST_PROCESS_CHILD_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/child_decl.hpp>
#include <boost/process/detail/execute_impl.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/posix.hpp>
#endif
namespace boost {
///The main namespace of boost.process.
namespace process {
template<typename ...Args>
child::child(Args&&...args)
: child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {}
///Typedef for the type of an pid_t
typedef ::boost::process::detail::api::pid_t pid_t;
#if defined(BOOST_PROCESS_DOXYGEN)
/** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread),
* in that it has a join and detach function.
*
* @attention The destructor will call terminate on the process if not joined or detached without any warning.
*
*/
class child
{
/** Type definition for the native process handle. */
typedef platform_specific native_handle_t;
/** Construct the child from a pid.
*
* @attention There is no guarantee that this will work. The process need the right access rights, which are very platform specific.
*/
explicit child(pid_t & pid) : _child_handle(pid) {};
/** Move-Constructor.*/
child(child && lhs);
/** Construct a child from a property list and launch it
* The standard version is to create a subprocess, which will spawn the process.
*/
template<typename ...Args>
explicit child(Args&&...args);
/** Construct an empty child. */
child() = default;
/** Move assign. */
child& operator=(child && lhs);
/** Detach the child, i.e. let it run after this handle dies. */
void detach();
/** Join the child. This just calls wait, but that way the naming is similar to std::thread */
void join();
/** Check if the child is joinable. */
bool joinable();
/** Destructor.
* @attention Will call terminate (without warning) when the child was neither joined nor detached.
*/
~child();
/** Get the native handle for the child process. */
native_handle_t native_handle() const;
/** Get the exit_code. The return value is without any meaning if the child wasn't waited for or if it was terminated. */
int exit_code() const;
/** Get the Process Identifier. */
pid_t id() const;
/** Get the native, uninterpreted exit code. The return value is without any meaning if the child wasn't waited
* for or if it was terminated. */
int native_exit_code() const;
/** Check if the child process is running. */
bool running();
/** \overload void running() */
bool running(std::error_code & ec) noexcept;
/** Wait for the child process to exit. */
void wait();
/** \overload void wait() */
void wait(std::error_code & ec) noexcept;
/** Wait for the child process to exit for a period of time.
* \return True if child exited while waiting.
*/
template< class Rep, class Period >
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time);
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) */
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept;
/** Wait for the child process to exit until a point in time.
* \return True if child exited while waiting.*/
template< class Clock, class Duration >
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time );
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )*/
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept;
/** Check if this handle holds a child process.
* @note That does not mean, that the process is still running. It only means, that the handle does or did exist.
*/
bool valid() const;
/** Same as valid, for convenience. */
explicit operator bool() const;
/** Check if the the chlid process is in any process group. */
bool in_group() const;
/** \overload bool in_group() const */
bool in_group(std::error_code & ec) const noexcept;
/** Terminate the child process.
*
* This function will cause the child process to unconditionally and immediately exit.
* It is implement with [SIGKILL](http://pubs.opengroup.org/onlinepubs/009695399/functions/kill.html) on posix
* and [TerminateProcess](https://technet.microsoft.com/en-us/library/ms686714.aspx) on windows.
*
*/
void terminate();
/** \overload void terminate() */
void terminate(std::error_code & ec) noexcept;
};
#endif
}}
#endif
#include <boost/config/header_deprecated.hpp>
BOOST_HEADER_DEPRECATED("<boost/process/v1/child.hpp>")
#include <boost/process/v1/child.hpp>

View File

@@ -1,9 +1,122 @@
// Copyright (c) 2024 Klemens D. Morgenstern
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 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_DETAIL_CMD_LINE_HPP
#define BOOST_PROCESS_DETAIL_CMD_LINE_HPP
#include <boost/config/header_deprecated.hpp>
BOOST_HEADER_DEPRECATED("<boost/process/v1/cmd.hpp>")
#include <boost/process/v1/cmd.hpp>
#include <boost/winapi/config.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/cmd.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/cmd.hpp>
#endif
/** \file boost/process/cmd.hpp
*
* This header provides the \xmlonly <globalname alt="boost::process::cmd">cmd</globalname>\endxmlonly property.
*
\xmlonly
<programlisting>
namespace boost {
namespace process {
<emphasis>unspecified</emphasis> <globalname alt="boost::process::cmd">cmd</globalname>;
}
}
</programlisting>
\endxmlonly
*/
namespace boost { namespace process { namespace detail {
struct cmd_
{
constexpr cmd_() {}
template<typename Char>
inline api::cmd_setter_<Char> operator()(const Char *s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator= (const Char *s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator()(const std::basic_string<Char> &s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator= (const std::basic_string<Char> &s) const
{
return api::cmd_setter_<Char>(s);
}
};
template<> struct is_wchar_t<api::cmd_setter_<wchar_t>> : std::true_type {};
template<>
struct char_converter<char, api::cmd_setter_<wchar_t>>
{
static api::cmd_setter_<char> conv(const api::cmd_setter_<wchar_t> & in)
{
return { ::boost::process::detail::convert(in.str()) };
}
};
template<>
struct char_converter<wchar_t, api::cmd_setter_<char>>
{
static api::cmd_setter_<wchar_t> conv(const api::cmd_setter_<char> & in)
{
return { ::boost::process::detail::convert(in.str()) };
}
};
}
/** The cmd property allows to explicitly set commands for the execution.
The overload form applies when only one string is passed to a launching function.
The string will be internally parsed and split at spaces.
The following expressions are valid, with `value` being either a C-String or
a `std::basic_string` with `char` or `wchar_t`.
\code{.cpp}
cmd="value";
cmd(value);
\endcode
The property can only be used for assignments.
*/
constexpr static ::boost::process::detail::cmd_ cmd;
}}
#endif

View File

@@ -11,26 +11,26 @@
#include <type_traits>
#if defined(BOOST_POSIX_API)
#include <boost/process/v1/posix.hpp>
#include <boost/process/v1/detail/posix/async_handler.hpp>
#include <boost/process/v1/detail/posix/asio_fwd.hpp>
#include <boost/process/posix.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/process/detail/posix/asio_fwd.hpp>
#else
#include <boost/process/v1/detail/windows/async_handler.hpp>
#include <boost/process/v1/detail/windows/asio_fwd.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#endif
namespace boost {
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
namespace process {
namespace detail {
#if defined(BOOST_POSIX_API)
using ::boost::process::v1::detail::posix::is_async_handler;
using ::boost::process::v1::detail::posix::does_require_io_context;
using ::boost::process::detail::posix::is_async_handler;
using ::boost::process::detail::posix::does_require_io_context;
#else
using ::boost::process::v1::detail::windows::is_async_handler;
using ::boost::process::v1::detail::windows::does_require_io_context;
using ::boost::process::detail::windows::is_async_handler;
using ::boost::process::detail::windows::does_require_io_context;
#endif
template<typename ...Args>
@@ -112,7 +112,6 @@ boost::asio::io_context &get_io_context_var(First&, Args&...args)
}
}
}
}
#endif /* BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_ */

View File

@@ -7,26 +7,26 @@
#ifndef BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/v1/detail/handler_base.hpp>
#include <boost/process/v1/detail/traits/cmd_or_exe.hpp>
#include <boost/process/v1/detail/traits/wchar_t.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#if defined( BOOST_WINDOWS_API )
#include <boost/process/v1/detail/windows/basic_cmd.hpp>
#include <boost/process/v1/detail/windows/cmd.hpp>
#include <boost/process/detail/windows/basic_cmd.hpp>
#include <boost/process/detail/windows/cmd.hpp>
#elif defined( BOOST_POSIX_API )
#include <boost/process/v1/detail/posix/basic_cmd.hpp>
#include <boost/process/v1/detail/posix/cmd.hpp>
#include <boost/process/detail/posix/basic_cmd.hpp>
#include <boost/process/detail/posix/cmd.hpp>
#endif
#include <boost/process/v1/shell.hpp>
#include <boost/process/shell.hpp>
#include <iterator>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
namespace boost { namespace process { namespace detail {
template<typename Char>
struct exe_setter_
@@ -47,7 +47,7 @@ struct char_converter<char, exe_setter_<wchar_t>>
{
static exe_setter_<char> conv(const exe_setter_<wchar_t> & in)
{
return {::boost::process::v1::detail::convert(in.exe_)};
return {::boost::process::detail::convert(in.exe_)};
}
};
@@ -56,7 +56,7 @@ struct char_converter<wchar_t, exe_setter_<char>>
{
static exe_setter_<wchar_t> conv(const exe_setter_<char> & in)
{
return {::boost::process::v1::detail::convert(in.exe_)};
return {::boost::process::detail::convert(in.exe_)};
}
};
@@ -105,7 +105,7 @@ struct char_converter<char, arg_setter_<wchar_t, true>>
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::v1::detail::convert(ws);
return ::boost::process::detail::convert(ws);
});
return {vec};
}
@@ -120,7 +120,7 @@ struct char_converter<wchar_t, arg_setter_<char, true>>
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::v1::detail::convert(ws);
return ::boost::process::detail::convert(ws);
});
return {vec};
@@ -136,7 +136,7 @@ struct char_converter<char, arg_setter_<wchar_t, false>>
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::v1::detail::convert(ws);
return ::boost::process::detail::convert(ws);
});
return {vec}; }
};
@@ -150,7 +150,7 @@ struct char_converter<wchar_t, arg_setter_<char, false>>
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::v1::detail::convert(ws);
return ::boost::process::detail::convert(ws);
});
return {vec};
}
@@ -168,7 +168,7 @@ struct exe_builder
string_type exe;
std::vector<string_type> args;
void operator()(const boost::process::v1::filesystem::path & data)
void operator()(const boost::filesystem::path & data)
{
not_cmd = true;
if (exe.empty())
@@ -285,7 +285,7 @@ struct initializer_builder<cmd_or_exe_tag<wchar_t>>
typedef exe_builder<wchar_t> type;
};
}}}}
}}}

View File

@@ -17,7 +17,7 @@
#ifndef BOOST_PROCESS_CHILD_DECL_HPP
#define BOOST_PROCESS_CHILD_DECL_HPP
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#include <chrono>
#include <memory>
@@ -25,42 +25,42 @@
#include <atomic>
#if defined(BOOST_POSIX_API)
#include <boost/process/v1/detail/posix/child_handle.hpp>
#include <boost/process/v1/detail/posix/terminate.hpp>
#include <boost/process/v1/detail/posix/wait_for_exit.hpp>
#include <boost/process/v1/detail/posix/is_running.hpp>
#include <boost/process/detail/posix/child_handle.hpp>
#include <boost/process/detail/posix/terminate.hpp>
#include <boost/process/detail/posix/wait_for_exit.hpp>
#include <boost/process/detail/posix/is_running.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/v1/detail/windows/child_handle.hpp>
#include <boost/process/v1/detail/windows/terminate.hpp>
#include <boost/process/v1/detail/windows/wait_for_exit.hpp>
#include <boost/process/v1/detail/windows/is_running.hpp>
#include <boost/process/detail/windows/child_handle.hpp>
#include <boost/process/detail/windows/terminate.hpp>
#include <boost/process/detail/windows/wait_for_exit.hpp>
#include <boost/process/detail/windows/is_running.hpp>
#endif
namespace boost {
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
namespace process {
using ::boost::process::v1::detail::api::pid_t;
using ::boost::process::detail::api::pid_t;
class child
{
::boost::process::v1::detail::api::child_handle _child_handle;
std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::v1::detail::api::still_active);
::boost::process::detail::api::child_handle _child_handle;
std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::detail::api::still_active);
bool _attached = true;
bool _terminated = false;
bool _exited()
{
return _terminated || !::boost::process::v1::detail::api::is_running(_exit_status->load());
return _terminated || !::boost::process::detail::api::is_running(_exit_status->load());
};
public:
typedef ::boost::process::v1::detail::api::child_handle child_handle;
typedef ::boost::process::detail::api::child_handle child_handle;
typedef child_handle::process_handle_t native_handle_t;
explicit child(child_handle &&ch, std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {}
explicit child(pid_t pid) : _child_handle(pid), _attached(false) {};
explicit child(pid_t & pid) : _child_handle(pid), _attached(false) {};
child(const child&) = delete;
child(child && lhs) noexcept
: _child_handle(std::move(lhs._child_handle)),
@@ -73,7 +73,7 @@ public:
template<typename ...Args>
explicit child(Args&&...args);
child() { } // Must be kept non defaulted for MSVC 14.1 & 14.2 #113
child() {}
child& operator=(const child&) = delete;
child& operator=(child && lhs)
{
@@ -98,7 +98,7 @@ public:
native_handle_t native_handle() const { return _child_handle.process_handle(); }
int exit_code() const {return ::boost::process::v1::detail::api::eval_exit_status(_exit_status->load());}
int exit_code() const {return ::boost::process::detail::api::eval_exit_status(_exit_status->load());}
pid_t id() const {return _child_handle.id(); }
int native_exit_code() const {return _exit_status->load();}
@@ -107,7 +107,7 @@ public:
{
std::error_code ec;
bool b = running(ec);
boost::process::v1::detail::throw_error(ec, "running error");
boost::process::detail::throw_error(ec, "running error");
return b;
}
@@ -115,38 +115,33 @@ public:
{
std::error_code ec;
terminate(ec);
boost::process::v1::detail::throw_error(ec, "terminate error");
boost::process::detail::throw_error(ec, "terminate error");
}
void wait()
{
std::error_code ec;
wait(ec);
boost::process::v1::detail::throw_error(ec, "wait error");
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;
bool b = wait_for(rel_time, ec);
boost::process::v1::detail::throw_error(ec, "wait_for error");
boost::process::detail::throw_error(ec, "wait_for error");
return b;
}
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;
bool b = wait_until(timeout_time, ec);
boost::process::v1::detail::throw_error(ec, "wait_until error");
boost::process::detail::throw_error(ec, "wait_until error");
return b;
}
#endif
bool running(std::error_code & ec) noexcept
{
@@ -154,7 +149,7 @@ public:
if (valid() && !_exited() && !ec)
{
int exit_code = 0;
auto res = boost::process::v1::detail::api::is_running(_child_handle, exit_code, ec);
auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec);
if (!ec && !res && !_exited())
_exit_status->store(exit_code);
@@ -166,7 +161,7 @@ public:
void terminate(std::error_code & ec) noexcept
{
if (valid() && running(ec) && !ec)
boost::process::v1::detail::api::terminate(_child_handle, ec);
boost::process::detail::api::terminate(_child_handle, ec);
if (!ec)
_terminated = true;
@@ -177,35 +172,32 @@ public:
if (!_exited() && valid())
{
int exit_code = 0;
boost::process::v1::detail::api::wait(_child_handle, exit_code, ec);
boost::process::detail::api::wait(_child_handle, exit_code, ec);
if (!ec)
_exit_status->store(exit_code);
}
}
#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())
{
int exit_code = 0;
auto b = boost::process::v1::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
if (!b || ec)
return false;
_exit_status->store(exit_code);
}
return true;
}
#endif
bool valid() const
{
@@ -225,7 +217,6 @@ public:
}}}
}}
#endif

View File

@@ -21,19 +21,7 @@
#include <system_error>
#include <boost/system/api_config.hpp>
#if !defined(BOOST_PROCESS_VERSION)
#define BOOST_PROCESS_VERSION 1
#endif
#if BOOST_PROCESS_VERSION == 1
#define BOOST_PROCESS_V1_INLINE inline
#else
#define BOOST_PROCESS_V1_INLINE
#endif
#include <boost/throw_exception.hpp>
#include <boost/process/v1/exception.hpp>
#include <boost/assert/source_location.hpp>
#include <boost/process/exception.hpp>
#if defined(BOOST_POSIX_API)
#include <errno.h>
@@ -48,9 +36,7 @@ extern char **environ;
#error "System API not supported by boost.process"
#endif
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail
namespace boost { namespace process { namespace detail
{
#if !defined(BOOST_PROCESS_PIPE_SIZE)
@@ -85,33 +71,31 @@ inline std::error_code get_last_error() noexcept
}
#endif
inline void throw_last_error(const std::string & msg, boost::source_location const & loc = boost::source_location())
inline void throw_last_error(const std::string & msg)
{
boost::throw_exception(process_error(get_last_error(), msg), loc);
throw process_error(get_last_error(), msg);
}
inline void throw_last_error(const char * msg, boost::source_location const & loc = boost::source_location())
inline void throw_last_error(const char * msg)
{
boost::throw_exception(process_error(get_last_error(), msg), loc);
throw process_error(get_last_error(), msg);
}
inline void throw_last_error(boost::source_location const & loc = boost::source_location())
inline void throw_last_error()
{
boost::throw_exception(process_error(get_last_error()), loc);
throw process_error(get_last_error());
}
inline void throw_error(const std::error_code& ec,
boost::source_location const & loc = boost::source_location())
inline void throw_error(const std::error_code& ec)
{
if (ec)
boost::throw_exception(process_error(ec), loc);
throw process_error(ec);
}
inline void throw_error(const std::error_code& ec, const char* msg,
boost::source_location const & loc = boost::source_location())
inline void throw_error(const std::error_code& ec, const char* msg)
{
if (ec)
boost::throw_exception(process_error(ec, msg), loc);
throw process_error(ec, msg);
}
template<typename Char> constexpr Char null_char();
@@ -130,10 +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

View File

@@ -17,17 +17,17 @@
#ifndef BOOST_PROCESS_EXECUTE_HPP
#define BOOST_PROCESS_EXECUTE_HPP
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/traits.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/v1/detail/posix/executor.hpp>
#include <boost/process/detail/posix/executor.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/v1/detail/windows/executor.hpp>
#include <boost/process/detail/windows/executor.hpp>
#endif
#include <boost/process/v1/detail/basic_cmd.hpp>
#include <boost/process/v1/detail/handler.hpp>
#include <boost/process/detail/basic_cmd.hpp>
#include <boost/process/detail/handler.hpp>
#include <boost/fusion/view.hpp>
#include <boost/fusion/container.hpp>
@@ -40,7 +40,7 @@
#include <type_traits>
#include <utility>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
namespace boost { namespace process {
class child;
@@ -228,7 +228,7 @@ inline child basic_execute_impl(Args && ... args)
boost::fusion::tuple<typename std::remove_reference<Args>::type&...> tup(args...);
auto inits = boost::fusion::filter_if<
boost::process::v1::detail::is_initializer<
boost::process::detail::is_initializer<
typename std::remove_reference<
boost::mpl::_
>::type
@@ -237,7 +237,7 @@ inline child basic_execute_impl(Args && ... args)
auto others = boost::fusion::filter_if<
boost::mpl::not_<
boost::process::v1::detail::is_initializer<
boost::process::detail::is_initializer<
typename std::remove_reference<
boost::mpl::_
>::type
@@ -250,20 +250,20 @@ inline child basic_execute_impl(Args && ... args)
//typedef typename boost::fusion::result_of::as_vector<decltype(inits)>::type inits_t;
typedef typename boost::fusion::result_of::as_vector<decltype(others)>::type others_t;
// typedef decltype(others) others_t;
typedef typename ::boost::process::v1::detail::make_builders_from_view<
typedef typename ::boost::process::detail::make_builders_from_view<
typename boost::fusion::result_of::begin<others_t>::type,
typename boost::fusion::result_of::end <others_t>::type>::type builder_t;
builder_t builders;
::boost::process::v1::detail::builder_ref<builder_t> builder_ref(builders);
::boost::process::detail::builder_ref<builder_t> builder_ref(builders);
boost::fusion::for_each(others, builder_ref);
auto other_inits = ::boost::process::v1::detail::get_initializers(builders);
auto other_inits = ::boost::process::detail::get_initializers(builders);
boost::fusion::joint_view<decltype(other_inits), decltype(inits)> complete_inits(other_inits, inits);
auto exec = boost::process::v1::detail::api::make_executor<Char>(complete_inits);
auto exec = boost::process::detail::api::make_executor<Char>(complete_inits);
return exec();
}
@@ -273,11 +273,12 @@ inline child execute_impl(Args&& ... args)
typedef required_char_type_t<Args...> req_char_type;
return basic_execute_impl<req_char_type>(
boost::process::v1::detail::char_converter_t<req_char_type, Args>::conv(
boost::process::detail::char_converter_t<req_char_type, Args>::conv(
std::forward<Args>(args))...
);
}
}}}}
}}}
#endif

View File

@@ -7,16 +7,16 @@
#ifndef BOOST_PROCESS_DETAIL_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_HANDLER_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/v1/detail/windows/handler.hpp>
#include <boost/process/detail/windows/handler.hpp>
#endif
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
namespace boost { namespace process { namespace detail {
//extended handler base.
typedef api::handler_base_ext handler;
@@ -68,6 +68,8 @@ private:
}}}
}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

View File

@@ -11,10 +11,9 @@
#ifndef BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP
#define BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP
#include <boost/process/v1/detail/config.hpp>
#include <system_error>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
namespace boost { namespace process { namespace detail {
template<template <class> class Template>
struct make_handler_t
@@ -45,6 +44,6 @@ struct handler_base
};
}}}}
}}}
#endif

View File

@@ -6,18 +6,18 @@
#ifndef BOOST_PROCESS_DETAIL_ON_EXIT_HPP_
#define BOOST_PROCESS_DETAIL_ON_EXIT_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/v1/detail/posix/on_exit.hpp>
#include <boost/process/detail/posix/on_exit.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/v1/detail/windows/on_exit.hpp>
#include <boost/process/detail/windows/on_exit.hpp>
#endif
#include <future>
#include <memory>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
namespace boost { namespace process { namespace detail {
inline std::function<void(int, const std::error_code &)> on_exit_from_future(std::future<int> &f)
{
@@ -46,9 +46,8 @@ struct on_exit_
}
constexpr static ::boost::process::v1::detail::on_exit_ on_exit{};
constexpr static ::boost::process::detail::on_exit_ on_exit{};
}}}
}}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */

View File

@@ -0,0 +1,86 @@
// Copyright (c) 2016 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_DETAIL_POSIX_ASIO_FWD_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_
#include <memory>
namespace boost { namespace asio {
template<typename T>
struct is_mutable_buffer_sequence;
template<typename T>
struct is_const_buffer_sequence;
template<typename Allocator>
class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_context;
class executor;
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class signal_set_service;
template <typename SignalSetService>
class basic_signal_set;
typedef basic_signal_set<signal_set_service> signal_set;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
template <typename Executor>
class basic_signal_set;
typedef basic_signal_set<executor> signal_set;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
template <typename Handler>
class basic_yield_context;
namespace posix {
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class stream_descriptor_service;
template <typename StreamDesscriptorService>
class basic_stream_descriptor;
typedef basic_stream_descriptor<stream_descriptor_service> stream_descriptor;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
template <typename Executor>
class basic_stream_descriptor;
typedef basic_stream_descriptor<executor> stream_descriptor;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
} //posix
} //asio
namespace process { namespace detail { namespace posix {
class async_pipe;
template<typename T>
struct async_in_buffer;
template<int p1, int p2, typename Buffer>
struct async_out_buffer;
template<int p1, int p2, typename Type>
struct async_out_future;
} // posix
} // detail
using ::boost::process::detail::posix::async_pipe;
} // process
} // boost
#endif /* BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_ */

View File

@@ -7,10 +7,10 @@
#ifndef BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <type_traits>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct require_io_context {};
@@ -35,6 +35,6 @@ template<typename T>
struct does_require_io_context<const T&> : std::is_base_of<require_io_context, T> {};
}}}}}
}}}}
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */

View File

@@ -10,22 +10,19 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#include <boost/process/v1/detail/handler_base.hpp>
#include <boost/process/v1/detail/posix/async_handler.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/write.hpp>
#include <boost/process/v1/async_pipe.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
#include <boost/process/v1/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Buffer>
struct async_in_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
::boost::process::v1::detail::posix::require_io_context,
::boost::process::v1::detail::uses_handles
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context
{
Buffer & buf;
@@ -36,8 +33,7 @@ struct async_in_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
fut = promise->get_future(); return std::move(*this);
}
std::shared_ptr<boost::process::v1::async_pipe> pipe;
std::shared_ptr<boost::process::async_pipe> pipe;
async_in_buffer(Buffer & buf) : buf(buf)
{
@@ -80,24 +76,14 @@ struct async_in_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
template<typename Executor>
void on_setup(Executor & exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
}
std::array<int, 3> get_used_handles()
{
if (pipe)
return {STDIN_FILENO, pipe->native_source(), pipe->native_sink()};
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
return {STDIN_FILENO, STDIN_FILENO, STDIN_FILENO};
}
template <typename Executor>
void on_exec_setup(Executor &exec)
{
if (::dup2(pipe->native_source(), STDIN_FILENO) == -1)
exec.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (pipe->native_source() != STDIN_FILENO)
::close(pipe->native_source());
@@ -106,6 +92,6 @@ struct async_in_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
};
}}}}}
}}}}
#endif

View File

@@ -11,18 +11,16 @@
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/v1/async_pipe.hpp>
#include <boost/process/async_pipe.hpp>
#include <istream>
#include <memory>
#include <exception>
#include <future>
#include <array>
#include <boost/process/v1/detail/used_handles.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
@@ -46,24 +44,12 @@ inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::in
}
template<int p1, int p2, typename Buffer>
struct async_out_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
::boost::process::v1::detail::posix::require_io_context,
::boost::process::v1::detail::uses_handles
struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context
{
Buffer & buf;
std::shared_ptr<boost::process::v1::async_pipe> pipe;
std::array<int, 4> get_used_handles()
{
const auto pp1 = p1 != -1 ? p1 : p2;
const auto pp2 = p2 != -1 ? p2 : p1;
if (pipe)
return {pipe->native_source(), pipe->native_sink(), pp1, pp2};
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
return {pp1, pp2, pp1, pp2};
}
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_buffer(Buffer & buf) : buf(buf)
@@ -71,7 +57,7 @@ struct async_out_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
}
template <typename Executor>
inline void on_success(Executor &)
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
@@ -90,7 +76,7 @@ struct async_out_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
}
@@ -100,7 +86,7 @@ struct async_out_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
int res = apply_out_handles(pipe->native_sink(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
if (res == -1)
exec.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_sink());
::close(pipe->native_source());
@@ -112,14 +98,14 @@ struct async_out_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::v1::detail::posix::handler_base_ext,
::boost::process::v1::detail::posix::require_io_context
struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context
{
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
std::shared_ptr<boost::process::v1::async_pipe> pipe;
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_future(std::future<Type> & fut)
{
@@ -145,11 +131,8 @@ struct async_out_future : ::boost::process::v1::detail::posix::handler_base_ext,
{
std::istream is (buffer_.get());
Type arg;
if (buffer_->size() > 0)
{
arg.resize(buffer_->size());
is.read(&*arg.begin(), buffer_->size());
}
arg.resize(buffer_->size());
is.read(&*arg.begin(), buffer_->size());
promise_->set_value(std::move(arg));
}
});
@@ -167,7 +150,7 @@ struct async_out_future : ::boost::process::v1::detail::posix::handler_base_ext,
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
}
template <typename Executor>
@@ -177,7 +160,7 @@ struct async_out_future : ::boost::process::v1::detail::posix::handler_base_ext,
int res = apply_out_handles(pipe->native_sink(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
if (res == -1)
exec.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_sink());
::close(pipe->native_source());
@@ -185,6 +168,6 @@ struct async_out_future : ::boost::process::v1::detail::posix::handler_base_ext,
};
}}}}}
}}}}
#endif

View File

@@ -7,14 +7,14 @@
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
#include <boost/process/v1/detail/posix/basic_pipe.hpp>
#include <boost/process/detail/posix/basic_pipe.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/post.hpp>
#include <system_error>
#include <string>
#include <utility>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
class async_pipe
{
@@ -23,12 +23,6 @@ class async_pipe
public:
typedef int native_handle_type;
typedef ::boost::asio::posix::stream_descriptor handle_type;
typedef typename handle_type::executor_type executor_type;
executor_type get_executor()
{
return _source.get_executor();
}
inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {}
@@ -37,7 +31,7 @@ public:
{
int fds[2];
if (::pipe(fds) == -1)
boost::process::v1::detail::throw_last_error("pipe(2) failed");
boost::process::detail::throw_last_error("pipe(2) failed");
_source.assign(fds[0]);
_sink .assign(fds[1]);
@@ -50,8 +44,8 @@ public:
inline async_pipe(const async_pipe& lhs);
async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink))
{
lhs._source = ::boost::asio::posix::stream_descriptor{lhs._source.get_executor()};
lhs._sink = ::boost::asio::posix::stream_descriptor{lhs._sink. get_executor()};
lhs._source.assign (-1);
lhs._sink .assign (-1);
}
template<class CharT, class Traits = std::char_traits<CharT>>
@@ -76,8 +70,10 @@ public:
~async_pipe()
{
boost::system::error_code ec;
close(ec);
if (_sink .native_handle() != -1)
::close(_sink.native_handle());
if (_source.native_handle() != -1)
::close(_source.native_handle());
}
template<class CharT, class Traits = std::char_traits<CharT>>
@@ -205,18 +201,18 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
auto fifo = mkfifo(name.c_str(), 0666 );
if (fifo != 0)
boost::process::v1::detail::throw_last_error("mkfifo() failed");
boost::process::detail::throw_last_error("mkfifo() failed");
int read_fd = open(name.c_str(), O_RDWR);
if (read_fd == -1)
boost::process::v1::detail::throw_last_error();
boost::process::detail::throw_last_error();
int write_fd = dup(read_fd);
if (write_fd == -1)
boost::process::v1::detail::throw_last_error();
boost::process::detail::throw_last_error();
_source.assign(read_fd);
_sink .assign(write_fd);
@@ -236,7 +232,7 @@ async_pipe::async_pipe(const async_pipe & p) :
{
_source.assign(::dup(source_in));
if (_source.native_handle()== -1)
::boost::process::v1::detail::throw_last_error("dup()");
::boost::process::detail::throw_last_error("dup()");
}
if (sink_in == -1)
@@ -245,7 +241,7 @@ async_pipe::async_pipe(const async_pipe & p) :
{
_sink.assign(::dup(sink_in));
if (_sink.native_handle() == -1)
::boost::process::v1::detail::throw_last_error("dup()");
::boost::process::detail::throw_last_error("dup()");
}
}
@@ -263,7 +259,7 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
{
source = ::dup(source_in);
if (source == -1)
::boost::process::v1::detail::throw_last_error("dup()");
::boost::process::detail::throw_last_error("dup()");
}
if (sink_in == -1)
@@ -272,7 +268,7 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
{
sink = ::dup(sink_in);
if (sink == -1)
::boost::process::v1::detail::throw_last_error("dup()");
::boost::process::detail::throw_last_error("dup()");
}
_source.assign(source);
_sink. assign(sink);
@@ -304,7 +300,7 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
{
source = ::dup(source_in);
if (source == -1)
::boost::process::v1::detail::throw_last_error("dup()");
::boost::process::detail::throw_last_error("dup()");
}
if (sink_in == -1)
@@ -313,7 +309,7 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
{
sink = ::dup(sink_in);
if (sink == -1)
::boost::process::v1::detail::throw_last_error("dup()");
::boost::process::detail::throw_last_error("dup()");
}
return basic_pipe<CharT, Traits>{source, sink};
@@ -360,6 +356,6 @@ inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe &
!compare_handles(lhs.native_sink(), rhs.native_sink());
}
}}}}}
}}}}
#endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */

View File

@@ -7,11 +7,10 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/v1/detail/posix/cmd.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/cmd.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/process/v1/shell.hpp>
#include <boost/process/shell.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/join.hpp>
#include <string>
@@ -21,13 +20,12 @@ namespace boost
{
namespace process
{
BOOST_PROCESS_V1_INLINE namespace v1
{
namespace detail
{
namespace posix
{
inline std::string build_cmd_shell(const std::string & exe, std::vector<std::string> && data)
{
std::string st = exe;
@@ -41,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;
@@ -103,7 +101,7 @@ template<typename Char>
struct exe_cmd_init;
template<>
struct exe_cmd_init<char> : boost::process::v1::detail::api::handler_base_ext
struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
{
exe_cmd_init(const exe_cmd_init & ) = delete;
exe_cmd_init(exe_cmd_init && ) = default;
@@ -114,10 +112,7 @@ struct exe_cmd_init<char> : boost::process::v1::detail::api::handler_base_ext
{
if (exe.empty()) //cmd style
{
if (args.empty())
exec.exe = "";
else
exec.exe = args.front().c_str();
exec.exe = args.front().c_str();
exec.cmd_style = true;
}
else
@@ -144,7 +139,7 @@ struct exe_cmd_init<char> : boost::process::v1::detail::api::handler_base_ext
}
static exe_cmd_init cmd_shell(std::string&& cmd)
{
std::vector<std::string> args = {"-c", cmd};
std::vector<std::string> args = {"-c", "\"" + cmd + "\""};
std::string sh = shell().string();
return exe_cmd_init(
@@ -160,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);
@@ -177,6 +170,6 @@ std::vector<char*> exe_cmd_init<char>::make_cmd()
}
}}}}}
}}}}
#endif

View File

@@ -11,15 +11,15 @@
#define BOOST_PROCESS_POSIX_PIPE_HPP
#include <boost/process/v1/filesystem.hpp>
#include <boost/process/v1/detail/posix/compare_handles.hpp>
#include <boost/filesystem.hpp>
#include <boost/process/detail/posix/compare_handles.hpp>
#include <system_error>
#include <array>
#include <unistd.h>
#include <fcntl.h>
#include <memory>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<class CharT, class Traits = std::char_traits<CharT>>
@@ -41,7 +41,7 @@ public:
{
int fds[2];
if (::pipe(fds) == -1)
boost::process::v1::detail::throw_last_error("pipe(2) failed");
boost::process::detail::throw_last_error("pipe(2) failed");
_source = fds[0];
_sink = fds[1];
@@ -77,32 +77,27 @@ public:
void assign_source(native_handle_type h) { _source = h;}
void assign_sink (native_handle_type h) { _sink = h;}
int_type write(const char_type * data, int_type count)
{
ssize_t write_len;
while ((write_len = ::write(_sink, data, count * sizeof(char_type))) == -1)
{
//Try again if interrupted
auto err = errno;
if (err != EINTR)
::boost::process::v1::detail::throw_last_error();
}
return static_cast<int_type>(write_len);
auto write_len = ::write(_sink, data, count * sizeof(char_type));
if (write_len == -1)
::boost::process::detail::throw_last_error();
return write_len;
}
int_type read(char_type * data, int_type count)
{
ssize_t read_len;
while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1)
{
//Try again if interrupted
auto err = errno;
if (err != EINTR)
::boost::process::v1::detail::throw_last_error();
}
return static_cast<int_type>(read_len);
auto read_len = ::read(_source, data, count * sizeof(char_type));
if (read_len == -1)
::boost::process::detail::throw_last_error();
return read_len;
}
bool is_open() const
bool is_open()
{
return (_source != -1) ||
(_sink != -1);
@@ -126,13 +121,13 @@ basic_pipe<CharT, Traits>::basic_pipe(const basic_pipe & rhs)
{
_source = ::dup(rhs._source);
if (_source == -1)
::boost::process::v1::detail::throw_last_error("dup() failed");
::boost::process::detail::throw_last_error("dup() failed");
}
if (rhs._sink != -1)
{
_sink = ::dup(rhs._sink);
if (_sink == -1)
::boost::process::v1::detail::throw_last_error("dup() failed");
::boost::process::detail::throw_last_error("dup() failed");
}
}
@@ -144,13 +139,13 @@ basic_pipe<CharT, Traits> &basic_pipe<CharT, Traits>::operator=(const basic_pipe
{
_source = ::dup(rhs._source);
if (_source == -1)
::boost::process::v1::detail::throw_last_error("dup() failed");
::boost::process::detail::throw_last_error("dup() failed");
}
if (rhs._sink != -1)
{
_sink = ::dup(rhs._sink);
if (_sink == -1)
::boost::process::v1::detail::throw_last_error("dup() failed");
::boost::process::detail::throw_last_error("dup() failed");
}
return *this;
@@ -163,18 +158,18 @@ basic_pipe<CharT, Traits>::basic_pipe(const std::string & name)
auto fifo = mkfifo(name.c_str(), 0666 );
if (fifo != 0)
boost::process::v1::detail::throw_last_error("mkfifo() failed");
boost::process::detail::throw_last_error("mkfifo() failed");
int read_fd = open(name.c_str(), O_RDWR);
if (read_fd == -1)
boost::process::v1::detail::throw_last_error();
boost::process::detail::throw_last_error();
int write_fd = dup(read_fd);
if (write_fd == -1)
boost::process::v1::detail::throw_last_error();
boost::process::detail::throw_last_error();
_sink = write_fd;
_source = read_fd;
@@ -195,6 +190,6 @@ inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Ch
!compare_handles(lhs.native_sink(), rhs.native_sink());
}
}}}}}
}}}}
#endif

View File

@@ -13,7 +13,7 @@
#include <utility>
#include <system_error>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
typedef ::pid_t pid_t;
@@ -55,6 +55,6 @@ struct child_handle
}
};
}}}}}
}}}}
#endif

View File

@@ -11,24 +11,20 @@
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/v1/detail/used_handles.hpp>
#include <boost/process/detail/posix/handler.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct close_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
struct close_in : handler_base_ext
{
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::close(STDIN_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
}
int get_used_handles() {return STDIN_FILENO;}
};
}}}}}
}}}}
#endif

View File

@@ -10,19 +10,16 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
#include <boost/process/v1/detail/used_handles.hpp>
#include <boost/process/v1/detail/posix/handler.hpp>
#include <array>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
#include <boost/process/detail/posix/handler.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct close_out : handler_base_ext
{
template <class Executor>
inline void on_exec_setup(Executor &e) const;
std::array<int, 2> get_used_handles() {return {{p1 != -1 ? p1 : p2, p2 != -1 ? p2 : p1}};}
};
template<>
@@ -30,7 +27,7 @@ template<typename Executor>
void close_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::close(STDOUT_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
}
@@ -39,7 +36,7 @@ template<typename Executor>
void close_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::close(STDERR_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
}
template<>
@@ -47,12 +44,12 @@ template<typename Executor>
void close_out<1,2>::on_exec_setup(Executor &e) const
{
if (::close(STDOUT_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
if (::close(STDERR_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
}
}}}}}
}}}}
#endif

View File

@@ -7,8 +7,8 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_CMD_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_CMD_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <string>
#include <vector>
@@ -16,8 +16,6 @@ namespace boost
{
namespace process
{
BOOST_PROCESS_V1_INLINE namespace v1
{
namespace detail
{
namespace posix
@@ -101,6 +99,6 @@ std::vector<Char*> cmd_setter_<Char>::make_cmd(std::vector<std::basic_string<Cha
return vec;
}
}}}}}
}}}}
#endif

View File

@@ -7,12 +7,12 @@
#define BOOST_PROCESS_DETAIL_POSIX_COMPARE_HANDLES_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
inline bool compare_handles(int lhs, int rhs)
@@ -25,8 +25,8 @@ inline bool compare_handles(int lhs, int rhs)
return true;
struct stat stat1, stat2;
if(fstat(lhs, &stat1) < 0) ::boost::process::v1::detail::throw_last_error("fstat() failed");
if(fstat(rhs, &stat2) < 0) ::boost::process::v1::detail::throw_last_error("fstat() failed");
if(fstat(lhs, &stat1) < 0) ::boost::process::detail::throw_last_error("fstat() failed");
if(fstat(rhs, &stat2) < 0) ::boost::process::detail::throw_last_error("fstat() failed");
return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
}
@@ -35,7 +35,7 @@ inline bool compare_handles(int lhs, int rhs)
}}}}}
}}}}

View File

@@ -8,11 +8,11 @@
#define BOOST_PROCESS_DETAIL_POSIX_ENV_INIT_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/v1/environment.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/environment.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Char>
struct env_init;
@@ -20,10 +20,10 @@ struct env_init;
template<>
struct env_init<char> : handler_base_ext
{
boost::process::v1::environment env;
boost::process::environment env;
env_init(boost::process::v1::environment && env) : env(std::move(env)) {};
env_init(const boost::process::v1::environment & env) : env(env) {};
env_init(boost::process::environment && env) : env(std::move(env)) {};
env_init(const boost::process::environment & env) : env(env) {};
template <class Executor>
@@ -34,7 +34,7 @@ struct env_init<char> : handler_base_ext
};
}}}}}
}}}}

View File

@@ -9,13 +9,13 @@
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#include <algorithm>
#include <cstdlib>
#include <boost/process/v1/locale.hpp>
#include <boost/process/locale.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Char>
class native_environment_impl
@@ -27,7 +27,7 @@ class native_environment_impl
while (*p != nullptr)
{
std::string str = *p;
val.push_back(::boost::process::v1::detail::convert(str));
val.push_back(::boost::process::detail::convert(str));
p++;
}
return val;
@@ -56,7 +56,6 @@ public:
{
_buffer = _load();
_impl = _load_var(_buffer);
_env_impl = _impl.data();
}
string_type get(const pointer_type id) { return get(string_type(id)); }
@@ -68,24 +67,24 @@ public:
string_type get(const string_type & id)
{
std::string id_c = ::boost::process::v1::detail::convert(id);
std::string id_c = ::boost::process::detail::convert(id);
std::string g = ::getenv(id_c.c_str());
return ::boost::process::v1::detail::convert(g.c_str());
return ::boost::process::detail::convert(g.c_str());
}
void set(const string_type & id, const string_type & value)
{
std::string id_c = ::boost::process::v1::detail::convert(id.c_str());
std::string value_c = ::boost::process::v1::detail::convert(value.c_str());
std::string id_c = ::boost::process::detail::convert(id.c_str());
std::string value_c = ::boost::process::detail::convert(value.c_str());
auto res = ::setenv(id_c.c_str(), value_c.c_str(), true);
if (res != 0)
boost::process::v1::detail::throw_last_error();
boost::process::detail::throw_last_error();
}
void reset(const string_type & id)
{
std::string id_c = ::boost::process::v1::detail::convert(id.c_str());
std::string id_c = ::boost::process::detail::convert(id.c_str());
auto res = ::unsetenv(id_c.c_str());
if (res != 0)
::boost::process::v1::detail::throw_last_error();
::boost::process::detail::throw_last_error();
}
native_environment_impl() = default;
@@ -95,7 +94,7 @@ public:
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = _impl.data();
native_handle_type native_handle() const {return _env_impl;}
native_handle_type native_handle() const {return environ;}
};
template<>
@@ -114,14 +113,14 @@ public:
{
auto res = ::setenv(id, value, 1);
if (res != 0)
boost::process::v1::detail::throw_last_error();
boost::process::detail::throw_last_error();
reload();
}
void reset(const pointer_type id)
{
auto res = ::unsetenv(id);
if (res != 0)
boost::process::v1::detail::throw_last_error();
boost::process::detail::throw_last_error();
reload();
}
@@ -186,13 +185,13 @@ public:
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::v1::codecvt_type & cv = ::boost::process::v1::codecvt())
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(rhs._data.size())
{
std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(),
[&](const std::basic_string<CharR> & st)
{
return ::boost::process::v1::detail::convert(st, cv);
return ::boost::process::detail::convert(st, cv);
}
);
@@ -202,7 +201,7 @@ public:
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::v1::detail::convert(rhs._data);
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
@@ -230,8 +229,8 @@ 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
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st) -> bool
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
@@ -250,8 +249,8 @@ inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_t
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st) -> bool
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
@@ -261,7 +260,7 @@ inline void basic_environment_impl<Char>::set(const string_type &id, const strin
if (itr != _data.end())
*itr = id + equal_sign<Char>() + value;
else
else
_data.push_back(id + equal_sign<Char>() + value);
reload();
@@ -270,8 +269,8 @@ inline void basic_environment_impl<Char>::set(const string_type &id, const strin
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st) -> bool
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
@@ -280,9 +279,9 @@ inline void basic_environment_impl<Char>::reset(const string_type &id)
);
if (itr != _data.end())
{
_data.erase(itr);//and remove it
_data.erase(itr);//and remove it
}
reload();
@@ -295,11 +294,7 @@ std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basi
ret.reserve(data.size() +1);
for (auto & val : data)
{
if (val.empty())
val.push_back(0);
ret.push_back(&val.front());
}
ret.push_back(nullptr);
return ret;
@@ -320,7 +315,7 @@ inline int native_handle() {return getpid(); }
}
}
}
}

View File

@@ -7,14 +7,11 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_EXE_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_EXE_HPP_
#include <boost/process/v1/detail/config.hpp>
namespace boost
{
namespace process
{
BOOST_PROCESS_V1_INLINE namespace v1
{
namespace detail
{
namespace posix
@@ -33,7 +30,7 @@ inline void apply_exe(const StringType & exe, Executor & e)
}
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */

View File

@@ -10,11 +10,11 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
#define BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
#include <boost/process/v1/detail/child_decl.hpp>
#include <boost/process/v1/error.hpp>
#include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/detail/posix/basic_pipe.hpp>
#include <boost/process/v1/detail/posix/use_vfork.hpp>
#include <boost/process/detail/child_decl.hpp>
#include <boost/process/error.hpp>
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/basic_pipe.hpp>
#include <boost/process/detail/posix/use_vfork.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <cstdlib>
#include <sys/types.h>
@@ -26,9 +26,7 @@
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/core/ignore_unused.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Executor>
struct on_setup_t
@@ -151,15 +149,15 @@ class executor
int _pipe_sink = -1;
void write_error(const std::error_code & ec, const char * msg)
{
//I am the child
const auto len = static_cast<int>(std::strlen(msg));
int data[2] = {ec.value(), len + 1};
int len = ec.value();
::write(_pipe_sink, &len, sizeof(int));
boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2));
boost::ignore_unused(::write(_pipe_sink, msg, len));
len = std::strlen(msg) + 1;
::write(_pipe_sink, &len, sizeof(int));
::write(_pipe_sink, msg, len);
}
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::false_)
@@ -204,9 +202,9 @@ class executor
throw process_error(_ec, _msg);
}
typedef typename ::boost::process::v1::detail::has_error_handler<Sequence>::type has_error_handler;
typedef typename ::boost::process::v1::detail::has_ignore_error <Sequence>::type has_ignore_error;
typedef typename ::boost::process::v1::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler;
typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error;
typedef typename ::boost::process::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
inline child invoke(boost::mpl::true_ , boost::mpl::true_ );
inline child invoke(boost::mpl::false_, boost::mpl::true_ );
@@ -275,15 +273,14 @@ class executor
prepare_cmd_style_fn = exe;
if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK))
{
const auto * e = ::environ;
while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH="))
auto e = ::environ;
while ((*e != nullptr) && !boost::starts_with(*e, "PATH="))
e++;
if ((e != nullptr) && (*e != nullptr))
if (e != nullptr)
{
std::vector<std::string> path;
//the beginning of the string contains "PATH="
boost::split(path, (*e) + 5, boost::is_any_of(":"));
boost::split(path, *e, boost::is_any_of(":"));
for (const std::string & pp : path)
{
@@ -328,13 +325,6 @@ public:
}
void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
std::vector<int> get_used_handles() const
{
if (_pipe_sink == -1)
return {};
else
return {_pipe_sink};
};
};
template<typename Sequence>
@@ -349,7 +339,7 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
this->pid = ::fork();
if (pid == -1)
{
auto ec = boost::process::v1::detail::get_last_error();
auto ec = boost::process::detail::get_last_error();
boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
return child();
}
@@ -357,7 +347,7 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
{
boost::fusion::for_each(seq, call_on_exec_setup(*this));
::execve(exe, cmd_line, env);
auto ec = boost::process::v1::detail::get_last_error();
auto ec = boost::process::detail::get_last_error();
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
_exit(EXIT_FAILURE);
}
@@ -389,25 +379,21 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
if (::pipe(p.p) == -1)
{
set_error(::boost::process::v1::detail::get_last_error(), "pipe(2) failed");
set_error(::boost::process::detail::get_last_error(), "pipe(2) failed");
return child();
}
if (::fcntl(p.p[1], F_SETFD, FD_CLOEXEC) == -1)
{
auto err = ::boost::process::v1::detail::get_last_error();
auto err = ::boost::process::detail::get_last_error();
set_error(err, "fcntl(2) failed");//this might throw, so we need to be sure our pipe is safe.
return child();
}
_pipe_sink = p.p[1];
_ec.clear();
boost::fusion::for_each(seq, call_on_setup(*this));
if (_ec)
{
boost::fusion::for_each(seq, call_on_error(*this, _ec));
_pipe_sink = -1;
return child();
}
@@ -417,24 +403,24 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
this->pid = ::fork();
if (pid == -1)
{
_ec = boost::process::v1::detail::get_last_error();
_ec = boost::process::detail::get_last_error();
_msg = "fork() failed";
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
boost::fusion::for_each(seq, call_on_error(*this, _ec));
_pipe_sink = -1;
return child();
}
else if (pid == 0)
{
_pipe_sink = p.p[1];
::close(p.p[0]);
boost::fusion::for_each(seq, call_on_exec_setup(*this));
::execve(exe, cmd_line, env);
_ec = boost::process::v1::detail::get_last_error();
_ec = boost::process::detail::get_last_error();
_msg = "execve failed";
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
_write_error(_pipe_sink);
_write_error(p.p[1]);
::close(p.p[1]);
_exit(EXIT_FAILURE);
@@ -443,14 +429,11 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
::close(p.p[1]);
p.p[1] = -1;
_pipe_sink = -1;
_read_error(p.p[0]);
}
if (_ec)
{
//if an error occurred we need to reap the child process
::waitpid(this->pid, nullptr, WNOHANG);
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
@@ -480,7 +463,7 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore
this->pid = ::vfork();
if (pid == -1)
{
auto ec = boost::process::v1::detail::get_last_error();
auto ec = boost::process::detail::get_last_error();
boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
return child();
}
@@ -488,7 +471,7 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore
{
boost::fusion::for_each(seq, call_on_exec_setup(*this));
::execve(exe, cmd_line, env);
auto ec = boost::process::v1::detail::get_last_error();
auto ec = boost::process::detail::get_last_error();
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
_exit(EXIT_FAILURE);
}
@@ -516,7 +499,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
this->pid = ::vfork();
if (pid == -1)
{
_ec = boost::process::v1::detail::get_last_error();
_ec = boost::process::detail::get_last_error();
_msg = "fork() failed";
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
boost::fusion::for_each(seq, call_on_error(*this, _ec));
@@ -529,7 +512,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
::execve(exe, cmd_line, env);
_ec = boost::process::v1::detail::get_last_error();
_ec = boost::process::detail::get_last_error();
_msg = "execve failed";
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
@@ -544,7 +527,6 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
if (_ec)
{
::waitpid(this->pid, nullptr, WNOHANG);
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
@@ -568,6 +550,6 @@ inline executor<Tup> make_executor(Tup & tup)
return executor<Tup>(tup);
}
}}}}}
}}}}
#endif

View File

@@ -10,15 +10,13 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_FD_HPP
#define BOOST_PROCESS_DETAIL_POSIX_FD_HPP
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
#include <boost/process/v1/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct close_fd_ : handler_base_ext, ::boost::process::v1::detail::uses_handles
struct close_fd_ : handler_base_ext
{
close_fd_(int fd) : fd_(fd) {}
@@ -26,18 +24,15 @@ struct close_fd_ : handler_base_ext, ::boost::process::v1::detail::uses_handles
void on_exec_setup(PosixExecutor& e) const
{
if (::close(fd_) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
}
int get_used_handles() {return fd_;}
private:
int fd_;
};
template <class Range>
struct close_fds_ : handler_base_ext, ::boost::process::v1::detail::uses_handles
struct close_fds_ : handler_base_ext
{
public:
close_fds_(const Range &fds) : fds_(fds) {}
@@ -48,13 +43,11 @@ public:
for (auto & fd_ : fds_)
if (::close(fd_) == -1)
{
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
break;
}
}
Range& get_used_handles() {return fds_;}
private:
Range fds_;
};
@@ -62,7 +55,7 @@ private:
template <class FileDescriptor>
struct bind_fd_ : handler_base_ext, ::boost::process::v1::detail::uses_handles
struct bind_fd_ : handler_base_ext
{
public:
bind_fd_(int id, const FileDescriptor &fd) : id_(id), fd_(fd) {}
@@ -71,12 +64,9 @@ public:
void on_exec_setup(PosixExecutor& e) const
{
if (::dup2(fd_, id_) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
std::array<int, 2> get_used_handles() {return {id_, fd_};}
private:
int id_;
FileDescriptor fd_;
@@ -97,6 +87,6 @@ struct fd_
};
}}}}}
}}}}
#endif

View File

@@ -8,10 +8,9 @@
#include <fcntl.h>
#include <string>
#include <boost/process/v1/filesystem.hpp>
#include <boost/core/exchange.hpp>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct file_descriptor
{
@@ -24,7 +23,7 @@ struct file_descriptor
file_descriptor() = default;
explicit file_descriptor(const boost::process::v1::filesystem::path& p, mode_t mode = read_write)
explicit file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
@@ -40,22 +39,10 @@ struct file_descriptor
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor &&other)
: _handle(boost::exchange(other._handle, -1))
{
}
file_descriptor(file_descriptor && ) = default;
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor &&other)
{
if (this != &other)
{
if (_handle != -1)
::close(_handle);
_handle = boost::exchange(other._handle, -1);
}
return *this;
}
file_descriptor& operator=(file_descriptor && ) = default;
~file_descriptor()
{
@@ -84,6 +71,6 @@ private:
int _handle = -1;
};
}}}}}
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */

View File

@@ -10,25 +10,19 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/v1/detail/posix/file_descriptor.hpp>
#include <boost/process/v1/detail/used_handles.hpp>
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <cstdio>
#include <unistd.h>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct file_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
struct file_in : handler_base_ext
{
file_descriptor file;
int handle = file.handle();
std::array<int, 2> get_used_handles()
{
return {{STDIN_FILENO, handle}};
}
template<typename T>
file_in(T&& t) : file(std::forward<T>(t)) {}
file_in(FILE * f) : handle(fileno(f)) {}
@@ -37,10 +31,10 @@ struct file_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
void on_exec_setup(WindowsExecutor &e) const
{
if (::dup2(handle, STDIN_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
}}}}}
}}}}
#endif

View File

@@ -11,15 +11,14 @@
#ifndef BOOST_PROCESS_POSIX_FILE_OUT_HPP
#define BOOST_PROCESS_POSIX_FILE_OUT_HPP
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/v1/detail/posix/file_descriptor.hpp>
#include <boost/process/v1/detail/used_handles.hpp>
#include <unistd.h>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct file_out : handler_base_ext, ::boost::process::v1::detail::uses_handles
struct file_out : handler_base_ext
{
file_descriptor file;
int handle = file.handle();
@@ -28,13 +27,6 @@ struct file_out : handler_base_ext, ::boost::process::v1::detail::uses_handles
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write), handle(file.handle()) {}
file_out(FILE * f) : handle(fileno(f)) {}
std::array<int, 3> get_used_handles()
{
const auto pp1 = p1 != -1 ? p1 : p2;
const auto pp2 = p2 != -1 ? p2 : p1;
return {handle, pp1, pp2};
}
template <typename Executor>
void on_exec_setup(Executor &e) const;
@@ -45,7 +37,7 @@ template<typename Executor>
void file_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
@@ -53,7 +45,7 @@ template<typename Executor>
void file_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
@@ -61,13 +53,13 @@ template<typename Executor>
void file_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
}}}}}
}}}}
#endif

View File

@@ -6,12 +6,12 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/posix/child_handle.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/child_handle.hpp>
#include <system_error>
#include <unistd.h>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct group_handle
{
@@ -42,7 +42,7 @@ struct group_handle
}
void add(handle_t proc)
{
{
if (::setpgid(proc, grp))
throw_last_error();
}
@@ -70,7 +70,7 @@ struct group_handle
inline void terminate(group_handle &p, std::error_code &ec) noexcept
{
if (::killpg(p.grp, SIGKILL) == -1)
ec = boost::process::v1::detail::get_last_error();
ec = boost::process::detail::get_last_error();
else
ec.clear();
@@ -81,7 +81,7 @@ inline void terminate(group_handle &p)
{
std::error_code ec;
terminate(p, ec);
boost::process::v1::detail::throw_error(ec, "killpg(2) failed in terminate");
boost::process::detail::throw_error(ec, "killpg(2) failed in terminate");
}
inline bool in_group()
@@ -89,6 +89,6 @@ inline bool in_group()
return true;
}
}}}}}
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */

View File

@@ -6,13 +6,13 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/posix/group_handle.hpp>
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/group_handle.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
namespace boost { namespace process {
namespace detail { namespace posix {
@@ -46,7 +46,7 @@ struct group_ref : handler_base_ext
};
}}}}}
}}}}
#endif /* BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_ */

View File

@@ -6,9 +6,9 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
#include <boost/process/v1/detail/handler_base.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
//does not extend anything.
struct handler_base_ext : handler_base
@@ -67,7 +67,7 @@ private:
Handler handler_;
};
}}}}}
}}}}

View File

@@ -6,8 +6,8 @@
#ifndef BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_
#define BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/v1/detail/posix/async_handler.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
@@ -17,8 +17,8 @@
#include <boost/fusion/container/vector/convert.hpp>
#include <boost/process/v1/detail/posix/sigchld_service.hpp>
#include <boost/process/v1/detail/posix/is_running.hpp>
#include <boost/process/detail/posix/sigchld_service.hpp>
#include <boost/process/detail/posix/is_running.hpp>
#include <functional>
#include <type_traits>
@@ -26,7 +26,7 @@
#include <vector>
#include <sys/wait.h>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Executor>
struct on_exit_handler_transformer
@@ -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
@@ -100,7 +100,7 @@ struct io_context_ref : handler_base_ext
{
es->store(val);
for (auto & func : funcs)
func(::boost::process::v1::detail::posix::eval_exit_status(val), ec);
func(::boost::process::detail::posix::eval_exit_status(val), ec);
};
sigchld_service.async_wait(exec.pid, std::move(wh));
@@ -117,9 +117,9 @@ struct io_context_ref : handler_base_ext
private:
boost::asio::io_context &ios;
boost::process::v1::detail::posix::sigchld_service &sigchld_service = boost::asio::use_service<boost::process::v1::detail::posix::sigchld_service>(ios);
boost::process::detail::posix::sigchld_service &sigchld_service = boost::asio::use_service<boost::process::detail::posix::sigchld_service>(ios);
};
}}}}}
}}}}
#endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2016 Klemens D. Morgenstern
// Copyright (c) 2106 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)
@@ -6,12 +6,12 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_IS_RUNNING_HPP
#define BOOST_PROCESS_DETAIL_POSIX_IS_RUNNING_HPP
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/posix/child_handle.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/child_handle.hpp>
#include <system_error>
#include <sys/wait.h>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
// Use the "stopped" state (WIFSTOPPED) to indicate "not terminated".
// This bit arrangement of status codes is not guaranteed by POSIX, but (according to comments in
@@ -34,8 +34,8 @@ 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.
ec = ::boost::process::v1::detail::get_last_error();
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;
}
else if (ret == 0)
@@ -55,7 +55,7 @@ inline bool is_running(const child_handle &p, int & exit_code)
{
std::error_code ec;
bool b = is_running(p, exit_code, ec);
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in is_running");
boost::process::detail::throw_error(ec, "waitpid(2) failed in is_running");
return b;
}
@@ -75,6 +75,6 @@ inline int eval_exit_status(int code)
}
}
}}}}}
}}}}
#endif

View File

@@ -10,34 +10,26 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/v1/detail/posix/file_descriptor.hpp>
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
#include <boost/process/v1/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct null_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
struct null_in : handler_base_ext
{
file_descriptor source{"/dev/null", file_descriptor::read};
std::array<int, 2> get_used_handles()
{
return {{STDIN_FILENO, source.handle()}};
}
public:
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source.handle(), STDIN_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
}}}}}
}}}}
#endif

View File

@@ -11,29 +11,19 @@
#ifndef BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/v1/detail/posix/file_descriptor.hpp>
#include <boost/process/v1/detail/used_handles.hpp>
#include <unistd.h>
#include <array>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct null_out : handler_base_ext, ::boost::process::v1::detail::uses_handles
struct null_out : handler_base_ext
{
file_descriptor sink{"/dev/null", file_descriptor::write};
template <typename Executor>
void on_exec_setup(Executor &e) const;
std::array<int, 3> get_used_handles()
{
const auto pp1 = p1 != -1 ? p1 : p2;
const auto pp2 = p2 != -1 ? p2 : p1;
return {sink.handle(), pp1, pp2};
}
};
template<>
@@ -41,7 +31,7 @@ template<typename Executor>
void null_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
@@ -49,7 +39,7 @@ template<typename Executor>
void null_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
@@ -57,12 +47,12 @@ template<typename Executor>
void null_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
}}}}}
}}}}
#endif

View File

@@ -0,0 +1,35 @@
// Copyright (c) 2016 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_POSIX_ON_EXIT_HPP_
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <system_error>
#include <functional>
namespace boost { namespace process { namespace detail { namespace posix {
struct on_exit_ : boost::process::detail::posix::async_handler
{
std::function<void(int, const std::error_code&)> handler;
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
{
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
{
return handler;
}
};
}}}}
#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */

View File

@@ -10,26 +10,20 @@
#ifndef BOOST_PROCESS_POSIX_PIPE_IN_HPP
#define BOOST_PROCESS_POSIX_PIPE_IN_HPP
#include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
#include <boost/process/v1/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
struct pipe_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
namespace boost { namespace process { namespace detail { namespace posix {
struct pipe_in : handler_base_ext
{
int source;
int sink; //opposite end
pipe_in(int sink, int source) : source(source), sink(sink) {}
std::array<int, 3> get_used_handles()
{
return {{STDIN_FILENO, source, sink}};
}
template<typename T>
pipe_in(T & p) : source(p.native_source()), sink(p.native_sink())
@@ -53,10 +47,8 @@ struct pipe_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
void on_exec_setup(Executor &e) const
{
if (::dup2(source, STDIN_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
if (source != STDIN_FILENO)
::close(source);
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(source);
::close(sink);
}
@@ -93,6 +85,6 @@ struct async_pipe_in : public pipe_in
}
};
}}}}}
}}}}
#endif

View File

@@ -11,28 +11,18 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#include <boost/process/v1/pipe.hpp>
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
#include <array>
#include <boost/process/v1/detail/used_handles.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct pipe_out : handler_base_ext, ::boost::process::v1::detail::uses_handles
struct pipe_out : handler_base_ext
{
int sink;
int source; //opposite end
std::array<int, 4> get_used_handles()
{
const auto pp1 = p1 != -1 ? p1 : p2;
const auto pp2 = p2 != -1 ? p2 : p1;
return {source, sink, pp1, pp2};
}
pipe_out(int sink, int source) : sink(sink), source(source) {}
template<typename T>
@@ -62,10 +52,8 @@ template<typename Executor>
void pipe_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
if (sink != STDOUT_FILENO)
::close(sink);
e.set_error(::boost::process::detail::get_last_error(), "dup3() failed");
::close(sink);
::close(source);
}
@@ -74,10 +62,8 @@ template<typename Executor>
void pipe_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
if (sink != STDOUT_FILENO)
::close(sink);
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
}
@@ -86,11 +72,10 @@ template<typename Executor>
void pipe_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
if ((sink != STDOUT_FILENO) && (sink != STDERR_FILENO))
::close(sink);
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
}
@@ -126,6 +111,6 @@ struct async_pipe_out : public pipe_out<p1, p2>
};
}}}}}
}}}}
#endif

View File

@@ -10,35 +10,31 @@
#ifndef BOOST_PROCESS_POSIX_SEARCH_PATH_HPP
#define BOOST_PROCESS_POSIX_SEARCH_PATH_HPP
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/filesystem.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/filesystem.hpp>
#include <boost/tokenizer.hpp>
#include <string>
#include <stdexcept>
#include <stdlib.h>
#include <unistd.h>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
inline boost::process::v1::filesystem::path search_path(
const boost::process::v1::filesystem::path &filename,
const std::vector<boost::process::v1::filesystem::path> &path)
inline boost::filesystem::path search_path(
const boost::filesystem::path &filename,
const std::vector<boost::filesystem::path> &path)
{
for (const boost::process::v1::filesystem::path & pp : path)
for (const boost::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::v1::filesystem::is_regular_file(p, ec);
bool file = boost::filesystem::is_regular_file(p, ec);
if (!ec && file && ::access(p.c_str(), X_OK) == 0)
return p;
}
return "";
}
}}}}}
}}}}
#endif

View File

@@ -10,23 +10,23 @@
#ifndef BOOST_PROCESS_POSIX_SHELL_PATH_HPP
#define BOOST_PROCESS_POSIX_SHELL_PATH_HPP
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/system/error_code.hpp>
#include <boost/process/v1/filesystem.hpp>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
inline boost::process::v1::filesystem::path shell_path()
inline boost::filesystem::path shell_path()
{
return "/bin/sh";
}
inline boost::process::v1::filesystem::path shell_path(std::error_code &ec)
inline boost::filesystem::path shell_path(std::error_code &ec)
{
ec.clear();
return "/bin/sh";
}
}}}}}
}}}}
#endif

View File

@@ -7,65 +7,24 @@
#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 { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
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::io_context::strand _strand{get_io_context()};
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,34 @@ 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)
h(-1, get_last_error());
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
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
{
@@ -145,7 +128,7 @@ void sigchld_service::_handle_signal(const boost::system::error_code & ec)
}
}
}
}

View File

@@ -11,10 +11,10 @@
#ifndef BOOST_PROCESS_POSIX_SIGNAL_HPP
#define BOOST_PROCESS_POSIX_SIGNAL_HPP
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <signal.h>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
#if defined(__GLIBC__)
using sighandler_t = ::sighandler_t;
@@ -55,16 +55,16 @@ struct sig_init_ : handler_base_ext
}
private:
bool _reset = false;
::boost::process::v1::detail::posix::sighandler_t _old{0};
::boost::process::v1::detail::posix::sighandler_t _handler{0};
::boost::process::detail::posix::sighandler_t _old{0};
::boost::process::detail::posix::sighandler_t _handler{0};
};
struct sig_
{
constexpr sig_() {}
sig_init_ operator()(::boost::process::v1::detail::posix::sighandler_t h) const {return h;}
sig_init_ operator= (::boost::process::v1::detail::posix::sighandler_t h) const {return h;}
sig_init_ operator()(::boost::process::detail::posix::sighandler_t h) const {return h;}
sig_init_ operator= (::boost::process::detail::posix::sighandler_t h) const {return h;}
sig_init_ dfl() const {return SIG_DFL;}
sig_init_ ign() const {return SIG_IGN;}
@@ -74,6 +74,6 @@ struct sig_
}}}}}
}}}}
#endif

View File

@@ -10,30 +10,29 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_START_DIR_HPP
#define BOOST_PROCESS_DETAIL_POSIX_START_DIR_HPP
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <string>
#include <unistd.h>
#include <boost/core/ignore_unused.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Char>
struct start_dir_init : handler_base_ext
{
typedef Char value_type;
typedef std::basic_string<value_type> string_type;
start_dir_init(string_type s) : s_(std::move(s)) {}
start_dir_init(const string_type &s) : s_(s) {}
template <class PosixExecutor>
void on_exec_setup(PosixExecutor&) const
{
boost::ignore_unused(::chdir(s_.c_str()));
::chdir(s_.c_str());
}
const string_type & str() const {return s_;}
private:
string_type s_;
};
}}}}}
}}}}
#endif

View File

@@ -10,33 +10,33 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_TERMINATE_HPP
#define BOOST_PROCESS_DETAIL_POSIX_TERMINATE_HPP
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/posix/child_handle.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/child_handle.hpp>
#include <system_error>
#include <signal.h>
#include <sys/wait.h>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
inline void terminate(const child_handle &p, std::error_code &ec) noexcept
{
if (::kill(p.pid, SIGKILL) == -1)
ec = boost::process::v1::detail::get_last_error();
ec = boost::process::detail::get_last_error();
else
ec.clear();
int status;
::waitpid(p.pid, &status, 0); //should not be WNOHANG, since that would allow zombies.
::waitpid(p.pid, &status, 0); //just to clean it up
}
inline void terminate(const child_handle &p)
{
std::error_code ec;
terminate(p, ec);
boost::process::v1::detail::throw_error(ec, "kill(2) failed");
boost::process::detail::throw_error(ec, "kill(2) failed");
}
}}}}}
}}}}
#endif

View File

@@ -9,11 +9,11 @@
#define BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/fusion/sequence/intrinsic/has_key.hpp>
#include <boost/fusion/container/set/convert.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct use_vfork_ : handler_base_ext
{
@@ -28,6 +28,6 @@ struct shall_use_vfork
};
}}}}}
}}}}
#endif /* BOOST_PROCESS_DETAIL_POSIX_USE_VFORK_HPP_ */

View File

@@ -10,14 +10,14 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_WAIT_FOR_EXIT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_WAIT_FOR_EXIT_HPP
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/posix/child_handle.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/child_handle.hpp>
#include <system_error>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
@@ -32,7 +32,7 @@ inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) no
(ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
ec = boost::process::v1::detail::get_last_error();
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
@@ -44,7 +44,7 @@ inline void wait(const child_handle &p, int & exit_code) noexcept
{
std::error_code ec;
wait(p, exit_code, ec);
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in wait");
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait");
}
template< class Clock, class Duration >
@@ -54,35 +54,11 @@ inline bool wait_until(
const std::chrono::time_point<Clock, Duration>& time_out,
std::error_code & ec) noexcept
{
::sigset_t sigset;
//I need to set the signal, because it might be ignore / default, in which case sigwait might not work.
using _signal_t = void(*)(int);
static thread_local _signal_t sigchld_handler = SIG_DFL;
struct signal_interceptor_t
{
static void handler_func(int val)
{
if ((sigchld_handler != SIG_DFL) && (sigchld_handler != SIG_IGN))
sigchld_handler(val);
}
signal_interceptor_t() { sigchld_handler = ::signal(SIGCHLD, &handler_func); }
~signal_interceptor_t() { ::signal(SIGCHLD, sigchld_handler); sigchld_handler = SIG_DFL;}
} signal_interceptor{};
if (sigemptyset(&sigset) != 0)
{
ec = get_last_error();
return false;
}
if (sigaddset(&sigset, SIGCHLD) != 0)
{
ec = get_last_error();
return false;
}
sigemptyset(&sigset);
sigaddset(&sigset, SIGCHLD);
auto get_timespec =
[](const Duration & dur)
@@ -93,8 +69,8 @@ inline bool wait_until(
return ts;
};
int ret;
int status{0};
pid_t ret;
int status;
struct ::sigaction old_sig;
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
@@ -104,7 +80,6 @@ inline bool wait_until(
}
bool timed_out;
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
do
{
@@ -131,23 +106,16 @@ inline bool wait_until(
pid_t timeout_pid = ::fork();
if (timeout_pid == -1)
{
ec = boost::process::v1::detail::get_last_error();
ec = boost::process::detail::get_last_error();
return true;
}
else if (timeout_pid == 0)
{
auto ts = get_timespec(time_out - Clock::now());
::timespec rem;
while (ts.tv_sec > 0 || ts.tv_nsec > 0)
{
if (::nanosleep(&ts, &rem) != 0)
{
auto err = errno;
if ((err == EINVAL) || (err == EFAULT))
break;
}
ts = get_timespec(time_out - Clock::now());
}
::nanosleep(&ts, &rem);
while (rem.tv_sec > 0 || rem.tv_nsec > 0)
::nanosleep(&rem, &rem);
::exit(0);
}
@@ -157,29 +125,27 @@ inline bool wait_until(
~child_cleaner_t()
{
int res;
::kill(pid, SIGKILL);
::waitpid(pid, &res, 0);
::kill(pid, -15);
::waitpid(pid, &res, WNOHANG);
}
};
child_cleaner_t child_cleaner{timeout_pid};
do
{
int sig_{0};
int ret_sig = 0;
if ((::waitpid(timeout_pid, &status, WNOHANG) != 0)
&& (WIFEXITED(status) || WIFSIGNALED(status)))
return false;
ret = ::sigwait(&sigset, &sig_);
&& (WIFEXITED(status) || WIFSIGNALED(status)))
ret_sig = ::sigwait(&sigset, nullptr);
errno = 0;
if ((sig_ == SIGCHLD) &&
ret = ::waitpid(p.pid, &status, WNOHANG);
if ((ret_sig == SIGCHLD) &&
(old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
old_sig.sa_handler(ret);
ret = ::waitpid(p.pid, &status, WNOHANG);
if (ret == 0) // == > is running
if (ret <= 0)
{
timed_out = Clock::now() >= time_out;
if (timed_out)
@@ -192,7 +158,7 @@ inline bool wait_until(
#endif
if (ret == -1)
ec = boost::process::v1::detail::get_last_error();
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
@@ -210,7 +176,7 @@ inline bool wait_until(
{
std::error_code ec;
bool b = wait_until(p, exit_code, time_out, ec);
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in wait_until");
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_until");
return b;
}
@@ -232,10 +198,10 @@ inline bool wait_for(
{
std::error_code ec;
bool b = wait_for(p, exit_code, rel_time, ec);
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in wait_for");
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_for");
return b;
}
}}}}}
}}}}
#endif

View File

@@ -0,0 +1,209 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// 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_DETAIL_POSIX_WAIT_GROUP_HPP
#define BOOST_PROCESS_DETAIL_POSIX_WAIT_GROUP_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/group_handle.hpp>
#include <chrono>
#include <system_error>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
inline void wait(const group_handle &p, std::error_code &ec) noexcept
{
pid_t ret;
siginfo_t status;
do
{
ret = ::waitpid(-p.grp, &status.si_status, 0);
if (ret == -1)
{
ec = get_last_error();
return;
}
//ECHILD --> no child processes left.
ret = ::waitid(P_PGID, p.grp, &status, WEXITED | WNOHANG);
}
while ((ret != -1) || (errno != ECHILD));
if (errno != ECHILD)
ec = boost::process::detail::get_last_error();
else
ec.clear();
}
inline void wait(const group_handle &p) noexcept
{
std::error_code ec;
wait(p, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait");
}
template< class Clock, class Duration >
inline bool wait_until(
const group_handle &p,
const std::chrono::time_point<Clock, Duration>& time_out,
std::error_code & ec) noexcept
{
::sigset_t sigset;
::siginfo_t siginfo;
sigemptyset(&sigset);
sigaddset(&sigset, SIGCHLD);
auto get_timespec =
[](const Duration & dur)
{
::timespec ts;
ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(dur).count() % 1000000000;
return ts;
};
bool timed_out = false;
int ret;
struct ::sigaction old_sig;
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
{
ec = get_last_error();
return false;
}
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
do
{
auto ts = get_timespec(time_out - Clock::now());
ret = ::sigtimedwait(&sigset, nullptr, &ts);
errno = 0;
if ((ret == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
old_sig.sa_handler(ret);
ret = ::waitpid(-p.grp, &siginfo.si_status, 0); //so in case it exited, we wanna reap it first
if (ret == -1)
{
ec = get_last_error();
return false;
}
//check if we're done
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG);
}
while (((ret != -1) || (errno != ECHILD)) && !(timed_out = (Clock::now() > time_out)));
#else
//if we do not have sigtimedwait, we fork off a child process to get the signal in time
pid_t timeout_pid = ::fork();
if (timeout_pid == -1)
{
ec = boost::process::detail::get_last_error();
return true;
}
else if (timeout_pid == 0)
{
auto ts = get_timespec(time_out - Clock::now());
::setpgid(0, p.grp);
::nanosleep(&ts, nullptr);
::exit(0);
}
struct child_cleaner_t
{
pid_t pid;
~child_cleaner_t()
{
int res;
::kill(pid, -15);
::waitpid(pid, &res, WNOHANG);
}
};
child_cleaner_t child_cleaner{timeout_pid};
do
{
int status;
if ((::waitpid(timeout_pid, &status, WNOHANG) != 0)
&& (WIFEXITED(status) || WIFSIGNALED(status)))
ret = ::sigwait(&sigset, nullptr);
errno = 0;
if ((ret == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
old_sig.sa_handler(ret);
ret = ::waitpid(-p.grp, &siginfo.si_status, 0); //so in case it exited, we wanna reap it first
if (ret == -1)
{
ec = get_last_error();
return false;
}
//check if we're done
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG);
}
while (((ret != -1) || (errno != ECHILD)) && !(timed_out = (Clock::now() > time_out)));
#endif
if (errno != ECHILD)
{
ec = boost::process::detail::get_last_error();
return !timed_out;
}
else
{
ec.clear();
return true; //even if timed out, there are no child proccessess left
}
}
template< class Clock, class Duration >
inline bool wait_until(
const group_handle &p,
const std::chrono::time_point<Clock, Duration>& time_out) noexcept
{
std::error_code ec;
bool b = wait_until(p, time_out, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_until");
return b;
}
template< class Rep, class Period >
inline bool wait_for(
const group_handle &p,
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code & ec) noexcept
{
return wait_until(p, std::chrono::steady_clock::now() + rel_time, ec);
}
template< class Rep, class Period >
inline bool wait_for(
const group_handle &p,
const std::chrono::duration<Rep, Period>& rel_time) noexcept
{
std::error_code ec;
bool b = wait_for(p, rel_time, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_for");
return b;
}
}}}}
#endif

View File

@@ -11,12 +11,12 @@
#ifndef BOOST_PROCESS_DETAIL_INITIALIZERS_THROW_ON_ERROR_HPP
#define BOOST_PROCESS_DETAIL_INITIALIZERS_THROW_ON_ERROR_HPP
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/handler_base.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
namespace boost { namespace process { namespace detail {
struct throw_on_error_ : ::boost::process::v1::detail::handler
struct throw_on_error_ : ::boost::process::detail::handler
{
template <class Executor>
void on_error(Executor& exec, const std::error_code & ec) const
@@ -29,8 +29,8 @@ struct throw_on_error_ : ::boost::process::v1::detail::handler
}
constexpr boost::process::v1::detail::throw_on_error_ throw_on_error;
constexpr boost::process::detail::throw_on_error_ throw_on_error;
}}}
}}
#endif

View File

@@ -0,0 +1,17 @@
// Copyright (c) 2016 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_TRAITS_HPP_
#define BOOST_PROCESS_TRAITS_HPP_
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/traits/async.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/env.hpp>
#include <boost/process/detail/traits/error.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#endif /* BOOST_PROCESS_TRAITS_HPP_ */

View File

@@ -7,15 +7,15 @@
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/traits/decl.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace asio {
class io_context;
}}
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
namespace boost { namespace process { namespace detail {
struct async_tag {};
@@ -27,6 +27,8 @@ template<> struct initializer_tag<::boost::asio::io_context> { typedef async_tag
}}}}
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

View File

@@ -11,11 +11,9 @@
#include <vector>
#include <type_traits>
#include <initializer_list>
#include <boost/process/v1/filesystem.hpp>
#include <boost/process/v1/detail/traits/decl.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
#include <boost/filesystem/path.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
template<typename Char>
struct cmd_or_exe_tag {};
@@ -55,12 +53,12 @@ template<> struct initializer_tag<std::initializer_list<const wchar_t *>> { type
template<> struct initializer_tag<shell_>
{
typedef cmd_or_exe_tag<typename boost::process::v1::filesystem::path::value_type> type;
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
};
template<> struct initializer_tag<boost::process::v1::filesystem::path>
template<> struct initializer_tag<boost::filesystem::path>
{
typedef cmd_or_exe_tag<typename boost::process::v1::filesystem::path::value_type> type;
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
};
template <typename Char>
@@ -80,6 +78,8 @@ template<>
struct initializer_builder<cmd_or_exe_tag<wchar_t>>;
}}}}
}}}
#endif /* BOOST_PROCESS_DETAIL_STRING_TRAITS_HPP_ */

View File

@@ -7,18 +7,18 @@
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/none.hpp>
#include <type_traits>
#if defined(BOOST_POSIX_API)
#include <boost/process/v1/detail/posix/handler.hpp>
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/v1/detail/windows/handler.hpp>
#include <boost/process/detail/windows/handler.hpp>
#endif
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
namespace boost { namespace process { namespace detail {
template<typename T>
@@ -69,6 +69,8 @@ struct valid_argument_list
}}}}
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

View File

@@ -6,10 +6,11 @@
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/v1/detail/traits/decl.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process {
template<typename Char>
class basic_environment;
@@ -22,6 +23,9 @@ namespace detail {
template<typename Char>
struct env_tag {};
template<typename Char> struct env_set;
template<typename Char> struct env_append;
@@ -35,8 +39,8 @@ template<typename Char> struct initializer_tag<env_append<Char>> { typedef env_t
template<typename Char> struct initializer_tag<env_reset<Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<env_init <Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<::boost::process::v1::basic_environment<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<::boost::process::v1::basic_native_environment<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<::boost::process::basic_environment<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<::boost::process::basic_native_environment<Char>> { typedef env_tag<Char> type; };
template<> struct initializer_builder<env_tag<char>>;
template<> struct initializer_builder<env_tag<wchar_t>>;
@@ -44,5 +48,6 @@ template<> struct initializer_builder<env_tag<wchar_t>>;
}
}}}
}}
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */

View File

@@ -7,19 +7,21 @@
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
#include <boost/process/v1/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/process/v1/detail/traits/decl.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
namespace boost { namespace process { namespace detail {
struct error_tag;
template<>
struct initializer_tag<std::error_code>;
}}}}
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

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