2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-20 16:52:14 +00:00

Compare commits

..

634 Commits

Author SHA1 Message Date
Klemens Morgenstern
743f0cca35 close #296. 2023-02-15 02:04:24 +08:00
Klemens Morgenstern
81ad643b00 ec use locations. 2023-02-08 10:02:29 +08:00
Klemens Morgenstern
6fd1200ab7 xproc fixes 2023-02-08 10:02:29 +08:00
Samuel Venable
c7bdccd57e extern process management. 2023-02-08 10:02:29 +08:00
Klemens Morgenstern
d6bcb0014a switched to BOOST_DEPRECATED. 2023-02-06 20:34:16 +08:00
Klemens Morgenstern
e5f0f245bd added clang 3.8. noexcept deduction. 2023-02-06 20:34:16 +08:00
Klemens Morgenstern
a4a3770501 disabled terminate test for freebsd. 2023-02-06 20:34:16 +08:00
Klemens Morgenstern
1e5892b8fb [drone] Removed mlocate dep. 2023-02-06 20:34:16 +08:00
Ivan Efimov
85b29d6442 Fix string construction in native_environment_impl::get 2023-02-06 20:33:12 +08:00
Klemens Morgenstern
b9ee759365 Deprecated wait_for & wait_until. 2023-02-06 20:05:09 +08:00
Klemens Morgenstern
f3b163a933 Switched vector in list of sigclhd_service.
Closes #175
2023-02-06 20:01:15 +08:00
Gary Miguel
be2ae2c3cf fix error message 2023-02-06 19:29:13 +08:00
Klemens
b2f5ebc760 ec fix for search_path with std::filesystem.
closes #287.
2023-02-06 19:09:37 +08:00
Orgad Shaneh
e34557faa0 Fix crash on search_path on Windows when PATHEXT is not found 2023-02-06 19:09:07 +08:00
Klemens Morgenstern
a9f083f45c Update process.cpp 2022-12-13 13:50:03 +08:00
Klemens Morgenstern
b5ab94c932 Disabled some tests for freebsd & added interrupt handling to osx test. 2022-12-13 10:45:47 +08:00
sdarwin
9ceda79fa2 Update metadata 2022-12-13 09:22:13 +08:00
Klemens Morgenstern
68cbeae491 Typo fix. 2022-12-13 09:19:45 +08:00
Klemens Morgenstern
ae778f36a8 Include fixes. 2022-11-11 11:14:46 +08:00
Sam Darwin
0671e4a133 Drone: update freebsd jobs (#274) 2022-11-01 10:40:04 +08:00
Klemens Morgenstern
cbf944c57b using scope-exit limit group_wait. 2022-11-01 03:08:12 +08:00
Klemens Morgenstern
5f2b8c53f4 Disabled limit_fd for freebsd. 2022-11-01 02:58:31 +08:00
Klemens Morgenstern
dac3614a38 group wait test on_scope exit fix. 2022-10-31 12:25:30 +08:00
Klemens Morgenstern
2fc71ca0a3 Disabled pdfork by default, bc of asio errors. 2022-10-31 11:23:49 +08:00
Klemens Morgenstern
404682d75d Increased timeout for sporadically failing test. 2022-10-31 11:21:48 +08:00
Klemens Morgenstern
9fbbdc3421 Merge pull request #276 from Flamefire/patch-1
Update .drone.star
2022-10-23 11:21:09 +08:00
Alexander Grund
3df0009a2f Update .drone.star
Remove the `image` param which is superflous, misleading and may become an error. See https://github.com/boostorg/boost-ci/pull/189

[skip ci]
2022-10-22 11:26:04 +02:00
Klemens Morgenstern
ecb384b253 Improved error message for OSX. 2022-10-21 12:03:31 +08:00
Klemens Morgenstern
05bce942c1 passing a pipe into sh test. 2022-10-12 11:54:05 +08:00
Klemens Morgenstern
dcf5d8ce41 Added return_type to async_result<code_as_error_t> 2022-10-12 10:54:30 +08:00
Klemens Morgenstern
4209f8ee6e Minor bugfixes 2022-10-12 01:12:28 +08:00
Klemens Morgenstern
d9513269cc Enabled freebsd build 2022-10-11 21:03:33 +08:00
Klemens
293f28dab6 Fixed async_system. 2022-09-20 13:45:43 +08:00
Klemens
fe1b629b5d Added bind_launcher. 2022-09-18 22:13:57 +08:00
Klemens
278fa57214 Added code_as_error completion handler. 2022-09-18 17:56:47 +08:00
Klemens Morgenstern
1addfba12e Added WIN32_LEAN_AND_MEAN to cmake 2022-09-17 20:39:01 +08:00
Klemens Morgenstern
4cc469b2a4 Merge pull request #252 from grtowel1510f/patch-1
fix issue #251 - fix simple shell command in posix
2022-09-14 11:38:37 +08:00
Klemens Morgenstern
6e4d1e29d2 Merge pull request #271 from boostorg/shell_v2
Shell v2
2022-09-02 20:30:03 +08:00
Klemens Morgenstern
dada865fd0 Merge pull request #269 from boostorg/klemens-morgenstern-patch-2
Closes #266
2022-09-02 20:29:20 +08:00
Klemens Morgenstern
380dd1b00f Merge pull request #268 from boostorg/klemens-morgenstern-patch-1
Closes #267
2022-09-02 20:28:50 +08:00
Klemens
7832cb6af3 Shell(posix) fixes. 2022-09-02 18:43:35 +08:00
Klemens Morgenstern
68f4c50be9 Exeuction support for shell. 2022-09-02 18:25:40 +08:00
Klemens Morgenstern
cd226a7616 Implemented shell on windows. 2022-09-02 17:05:49 +08:00
Klemens Morgenstern
4243ce72f8 Windows bugfixes. 2022-09-02 16:46:45 +08:00
Klemens
9065833e61 Added shell class. 2022-08-31 23:54:22 +08:00
Klemens Morgenstern
7cb7af6c8b Closes #267 2022-08-31 15:40:57 +08:00
Klemens Morgenstern
90cbe7cec0 Closes #266 2022-08-31 15:35:51 +08:00
Klemens
df33c1ad7b Fixed unsafe post-fork allocs for fd_whitelist. 2022-08-31 15:35:41 +08:00
Klemens
bbabea30dd Added reaping child for execve error, closes #265. 2022-08-31 15:35:41 +08:00
Klemens
c1b6eb4eb8 Merge branch 'develop' 2022-08-19 00:04:30 +08:00
Klemens
4ef1792b0a Typo fix. 2022-08-19 00:04:16 +08:00
Klemens
1a6956134a Merge branch 'develop' 2022-08-19 00:01:33 +08:00
Klemens Morgenstern
eb6bce0910 Merge pull request #264 from hebasto/220802-mingw
Fix compiling for MinGW-w64 using std::filesystem
2022-08-18 23:57:10 +08:00
Klemens
9a1c6991c9 Fixed cmake build 2022-08-18 22:02:33 +08:00
Klemens
352b6cf89f Added github action yml 2022-08-18 21:17:42 +08:00
Klemens
317b1b7c62 Added Boost::process to link_libraries in CMake. 2022-08-17 18:12:55 +08:00
Hennadii Stepanov
a7b65bfc44 Fix compiling for MinGW-w64 using std::filesystem 2022-08-02 09:36:44 +01:00
Klemens Morgenstern
ee945a6b95 Merge pull request #262 from boostorg/develop
Master update 1.80
2022-06-24 01:23:56 +08:00
Klemens Morgenstern
992de7b6ea Merge pull request #261 from boostorg/develop-merge
Master update 1.80
2022-06-23 10:30:01 +08:00
Klemens Morgenstern
6e597b5c8a Merge branch 'master' into develop-merge 2022-06-20 02:38:26 +08:00
Klemens
1a1d677d76 Closes #202 2022-06-11 15:00:32 +08:00
Klemens
c1fb7758b2 Added missing incldue 2022-06-11 13:25:27 +08:00
Klemens Morgenstern
e24af699cf Merge pull request #257 from boostorg/v2
V2
2022-06-11 13:15:49 +08:00
Klemens
e585864cf4 Changed default whitelist to stdio 2022-06-11 12:17:36 +08:00
Klemens
69a0615530 Fixed times in test 2022-06-10 22:04:01 +08:00
Klemens
26f4584e1e Increased wait time for group_wait 2022-06-10 19:52:41 +08:00
Klemens
43e845a691 Fixed execute_op error 2022-06-08 14:58:06 +08:00
Klemens
4d59330067 Added EINTR handling for OSX 2022-06-07 12:06:33 +08:00
Klemens
f59c1c180e Removed asserts around printf. 2022-06-07 11:38:03 +08:00
Klemens
618c931188 Added more additional diagnostics to test 2022-06-07 11:16:09 +08:00
Klemens
727881649c Typo fixes 2022-06-07 10:17:23 +08:00
Klemens
dd4bf8d857 Debugging env 2022-06-07 00:56:03 +08:00
Klemens
9d006cdd94 Improved environment tests to not drop other vars 2022-06-07 00:19:34 +08:00
Klemens
442a6ed8d8 Fixed fork_parent 2022-06-06 23:48:35 +08:00
Klemens
686945f46f Fixed signal completion. 2022-06-06 13:32:48 +08:00
Klemens
8979836f32 Added BOOST_TEST_IGNORE_SIGCHLD 2022-06-06 01:19:39 +08:00
Klemens
4dfc1bd4fd Fixed waitpid in the async_wait 2022-06-05 22:00:36 +08:00
Klemens
f90edf44e1 temporarily ignoring close_all_fds for diagnostics 2022-06-05 20:45:20 +08:00
Klemens
f56e42fd2e Added diagnostic for CI 2022-06-05 18:24:01 +08:00
Klemens
b9420be981 removed usin ""s 2022-06-05 17:47:37 +08:00
Klemens
548ea7d999 Process env test fixes 2022-06-05 16:54:52 +08:00
Klemens
f453d93e83 Set pth in env test to absolute 2022-06-05 16:09:24 +08:00
Klemens
693a33010d Added more logs to tests 2022-06-05 15:59:09 +08:00
Klemens
faad3fa4df More fixes 2022-06-05 15:36:04 +08:00
Klemens
4e2e580b4c Multiple non-linux fixes 2022-06-05 14:58:00 +08:00
Klemens
d60ea9c4d3 environ fix for apple 2022-06-05 02:39:41 +08:00
Klemens
a911da2c1f More CI-driven test fixes 2022-06-05 02:35:49 +08:00
Klemens
f0c98aa97f Multiple fixes 2022-06-05 02:11:24 +08:00
Klemens
062ac9beb2 Added limit_fd functionality 2022-06-05 01:55:28 +08:00
Klemens
fb48747fc8 Another cstring_ref 2022-06-04 23:26:14 +08:00
Klemens
f2a0367605 Minor buf fixes 2022-06-04 23:00:13 +08:00
Klemens
3163496b70 Added documentation 2022-06-04 21:19:40 +08:00
Klemens
4e64224ef1 Starlark fix & added alias for subdirector 2022-06-04 17:21:28 +08:00
Klemens
25669a78de Removed superfluous builds 2022-06-04 16:59:40 +08:00
Klemens
910192e2ad Added reference doc for v2. 2022-06-04 16:44:57 +08:00
Klemens
15984e3288 Enabled freebsd 2022-06-04 12:40:41 +08:00
Klemens
6aa704c208 Added comments 2022-06-04 12:35:20 +08:00
Klemens
62d40caddd Added sleep test. 2022-06-03 11:54:34 +08:00
Klemens
d63d502b40 Added v2 examples and some doc comments. 2022-06-03 11:03:30 +08:00
Klemens Morgenstern
3a401dd306 Merge pull request #253 from Flamefire/patch-1
Remove superflous calls in CMakeLists
2022-06-03 01:05:51 +08:00
Klemens
3893a96c6e Added hashs for environment. 2022-06-02 04:01:24 +08:00
Klemens
76c393fb8e Added execute & async_execute. 2022-06-01 16:07:38 +08:00
Klemens
4fce3c8184 Added popen. 2022-06-01 14:51:56 +08:00
Klemens
54b698dcbd Added special treatment for pipes in stdio. 2022-06-01 13:48:51 +08:00
Klemens
1f45677518 Added exit-code error category. 2022-06-01 12:43:57 +08:00
Klemens
1493e365ed FreeBSD fixes. 2022-05-31 13:24:36 +08:00
Klemens
5e5e0b8641 Minor doc additions. 2022-05-31 12:55:14 +08:00
Klemens Morgenstern
932ac3038e Added tests for windows extra launchers. 2022-05-31 10:29:39 +08:00
Klemens Morgenstern
00bc1ccf47 Fixed windows extra launchers. 2022-05-30 11:47:58 +08:00
Klemens
257da990d5 Added pidfd_open impl for linux. 2022-05-30 01:41:20 +08:00
Klemens Morgenstern
c6a812e401 Added test & fixed some found bugs. 2022-05-29 14:51:44 +08:00
Klemens Morgenstern
f93290d3d4 Completed windows port to v2 from asio. 2022-05-29 02:38:37 +08:00
Klemens
a46ab25046 Added utf8 on linux. 2022-05-26 16:58:20 +08:00
Klemens Morgenstern
1b61ba6ea7 Fixed InputIt overlaods. 2022-05-26 15:59:49 +08:00
Klemens Morgenstern
27f79e1774 Added missing files. 2022-05-26 15:54:21 +08:00
Klemens Morgenstern
0fbfa1cdc1 Switched to pure utf8 support on windows. 2022-05-26 15:01:01 +08:00
Alexander Grund
47c4496d05 Remove superflous calls in CMakeLists
The find_package is not required, as the dependencies are done using the superproject build
The include_directories is already there: target_include_directories
2022-05-23 16:12:28 +02:00
grtowel1510f
8a61f8daa3 fix issue #251 - fix simple shell command in posix
see issue #251 for description.
2022-05-21 14:59:37 +00:00
Klemens Morgenstern
c473251709 Added windows environment stuff. 2022-05-20 12:25:32 +08:00
Klemens
7bdf11f550 Added posix first environment draft. 2022-05-20 01:52:48 +08:00
Klemens
dbcc946dac Added early return for empty input. 2022-05-19 19:24:03 +08:00
Klemens
e0e801cbb4 Added the pid get_id function and pid_type type alias. 2022-05-19 19:24:03 +08:00
Klemens
4943c74e8e First steps for v2
- Added utility functions
 - cstring_ref
 - codecvt functions
2022-05-19 19:24:01 +08:00
Klemens
0733217423 Added boost_process_ prefix to test/CMakeFiles.txt. 2022-05-19 19:20:53 +08:00
Klemens
397e685053 Updated readme. 2022-05-19 17:20:36 +08:00
Klemens Morgenstern
610b337fa3 Drone & Multple fix (#250)
Squash after invalid branch & merge conflict.

* Fixed file_descriptor move assignment operator to return a reference to 'this'. Issue # 219

* Returning *this instead of erroneous *this. Issue # 219

* Removed unneeded WNOHANG.

* Closes boostorg/process#190

* Closes boostorg/process#121

* Attempting to fix wchar_t build error on circle.

* Closes boostorg/process#197.

* Changed child(pid_t) signature.

* Multiple fixes.

* Closes boostorg/process#189.

* Closes boostorg/process#191.

* Added missing work guard on windows.

* Trying to catch windows early complete.

* Increased log level on windows.

* Multiple windows test fixes

* Removed overly constraint tests.

* fix missing headers

* Closes klemens-morgenstern/boost-process#218

* Update executor.hpp

explicit cast to int to silence this: `error: non-constant-expression cannot be narrowed from type 'unsigned long' to 'int' in initializer list [-Wc++11-narrowing]`

* Fix posix implementation of move constructor/assignment in file_descriptor

* Adjust docs `@boost` relative paths

* Fixed UB for large environment names.

* Closes boostorg/process#207.

* Drone setup

* Added include for filesystem::fstream.

* Disabled useless tests.

* Fixed environment length checks.

* Pipe test & warning fixes.

* Disabled warnings & added windows include fix.

* More test fixes.

* Removed some tests from apple build.

* Removed some tests from apple build.

* Disabled OSX tests via build script & fixed windows examples.

* TSA fix attempt.

Co-authored-by: James Baker <james.baker@bullochtech.com>
Co-authored-by: silent <silent@symica.com>
Co-authored-by: ikrijan <62850248+ikrijan@users.noreply.github.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Co-authored-by: alandefreitas <alandefreitas@gmail.com>
2022-05-19 17:00:15 +08:00
Klemens Morgenstern
bbb7dced5c Merge pull request #245 from hgkjshegfskef/develop
Fix missing include
2022-05-19 14:50:17 +08:00
ikrijan
ab82e78c3d Update executor.hpp
explicit cast to int to silence this: `error: non-constant-expression cannot be narrowed from type 'unsigned long' to 'int' in initializer list [-Wc++11-narrowing]`
2022-05-18 21:15:44 +08:00
silent
a295cd8635 Closes klemens-morgenstern/boost-process#218 2022-05-18 21:15:44 +08:00
silent
b8bcfa2e11 fix missing headers 2022-05-18 21:15:44 +08:00
Klemens Morgenstern
ed659bf129 Removed overly constraint tests. 2022-05-18 21:15:44 +08:00
Klemens Morgenstern
4cadf1d333 Multiple windows test fixes 2022-05-18 21:15:44 +08:00
Klemens
220bec28bf Increased log level on windows. 2022-05-18 21:15:44 +08:00
Klemens
ee3c2cfeeb Trying to catch windows early complete. 2022-05-18 21:15:44 +08:00
Klemens
221550a848 Added missing work guard on windows. 2022-05-18 21:15:44 +08:00
Klemens
b7821ccf09 Closes boostorg/process#191. 2022-05-18 21:15:44 +08:00
Klemens
1f464b3eb5 Closes boostorg/process#189. 2022-05-18 21:15:44 +08:00
Klemens
5abb4f4a23 Multiple fixes. 2022-05-18 21:15:44 +08:00
Klemens
722bd31cdb Changed child(pid_t) signature. 2022-05-18 21:15:44 +08:00
Klemens
e358dc52a2 Closes boostorg/process#197. 2022-05-18 21:15:44 +08:00
Klemens
d54788a385 Attempting to fix wchar_t build error on circle. 2022-05-18 21:15:44 +08:00
Klemens
4a5d711c86 Closes boostorg/process#121 2022-05-18 21:15:44 +08:00
Klemens
d11e327ab0 Closes boostorg/process#190 2022-05-18 21:15:44 +08:00
Klemens
edaf70a7a7 Removed unneeded WNOHANG. 2022-05-18 21:15:44 +08:00
Klemens Morgenstern
dc8ba65c77 Merge pull request #249 from ikrijan/patch-1
Update executor.hpp
2022-05-13 23:49:56 +08:00
ikrijan
ea26c7b2bd Update executor.hpp
explicit cast to int to silence this: `error: non-constant-expression cannot be narrowed from type 'unsigned long' to 'int' in initializer list [-Wc++11-narrowing]`
2022-05-13 16:50:25 +02:00
hgkjshegfskef
4d1c438d91 Fix missing include 2022-04-20 17:36:20 +02:00
Klemens Morgenstern
d231979a6c Merge pull request #233 from alandefreitas/boost_rel_paths
Adjust documentation relative paths
2021-12-31 21:50:06 +08:00
alandefreitas
a3e8600e40 Adjust docs @boost relative paths 2021-12-28 19:41:40 -03:00
Klemens Morgenstern
c1d0f1be76 Merge pull request #227 from x-santiaga-x/patch-1
Closes klemens-morgenstern/boost-process#218
2021-10-29 18:59:23 +08:00
Klemens Morgenstern
10c93d88a1 Merge pull request #228 from x-santiaga-x/patch-2
Fix missing headers
2021-10-29 18:55:03 +08:00
silent
5f80e72e9c Closes klemens-morgenstern/boost-process#218 2021-10-29 13:24:19 +03:00
silent
d26ef52519 fix missing headers 2021-10-29 12:18:20 +03:00
Klemens Morgenstern
f4d2c260d4 Merge pull request #231 from klemens-morgenstern/develop
Master update
2021-10-27 17:36:17 +08:00
Klemens Morgenstern
e32651a260 Removed overly constraint tests. 2021-10-27 12:23:18 +08:00
Klemens Morgenstern
71aa7d9c00 Merge commit 'ed3b066' into develop 2021-10-27 11:45:43 +08:00
Klemens Morgenstern
ed3b066da1 Multiple windows test fixes 2021-10-27 11:43:33 +08:00
Klemens
83380dad79 Increased log level on windows. 2021-10-26 23:53:02 +08:00
Klemens
5ad5e82577 Trying to catch windows early complete. 2021-10-22 19:42:53 +08:00
Klemens
3acc1a3fa8 Added missing work guard on windows. 2021-10-16 15:46:11 +08:00
Klemens
9bb088ed5d Closes boostorg/process#191. 2021-10-15 10:57:01 +08:00
Klemens
cd4ef692e1 Closes boostorg/process#189. 2021-10-15 10:54:38 +08:00
Klemens
268795f3c0 Multiple fixes. 2021-10-14 17:41:27 +08:00
Klemens
f8f9c2323c Changed child(pid_t) signature. 2021-10-14 15:36:07 +08:00
Klemens
0c3ded6636 Closes boostorg/process#197. 2021-10-14 15:36:07 +08:00
Klemens
20b328dbf1 Attempting to fix wchar_t build error on circle. 2021-10-14 14:48:23 +08:00
Klemens
a60203dac3 Closes boostorg/process#121 2021-10-14 14:48:23 +08:00
Klemens
6d08cb369e Closes boostorg/process#190 2021-10-14 14:28:07 +08:00
Klemens
8dc5ee22f5 Merge remote-tracking branch 'boostorg/develop' into develop 2021-10-14 14:20:27 +08:00
Klemens Morgenstern
f7053f31ec Merge pull request #194 from Shauren/fix-linux-file-descriptor-move
Fix posix implementation of move constructor/assignment in file_descriptor
2021-10-14 14:20:18 +08:00
Klemens
a13a60d428 Removed unneeded WNOHANG. 2021-10-14 14:19:32 +08:00
Klemens Morgenstern
fa2a522ef2 Merge pull request #220 from odhinnsrunes/file_descriptor_move_assign_fix
Fixed file_descriptor move assignment operator returns a reference to this.
2021-10-14 14:14:23 +08:00
Klemens Morgenstern
2b39b56efb Merge pull request #208 from jorj1988/extend_hpp_include_memory
Add include to extend.hpp for memory.
2021-10-09 16:23:38 +08:00
Klemens Morgenstern
5a283e5200 Merge pull request #218 from Val-test/develop
Fix child construction from pid_t (it takes reference to pid_t for no reason).
2021-10-09 16:23:26 +08:00
Klemens Morgenstern
3d5f449052 Merge pull request #223 from apolukhin/patch-1
Remove trailing whitespace
2021-10-09 16:22:13 +08:00
Antony Polukhin
aefb990a7a Remove triling whitespace 2021-10-03 10:30:10 +03:00
Valentyn Pavliuchenko
3d092498b2 Fix child construction from pid_t (it takes reference to pid_t for no reason). 2021-08-19 19:54:42 +03:00
Klemens Morgenstern
7d7476343a Merge pull request #215 from Eddie-cz/develop
Missing include added
2021-08-08 20:09:20 +08:00
Eddie-cz
e08374ed95 Update wchar_t.hpp 2021-08-02 10:49:42 +02:00
Klemens Morgenstern
155ebdcf1f Merge pull request #181 from orgads/patch-1
Fix cross-compile linux->mingw
2021-07-05 14:48:01 +08:00
Orgad Shaneh
a9925a5d6d Fix cross-compile linux->mingw
Headers are lower case.
2021-07-05 09:17:16 +03:00
Peter Dimov
741d3f4a07 Add CMakeLists.txt 2021-05-28 02:42:50 +03:00
Peter Dimov
f195243a81 Merge branch 'master' into develop 2021-05-28 02:40:12 +03:00
George Pimm
8c5ab02192 Add include to extend.hpp for memory.
extend.hpp uses std::shared_ptr as a member but does not include it
2021-04-14 13:52:46 +01:00
Shauren
b526ac7ce5 Fix posix implementation of move constructor/assignment in file_descriptor 2021-01-16 17:02:41 +01:00
Klemens Morgenstern
8222a57744 Merge pull request #192 from eldiener/develop
Add "cxxstd" json field. The "cxxstd" json field is being added to ea…
2020-12-17 17:35:23 +08:00
Edward Diener
aa3ae06ab7 Add "cxxstd" json field. The "cxxstd" json field is being added to each Boost library's meta json information for libraries whose minumum C++ standard compilation level is C++11 on up. The value of this field matches one of the values for 'cxxstd' in Boost.Build. The purpose of doing this is to provide information for the Boost website documentation for each library which will specify the minimum C++ standard compilation that an end-user must employ in order to use the particular library. This will aid end-users who want to know if they can successfully use a Boost library based on their C++ compiler's compilation level, without having to search the library's documentation to find this out. 2020-12-16 10:32:08 -05:00
Klemens Morgenstern
1b4d67170f Merge pull request #177 from giomasce-throwaway/develop
Fix typo in copyright headers.
2020-10-29 21:17:53 +04:00
Klemens Morgenstern
e3594034eb Merge pull request #179 from nre-ableton/nre/develop/posix-default-locale
Return default locale on POSIX systems
2020-10-29 21:17:34 +04:00
Klemens Morgenstern
ee983eba64 Merge pull request #171 from Shauren/fix-windows-h
Fix windows builds that don't include Windows.h
2020-10-29 21:17:05 +04:00
nre
0eb4685558 Return default locale on POSIX systems
The comment here is incorrect; an empty locale is not the correct
behavior here and will cause exceptions to be thrown in other code.
Instead a locale object with the default constructor should be
returned, not one created with an empty string. This is a known issue
which was originally reported here:

https://svn.boost.org/trac10/ticket/4688

The issue claims to have been fixed in 7bb19f9 (see also:
https://svn.boost.org/trac10/changeset/72855).

However, this only fixes the issue for FreeBSD and not other POSIX
platforms. This patch is based on the one originally submitted here:

https://svn.boost.org/trac10/attachment/ticket/4688/boost_filesystem.patch
2020-10-16 10:07:14 +02:00
Giovanni Mascellani
7cf1a3b8e6 Fix typo in copyright headers. 2020-10-09 15:49:45 +02:00
Klemens Morgenstern
c0a1a82361 Merge pull request #173 from alloutlife/issue_121
Adding bug fix to resolve issue #121
2020-09-22 01:46:03 +03:00
Alexey Kushnarev
532951902f Adding bug fix to resolve issue #121 2020-09-14 12:16:14 +03:00
Shauren
642c2d369f Use ::boost::winapi::DWORD_ instead of global DWORD 2020-09-03 13:21:36 +02:00
Shauren
d7a721ee0d Removed __kernel_entry usage from Nt* function typedefs, is is part of SAL annoations, not neccessary for proper signature 2020-09-03 13:21:02 +02:00
James Baker
baa8d3fe7c Returning *this instead of erroneous *this. Issue # 219 2020-08-28 12:43:16 -04:00
James Baker
42bdfb5545 Fixed file_descriptor move assignment operator to return a reference to 'this'. Issue # 219 2020-08-28 11:13:39 -04:00
Klemens Morgenstern
0f053c323e Merge pull request #167 from zaucy/move_assignment_return_value_fix
Added return *this in move assignment operator
2020-08-03 16:29:09 +07:00
Ezekiel Warren
036c9fc4d1 Added return *this in move assignment operator 2020-08-01 18:53:20 -07:00
Klemens Morgenstern
b2a96a3e13 Merge pull request #215 from klemens-morgenstern/develop
Develop merge
2020-06-28 23:25:58 +07:00
Klemens David Morgenstern
1dbb3626a9 Changed async system test to let the subprocess wait, to avoid a race condition 2020-06-28 22:06:07 +07:00
Klemens David Morgenstern
d79e1f2443 changed limit_fd test to use stdin 2020-06-28 16:29:07 +07:00
Klemens David Morgenstern
605dcd19d8 Removed faulty reinterpret cast from posix test 2020-06-28 15:09:58 +07:00
Klemens David Morgenstern
6b6a6fa61c Fixed limit_fd windows test the current broke if stdout and stderr were the same, as a CI system might do 2020-06-27 14:21:53 +07:00
Klemens David Morgenstern
295e2bdd9c Merge branch 'develop' of github.com:boostorg/process into develop 2020-06-27 12:55:04 +07:00
Klemens Morgenstern
dd1513846b Merge pull request #165 from chriskohlhoff/standard-executors-changes
Changes required to compile with new Asio executors model
2020-06-27 12:54:34 +07:00
Christopher Kohlhoff
7a94abfaf2 Use strand<> rather than legacy executor io_context::strand. 2020-06-24 19:52:52 +10:00
Christopher Kohlhoff
b55a09479c New name for polymorphic executor. Remove unused "old services" code. 2020-06-24 19:52:52 +10:00
Klemens David Morgenstern
5afb20760c Fixed exe-args style for windows 2020-05-21 18:48:04 +07:00
Klemens Morgenstern
eec87e1dd9 Update child_handle.hpp 2020-05-21 01:38:37 +07:00
Klemens Morgenstern
f250a33fb4 Switched to report.py script 2020-05-20 21:50:37 +07:00
Klemens David Morgenstern
570cf83a96 Merge branch 'develop' of github.com:boostorg/process into develop 2020-05-20 21:07:49 +07:00
Klemens David Morgenstern
d52d244f83 Closes boostorg/process#134 2020-05-20 21:00:50 +07:00
Klemens Morgenstern
04ab646f12 Merge pull request #136 from jonesmz/patch-10
Fix "comparison between signed and unsigned" warning
2020-05-20 20:51:31 +07:00
Klemens David Morgenstern
31c65b5442 Closes boostorg/process#127 2020-05-20 20:49:46 +07:00
Klemens Morgenstern
ebbb6d8b36 Merge pull request #126 from Martchus/fix-on_exit-example
Pass io_context in on_exit example
2020-05-20 20:44:42 +07:00
Klemens Morgenstern
b9c0140a26 Merge pull request #119 from licekto/double-closed-fd-fixed
Fix for double closed FD: https://github.com/boostorg/process/issues/105
2020-05-20 20:44:02 +07:00
Klemens Morgenstern
27f587a4be Merge pull request #137 from jonesmz/patch-11
Fix async_system_future.cpp:60:9: warning: variable ‘exit_code’ set but not used
2020-05-20 20:40:07 +07:00
Klemens Morgenstern
7f6061c956 Merge pull request #138 from jonesmz/patch-12
Fix "comparison between signed and unsigned" warning
2020-05-20 20:38:58 +07:00
Klemens David Morgenstern
2f32c95341 Closes boostorg/process#145 and boostorg/process#188 2020-05-20 20:33:55 +07:00
Klemens Morgenstern
a8029fc191 Merge pull request #140 from jonesmz/patch-14
Fix comparison between signed and unsigned integer expressions
2020-05-20 20:15:01 +07:00
Klemens Morgenstern
9f4bd9bce3 Merge pull request #139 from jonesmz/patch-13
Fix warning: unused variable ‘env’
2020-05-20 20:14:53 +07:00
Klemens Morgenstern
71f844c24f Merge pull request #149 from jonesmz/patch-22
file_in.hpp:29:17: warning: suggest braces around initialization of subobject
2020-05-20 20:09:30 +07:00
Klemens David Morgenstern
b0b6d67e6f Closes boostorg/process#144 2020-05-20 20:09:14 +07:00
Klemens David Morgenstern
3a2576a4d8 Merge branch 'develop' of github.com:boostorg/process into develop 2020-05-20 20:07:47 +07:00
Klemens Morgenstern
34eaa262dd Merge pull request #147 from jonesmz/patch-20
close_out.hpp:25:52: warning: suggest braces around initialization of subobject
2020-05-20 20:06:46 +07:00
Klemens Morgenstern
ce3b3d8f99 Merge pull request #148 from jonesmz/patch-21
null_in.hpp:28:17: warning: suggest braces around initialization of s…
2020-05-20 20:06:35 +07:00
Klemens Morgenstern
429f2ba95c Merge pull request #150 from jonesmz/patch-23
pipe_in.hpp:30:17: warning: suggest braces around initialization of subobject
2020-05-20 20:05:29 +07:00
Klemens Morgenstern
0c2e7387c8 Merge pull request #152 from Naios/msvcfix
[Build Fix] Workaround for a MSVC 14.1 and 14.2 compiler bug
2020-05-20 20:05:22 +07:00
Klemens Morgenstern
2a2ea4b92d Merge pull request #146 from jonesmz/patch-19
Fix example/intro.cpp includes
2020-05-20 20:01:47 +07:00
Klemens David Morgenstern
873ab2558d Closes boostorg/process#153 2020-05-20 19:58:23 +07:00
Klemens David Morgenstern
03571d4eaf Merge branch 'develop' of github.com:boostorg/process into develop 2020-05-20 19:44:42 +07:00
Klemens Morgenstern
46ab3ba9b8 Merge pull request #158 from acronce/develop
Add the lambda declarator needed to disambiguate the multiple return …
2020-05-20 19:39:24 +07:00
Allen Cronce
3aba1f6eb1 Add the lambda declarator needed to disambiguate the multiple return values from these lambda functions as a bool. Before this change the return of a "false" was interpreted as an int, but the second return is a bool. This caused the following compile error when accessing environment variables under Xcode 11.4.1: Return type 'bool' must match previous return type 'int' when lambda expression has unspecified explicit return type 2020-05-13 07:25:36 -07:00
Denis Blank
44771769fa Workaround for a MSVC 14.1 and 14.2 compiler bug
* boost\include\boost/process/child.hpp(35): error C2600:
    'boost::process::child::child': cannot define a compiler-generated
    special member function (must be declared in the class first)
* Introduced by 8541cae
* See boostorg/process#113
2020-03-23 22:35:59 +01:00
Michael Jones
8704416941 pipe_in.hpp:30:17: warning: suggest braces around initialization of subobject 2020-03-13 02:57:56 -05:00
Michael Jones
f48392399f file_in.hpp:29:17: warning: suggest braces around initialization of subobject 2020-03-13 02:57:11 -05:00
Michael Jones
80f81117aa null_in.hpp:28:17: warning: suggest braces around initialization of subobject 2020-03-13 02:56:28 -05:00
Michael Jones
9cff55215d close_out.hpp:25:52: warning: suggest braces around initialization of subobject 2020-03-13 02:55:35 -05:00
Michael Jones
2e4b3c2406 Fix example/intro.cpp includes 2020-03-13 02:26:10 -05:00
Michael Jones
b510b6a9d9 Fix comparison between signed and unsigned integer expressions 2020-03-13 01:22:01 -05:00
Michael Jones
046b96186f Fix warning: unused variable ‘env’ 2020-03-13 01:20:10 -05:00
Michael Jones
1df2e67bc4 Fix "comparison between signed and unsigned" warning 2020-03-13 01:18:11 -05:00
Michael Jones
6cf69e2797 Fix async_system_future.cpp:60:9: warning: variable ‘exit_code’ set but not used 2020-03-13 01:11:46 -05:00
Michael Jones
d3e4cbf3b3 Fix "comparison between signed and unsigned" warning 2020-03-13 01:03:31 -05:00
Martchus
e67e49c891 Pass io_context in on_exit example
The description already states that an io_context needs
to be passed. This change is adjusting the example accordingly.
2020-03-08 21:17:54 +01:00
Licek Tomáš
29a43b17e4 Fix for double closed FD: https://github.com/boostorg/process/issues/105 2020-02-04 10:22:11 +01:00
Klemens David Morgenstern
6d10c3a807 Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2020-01-26 15:18:00 +07:00
Klemens Morgenstern
668579ed6f Merge pull request #110 from sorayuki/patch-1
Fix memory over-write in pipe.hpp
2020-01-26 15:17:27 +07:00
Klemens Morgenstern
8af828cd43 Merge pull request #73 from fkonvick/develop
Fix double quotes processing on Windows
2020-01-26 15:16:39 +07:00
Klemens Morgenstern
590cc10b42 Merge pull request #75 from brunom/patch-1
typo
2020-01-26 15:15:07 +07:00
Klemens Morgenstern
3bc11ce3ac Merge pull request #113 from jonesmz/patch-1
Use = default for default constructor
2020-01-26 15:14:52 +07:00
Klemens Morgenstern
603441ecc3 Merge pull request #114 from jonesmz/patch-2
Use static constexpr instead of const for compile-time constant variable
2020-01-26 15:14:32 +07:00
Klemens Morgenstern
612a953369 Merge pull request #115 from jonesmz/patch-3
Use move construction for struct start_dir
2020-01-26 15:13:15 +07:00
Klemens Morgenstern
1554773d39 Merge pull request #213 from dermojo/develop
Documentation fixes
2020-01-26 15:10:44 +07:00
Daniel Evers
dd003bf2b0 Correct some typos etc. 2020-01-05 17:33:59 +01:00
Klemens Morgenstern
0341e08297 Merge pull request #212 from klemens-morgenstern/develop
Master update
2019-12-29 04:37:11 +08:00
Klemens David Morgenstern
5853345715 trying to fix appveyor to upload to report.ci 2019-12-29 04:16:44 +08:00
Klemens David Morgenstern
41f8b1cf00 removed sigtimedwait for group_wait 2019-12-29 03:39:32 +08:00
Klemens David Morgenstern
56ae00c7a4 typo fix 2019-12-29 00:48:51 +08:00
Klemens David Morgenstern
f58882c956 small travis fixes, hopefully fixing the build 2019-12-29 00:42:21 +08:00
Klemens David Morgenstern
3f14ebc755 changed report script 2019-12-29 00:04:26 +08:00
Michael Jones
1502de1001 Use move construction for struct start_dir 2019-12-05 17:48:17 -06:00
Michael Jones
8541cae396 Update child_decl.hpp 2019-12-05 12:59:09 -06:00
Michael Jones
38fa1fd040 Update cmd.hpp 2019-12-05 12:54:35 -06:00
Michael Jones
ba15f760ab Use static constexpr instead of const for compile-time constant variable 2019-12-05 12:53:06 -06:00
Michael Jones
5e3e8f977e Update error.hpp 2019-12-05 12:49:56 -06:00
Michael Jones
6182876d4f Update io.hpp 2019-12-05 12:44:14 -06:00
Michael Jones
5bfd2ee08c Use = default for default constructor 2019-12-05 12:41:31 -06:00
sorayuki
c91b227c47 Fix memory over-write in pipe.hpp 2019-11-25 15:31:48 +08:00
Klemens David Morgenstern
6a4d2ff721 added typedef executor_type; 2019-11-22 14:03:22 +08:00
Klemens David Morgenstern
6bf37ea8e8 Merge branch 'develop' of github.com:boostorg/process into develop
# Conflicts:
#	test/async_pipe.cpp
2019-11-22 13:11:17 +08:00
Klemens Morgenstern
ad38cdfada Merge pull request #106 from treesoft-de/bugfix
fix double CloseHandle after move of file_descriptor on windows
2019-11-22 13:08:17 +08:00
Klemens Morgenstern
167ee79fa9 Merge pull request #102 from res2k/develop
Miscellaneous fixes related to POSIX environments
2019-11-22 13:07:52 +08:00
Klemens David Morgenstern
6b83d0b9dd closes boostorg/process#97 2019-11-22 13:07:08 +08:00
Klemens Morgenstern
16d16d40be Merge pull request #90 from BikingGlobetrotter/develop
fixed hidden local variable
2019-11-22 13:06:12 +08:00
Klemens David Morgenstern
f5f0866745 closes boostorg/process#103 2019-11-22 13:04:59 +08:00
Klemens Morgenstern
408cff1997 Merge pull request #70 from thomassuckow/patch-1
Guard against EINTR in basic_pipe
2019-11-22 13:01:52 +08:00
Klemens David Morgenstern
09faec4732 closes boostorg/process#104 2019-11-22 12:59:05 +08:00
Klemens Morgenstern
5ab43529b7 Merge pull request #209 from killerbot242/changes3
only carry out when buffer size is > 0
2019-11-22 12:52:41 +08:00
Klemens Morgenstern
97f5b3c049 Merge pull request #211 from Instand/patch
Fix basic_ipstream is_open compile error.
2019-11-22 12:51:58 +08:00
Klemens David Morgenstern
6dd3e0bdb4 typo fix, closes klemens-morgenstern/boost-process#210 2019-11-22 12:50:40 +08:00
Arew
eba5cb7be2 Fix basic_ipstream is_open compile error. 2019-11-21 17:57:24 +03:00
Klemens David Morgenstern
f4c51bcd5a closes klemens-morgenstern/boost-process#107 2019-10-26 11:04:42 +07:00
Raymond Häb
410c0d592e fix double CloseHandle after move of file_descriptor on windows 2019-10-18 10:08:21 +02:00
Frank Richter
40df7899b2 test: Add test for direct conversion of wnative_environment to native_environment 2019-09-11 11:31:19 +02:00
Frank Richter
51083a8fa8 posix environment: Fix assignment of wnative_environment to wenvironment
Using 'environ' as the native_handle for a wide environment doesn't work,
as environ returns char**. Instead, use data we already converted.
2019-09-11 11:23:36 +02:00
Frank Richter
fe3cb0efc7 posix environment: Avoid using front() on empty string
That is undefined behaviour. Pushing a single NUL makes the string
non-empty but still gives us "".
2019-09-11 11:20:24 +02:00
Frank Richter
e0dd3b9658 test: Build fix for async_pipe 2019-09-11 11:01:45 +02:00
Lieven de Cock
d7d84f3952 only carry out when buffer size is > 0 2019-08-19 12:11:34 +02:00
Klemens Morgenstern
6ccce9104a Merge pull request #91 from orgads/patch-1
Fix GCC9 warning
2019-06-26 20:30:18 +10:00
Orgad Shaneh
984c0c5b71 Fix GCC9 warning
warning: moving a local object in a return statement prevents copy elision
2019-06-26 13:11:49 +03:00
michael
43523fcf8b fixed hidden local variable 2019-06-21 13:39:54 +02:00
Klemens Morgenstern
cf7ad36438 Merge pull request #87 from OBorce/feature/fix-stream-move-assignments
fix move assignment operators for basic_[io]pstream
2019-06-06 11:30:33 +07:00
boris
ca994c1972 fix move assignment operators for basic_[io]pstream 2019-06-05 00:19:53 +02:00
Klemens David Morgenstern
0a554c92b5 Merge branch 'develop' of github.com:boostorg/process into develop 2019-05-18 11:11:20 +07:00
Klemens Morgenstern
fa81cecffc Merge pull request #196 from klemens-morgenstern/limit_fd
Limit fd
2019-05-18 11:07:55 +07:00
Klemens David Morgenstern
977b76f6aa Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2019-05-15 12:31:16 +07:00
Klemens Morgenstern
fc1acb82d9 Merge pull request #199 from klemens-morgenstern/stream_close
added opstream::close, closes klemens-morgenstern/boost-process#198
2019-05-14 22:04:21 +07:00
Klemens David Morgenstern
db7af9f87d doc addition 2019-05-14 13:22:05 +07:00
Klemens Morgenstern
a350cc346b Merge pull request #203 from klemens-morgenstern/win_pipe_unlimited_instances
Closes boostorg/process#84 and boostorg/process#83
2019-05-14 12:41:29 +07:00
Klemens David Morgenstern
9fa86d3d65 removed call to 'close_sink' 2019-05-14 12:15:57 +07:00
Klemens David Morgenstern
e426f2bfac remove ill-formed test & minor fixes 2019-05-14 11:57:20 +07:00
Klemens David Morgenstern
6b173117aa Merge branch 'develop' into stream_close 2019-05-14 10:45:53 +07:00
Klemens David Morgenstern
ecbc93408f Merge branch 'develop' into win_pipe_unlimited_instances 2019-05-14 10:45:16 +07:00
Klemens David Morgenstern
6ba9a48d15 Merge branch 'develop' into new_wait_for_test 2019-05-14 10:44:40 +07:00
Klemens David Morgenstern
519c0a636a Merge branch 'develop' into limit_fd 2019-05-14 10:44:08 +07:00
Klemens David Morgenstern
82195c61af Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop
# Conflicts:
#	include/boost/process/detail/posix/wait_group.hpp
2019-05-14 00:41:41 +07:00
Klemens David Morgenstern
c604e3a20e switched to a wait/sleep version for OSX - should work fine for groups 2019-05-14 00:36:24 +07:00
Klemens Morgenstern
b27d0170ba Typo fix 2019-05-13 23:50:31 +07:00
Klemens David Morgenstern
98fd4eecf0 small reordering of code 2019-05-13 20:43:03 +07:00
Klemens David Morgenstern
3799315ce7 reverted to pipes for OSX 2019-05-13 20:11:17 +07:00
Klemens David Morgenstern
b9431ba492 fixing signal workaround 2019-05-13 10:30:28 +07:00
Klemens David Morgenstern
c0dca35615 added wrongfully removed build script options 2019-05-13 00:28:10 +07:00
Klemens David Morgenstern
790d79db9c Merge branch 'develop' into limit_fd 2019-05-13 00:23:52 +07:00
Klemens David Morgenstern
5de0a795d1 fixed wait_for_exit 2019-05-13 00:22:46 +07:00
Klemens David Morgenstern
cbaa913e3d Merge branch 'develop' into limit_fd
# Conflicts:
#	include/boost/process/detail/posix/pipe_out.hpp
#	test/Jamfile.jam
2019-05-12 17:43:40 +07:00
Klemens David Morgenstern
5786162fb5 Merge branch 'develop' into new_wait_for_test 2019-05-12 17:42:08 +07:00
Klemens David Morgenstern
78c44dd560 Merge branch 'develop' into win_pipe_unlimited_instances 2019-05-12 17:40:54 +07:00
Klemens David Morgenstern
23ff67d83d added space for pipe close test 2019-05-12 17:37:35 +07:00
Klemens David Morgenstern
476c6ccd95 Merge branch 'develop' into stream_close 2019-05-12 17:13:36 +07:00
Klemens David Morgenstern
28126b3432 osx fix 2019-05-12 17:02:25 +07:00
Klemens David Morgenstern
ed8388d091 actual fix 2019-05-12 16:55:45 +07:00
Klemens David Morgenstern
43c402a5da test logic fix 2019-05-12 16:53:54 +07:00
Klemens David Morgenstern
9ff2f6f3ef still trying for circleci 2019-05-10 16:56:11 +07:00
Klemens David Morgenstern
b2a0fadaca Merge branch 'develop' into new_wait_for_test
# Conflicts:
#	.travis.yml
2019-05-10 16:38:23 +07:00
Klemens David Morgenstern
3c4057204e hopefully fixed wait_for for osx 2019-05-10 16:34:51 +07:00
Klemens David Morgenstern
717ac47510 further investigation of circlci error 2019-05-10 12:21:37 +07:00
Klemens David Morgenstern
4f6f4eb391 updated for circle 2019-05-10 12:00:43 +07:00
Klemens David Morgenstern
99e04036c7 removed report-ci from circle-ci 2019-05-10 00:37:00 +07:00
Klemens David Morgenstern
519e339365 added more checks 2019-05-09 23:05:09 +07:00
Klemens David Morgenstern
d2c930470f removed && false 2019-05-09 17:08:58 +07:00
Klemens David Morgenstern
d5709ae747 trying to fix wait_for 2019-05-09 16:35:58 +07:00
Klemens David Morgenstern
d2ab81b1b9 Merge branch 'develop' into new_wait_for_test
# Conflicts:
#	include/boost/process/detail/posix/wait_for_exit.hpp
#	include/boost/process/detail/posix/wait_group.hpp
2019-05-09 12:20:20 +07:00
Klemens David Morgenstern
885557fe01 still trying to make wait_for work 2019-05-09 12:19:26 +07:00
Klemens David Morgenstern
b5b758f89a Merge branch 'develop' into stream_close 2019-05-09 11:29:31 +07:00
Klemens David Morgenstern
2a954eb809 Merge branch 'develop' into win_pipe_unlimited_instances 2019-05-09 11:24:14 +07:00
Klemens David Morgenstern
0edff5449a Merge branch 'develop' into new_wait_for_test
# Conflicts:
#	include/boost/process/detail/posix/wait_for_exit.hpp
2019-05-08 16:53:45 +07:00
Klemens David Morgenstern
417ea77f2f changed SIGTERM to SIGKILL 2019-05-08 16:50:49 +07:00
Klemens David Morgenstern
9e3fdc9669 SIGSEV fix 2019-05-08 16:44:38 +07:00
Klemens David Morgenstern
66c2867371 removed travis token 2019-05-08 16:30:39 +07:00
Klemens David Morgenstern
caa7b2fcc8 two minor fixes 2019-05-08 16:28:54 +07:00
Klemens David Morgenstern
6263e74bcd Merge branch 'develop' into limit_fd 2019-05-07 12:16:53 +07:00
Klemens David Morgenstern
faae08ee64 replaced 1 with ::boost::winapi::HANDLE_FLAG_INHERIT_ 2019-05-07 12:16:32 +07:00
Klemens David Morgenstern
2314e19f12 restructured osx wait
Check if it solves klemens-morgenstern/boost-process#200
2019-05-07 12:01:04 +07:00
Klemens David Morgenstern
cfd0fc055c fixed overflow func 2019-05-07 11:48:16 +07:00
Klemens David Morgenstern
849b5d0f30 Closes boostorg/process#84 and boostorg/process#83 2019-05-07 10:59:50 +07:00
Klemens Morgenstern
d13df2a194 Merge pull request #82 from Parean/develop
should close klemens-morgenstern/boost-process#201
2019-05-03 21:07:53 +07:00
Denis Smirnov
86fc3b0b4d should close klemens-morgenstern/boost-process#201 2019-05-03 19:07:17 +07:00
Klemens David Morgenstern
4733ca719f typo fix 2019-04-25 22:40:13 +07:00
Klemens David Morgenstern
296f12eb64 RAII issues & resetting flags on windwos handles 2019-04-25 22:36:30 +07:00
Klemens David Morgenstern
96d3470e37 added this-> before clear() 2019-04-25 22:06:23 +07:00
Klemens David Morgenstern
2265c98d81 added missing ; 2019-04-25 20:24:42 +07:00
Klemens David Morgenstern
060e5c2526 fixed name lookup 2019-04-25 15:15:29 +07:00
Klemens David Morgenstern
b4894807f1 added opstream::close, closes klemens-morgenstern/boost-process#198 2019-04-24 18:24:44 +07:00
Klemens David Morgenstern
2aa5e1461c Merge branch 'develop' into new_wait_for_test
# Conflicts:
#	test/Jamfile.jam
2019-04-20 16:41:31 +08:00
Klemens Morgenstern
61fa15fa48 Merge pull request #197 from toonetown/fix-wait_for-fork-macOS
Use SIGTERM instead of `-15`.
2019-04-20 15:39:54 +07:00
Nathan Toone
92508e06a1 Use SIGTERM instead of -15. 2019-04-19 23:44:54 -06:00
Klemens David Morgenstern
e85f0d0816 Closes klemens-morgenstern/boost-process#139 2019-04-10 12:18:02 +08:00
Klemens David Morgenstern
5e90c8de9b fixed up tests 2019-04-10 10:09:32 +08:00
Klemens David Morgenstern
a486a25a07 appveyor minor fix, pipe_out naming fix & limit_fd small sanity check because of weird osx bug 2019-04-10 01:33:21 +08:00
Klemens David Morgenstern
f8c0dd4da5 prototype for limit_fd 2019-04-09 23:39:43 +08:00
Klemens David Morgenstern
ee6870bfbc added used_handles & limit_fd for windows 2019-04-09 19:16:55 +08:00
Klemens David Morgenstern
0422b6bfb8 added posix get_handle function 2019-04-09 15:40:26 +08:00
Klemens David Morgenstern
7fc41b2815 added windows handles functionality 2019-04-09 14:31:50 +08:00
Klemens David Morgenstern
a49f1f6e2d Started on limit-fd functionality 2019-04-08 11:11:55 +08:00
Klemens David Morgenstern
af54484bc2 sed typo fix 2019-04-07 21:40:28 +08:00
Klemens David Morgenstern
ebcb30e4bd reduced amount of threads for build 2019-04-07 13:31:46 +08:00
Klemens David Morgenstern
5371c9813b typo fix 2019-04-07 13:07:11 +08:00
Klemens David Morgenstern
9a833c610d trying to fix the exit code 2019-04-07 12:53:02 +08:00
Klemens David Morgenstern
c99ebfee7a flipping typos 2019-04-07 12:34:37 +08:00
Klemens David Morgenstern
34861366e0 added sed for annotations 2019-04-07 12:19:17 +08:00
Klemens David Morgenstern
e6722c452c faulty log name fix (attempt) 2019-04-07 11:47:18 +08:00
Klemens David Morgenstern
b1e38842fb renamed the no-valgrind log 2019-04-07 03:15:38 +08:00
Klemens David Morgenstern
bcc9826e67 still doing the ci thing here 2019-04-07 03:09:17 +08:00
Klemens David Morgenstern
b6c6753b87 added valgrind to circle Ci 2019-04-07 02:57:14 +08:00
Klemens David Morgenstern
0d008a88fc dammit circle 2019-04-07 02:49:14 +08:00
Klemens David Morgenstern
f92ec53968 circle ci example job fix 2019-04-07 02:36:14 +08:00
Klemens David Morgenstern
00a87d0a67 report-ci update for circleci 2019-04-07 02:29:52 +08:00
Klemens David Morgenstern
462334639c typo fix 2019-04-07 02:08:31 +08:00
Klemens David Morgenstern
7129182044 ci fixes - the similtaneous wait doen't work on osx 2019-04-07 02:03:08 +08:00
Klemens David Morgenstern
03fbed44ad typo fix 2019-04-07 01:23:10 +08:00
Klemens David Morgenstern
0277c4fcec CI fixes 2019-04-07 01:19:19 +08:00
Klemens David Morgenstern
4bc1ae6ff8 added async fix & fixed dangling develop workaroudn for async_pipe copy 2019-04-07 00:21:27 +08:00
Klemens David Morgenstern
266c4503aa Merge branch 'develop' into asio_no_deprecated 2019-04-06 23:58:47 +08:00
Klemens David Morgenstern
80479b6b70 removed errornous global variable 2019-04-06 23:58:27 +08:00
Klemens David Morgenstern
823a346a08 added another exit_code test 2019-04-06 23:53:11 +08:00
Klemens David Morgenstern
8f3a7b9c63 Merge branch 'develop' into asio_no_deprecated 2019-04-06 22:35:45 +08:00
Klemens David Morgenstern
2ebcc07892 Merge branch 'circleci' into develop 2019-04-06 22:33:22 +08:00
Klemens Morgenstern
a673cd9643 Update config.yml 2019-04-06 22:25:52 +08:00
Klemens Morgenstern
12971db132 Update config.yml 2019-04-06 22:19:11 +08:00
Klemens Morgenstern
94be279992 Update config.yml 2019-04-06 22:15:38 +08:00
Klemens David Morgenstern
12cded5995 switched test to strand 2019-04-06 22:15:12 +08:00
Klemens David Morgenstern
0c16a0e5b3 set params back to support report.ci 2019-04-06 22:11:04 +08:00
Klemens Morgenstern
e4a6fde7b9 Update config.yml 2019-04-06 18:28:40 +08:00
Klemens David Morgenstern
92d2bebaaf added test and fixed #189 and #157 as well as #93 2019-04-06 18:25:08 +08:00
Klemens David Morgenstern
7e7a8cbc1d fixed #194 2019-04-06 17:29:52 +08:00
Klemens Morgenstern
4f767f4bfe Update config.yml 2019-04-06 17:25:03 +08:00
Klemens Morgenstern
63f714ae2f Update config.yml 2019-04-06 16:54:07 +08:00
Klemens Morgenstern
1b3b9b707c Update config.yml 2019-04-06 16:41:44 +08:00
Klemens Morgenstern
f64bc8a6d4 Update config.yml 2019-04-06 16:34:26 +08:00
Klemens Morgenstern
102834130d Update config.yml 2019-04-06 16:28:48 +08:00
Klemens Morgenstern
fdc6a11cbc Update config.yml 2019-04-06 16:09:16 +08:00
Klemens Morgenstern
19b20f55ce Update config.yml 2019-04-06 16:04:28 +08:00
Klemens David Morgenstern
60d072ce46 Merge branch 'develop' into circleci 2019-04-06 15:29:22 +08:00
Klemens David Morgenstern
34f05b9276 Merge branch 'develop' into asio_no_deprecated 2019-04-06 15:22:10 +08:00
Klemens David Morgenstern
1b476b0430 Closes #65 2019-04-06 15:21:52 +08:00
Klemens David Morgenstern
b294710e60 fixed self-pipe issue 2019-04-06 14:42:08 +08:00
Klemens David Morgenstern
f8cd325d1b trying circleci 2019-04-05 15:13:14 +08:00
Klemens David Morgenstern
2a6c23e173 typo fix 2019-04-04 18:11:33 +08:00
Klemens David Morgenstern
d7768b7221 Merge branch 'develop' into asio_no_deprecated 2019-04-04 17:57:28 +08:00
Klemens David Morgenstern
b8821eac57 should close #78 2019-03-30 23:14:25 +08:00
Klemens David Morgenstern
d20b64cf37 removed unnecessary int to remove warning 2019-03-29 01:39:00 +08:00
Klemens David Morgenstern
f0ddd6ca29 typo & structure fix 2019-03-29 00:57:11 +08:00
Klemens David Morgenstern
574d9e09d6 should close #193 2019-03-29 00:32:12 +08:00
Klemens Morgenstern
7085a50f36 Merge pull request #77 from SimonEbner/develop
Fix leaking pipe
2019-03-23 00:01:27 +08:00
Klemens Morgenstern
0485459da2 Merge pull request #76 from orgads/patch-1
Fix signed/unsigned comparison
2019-03-22 23:56:13 +08:00
Simon Ebner
318439af2e Fix Issue 62
Fixes a leaking pipe. See https://github.com/boostorg/process/issues/62
2019-03-22 15:27:35 +01:00
Orgad Shaneh
4d52ff362f Fix signed/unsigned comparison 2019-03-21 23:39:27 +02:00
Klemens David Morgenstern
8d48d9cbfa dumb workaround -> fix report.ci detection! 2019-03-21 16:21:40 +08:00
Klemens David Morgenstern
f25c31c847 added test by @grives as recommended in #69 2019-03-21 12:51:32 +08:00
Bruno Martinez
192191ecfb typo 2019-03-05 12:30:06 -03:00
Klemens David Morgenstern
3eacae5e38 Merge branch 'develop' 2019-03-04 12:16:07 +08:00
Klemens David Morgenstern
14b294c10c Merge branch 'develop' of github.com:boostorg/process into develop 2019-03-04 12:14:56 +08:00
Klemens Morgenstern
881da4f9e2 Merge pull request #191 from klemens-morgenstern/develop
Update master
2019-02-28 12:44:50 +08:00
Filip Konvička
3aeb6601cd Merge pull request #1 from fkonvick/windows-shell-dquotes
Fix double quotes processing on Windows
2019-02-27 14:05:59 +01:00
Filip Konvička
8a7c37617e Fix double quotes processing on Windows
Fix double quotes processing on Windows:
- quotes should only be added when not already present
- quotes need to be used when an argument includes spaces or double quotes
- quotes inside an argument should be doubled (that's the way Windows does escaping)
2019-02-27 14:02:45 +01:00
Klemens Morgenstern
2758e8d438 Merge pull request #190 from klemens-morgenstern/report-ci
Report ci
2019-02-27 12:44:12 +08:00
Klemens David Morgenstern
b5a6b4b945 updated readme 2019-02-25 12:59:56 +08:00
Klemens David Morgenstern
ac94f81b77 renamed wait test suite 2019-02-25 09:42:45 +08:00
Klemens David Morgenstern
06747d7dd3 added test suites 2019-02-25 00:04:09 +08:00
Klemens David Morgenstern
fb9b9215e0 another windows fix 2019-02-24 22:37:13 +08:00
Klemens David Morgenstern
eed0505f6e trying to fix the windows build 2019-02-24 21:26:34 +08:00
Klemens David Morgenstern
8f6aa8bcff added root-dir parameter 2019-02-24 17:14:28 +08:00
Klemens David Morgenstern
6f9cabbd04 trying to fix the build scripts 2019-02-24 13:10:03 +08:00
Klemens David Morgenstern
355d20faf3 update async pipe executor assignment 2019-02-24 00:51:44 +08:00
Klemens David Morgenstern
15c4a64a81 updated asio fwd 2019-02-23 23:38:20 +08:00
Klemens David Morgenstern
49ec65a735 updated yamls 2019-02-23 22:29:04 +08:00
Klemens David Morgenstern
7cdea96caf added report-ci 2019-02-23 20:51:24 +08:00
Klemens Morgenstern
8bf7da3b6b Merge pull request #71 from killerbot242/changes
fix warning due to extra semi colon
2019-02-03 21:19:45 +08:00
Lieven de Cock
c1ad9d1227 fix warning due to extra semi colon
In file included from /home/ldco/boost/include/boost/process/detail/on_exit.hpp:12:0,
                 from /home/ldco/boost/include/boost/process/async.hpp:33,
                 from /home/ldco/boost/include/boost/process.hpp:23,
                 from /home/ldco/Projects/Teaching/Teaching/Boost/Process/Process1/src/main.cpp:7:
/home/ldco/boost/include/boost/process/detail/posix/on_exit.hpp:30:6: warning: extra ‘;’ [-Wpedantic]
     };
      ^
In file included from /home/ldco/boost/include/boost/process/async.hpp:42:0,
                 from /home/ldco/boost/include/boost/process.hpp:23,
                 from /home/ldco/Projects/Teaching/Teaching/Boost/Process/Process1/src/main.cpp:7:
/home/ldco/boost/include/boost/process/detail/posix/io_context_ref.hpp:67:6: warning: extra ‘;’ [-Wpedantic]
     };
      ^
2019-01-29 12:57:43 +01:00
Thomas Suckow
1b6ccb6d39 Guard against EINTR in basic_pipe
Based on the code from executor.hpp, a signal can cause invoking a child process to fail because reading/writing the pipe was interrupted.
2019-01-22 09:22:52 -08:00
Klemens David Morgenstern
e2e2b5ddb2 Merge branch 'develop' 2019-01-08 15:02:41 +08:00
Klemens David Morgenstern
b4584dd0b0 Merge branch 'develop' of github.com:boostorg/process into develop 2019-01-08 15:02:17 +08:00
Klemens Morgenstern
55e5d178bd Merge pull request #67 from amensel/develop
Use the non-deprecated ASIO APIs.
2019-01-07 17:30:48 +07:00
Klemens David Morgenstern
f778702257 closes #188 2019-01-07 17:12:58 +07:00
Klemens David Morgenstern
b4ff07cfcb fixed BOOST_NO_ANSI_APIS issue in basic_pipe, closed #26 2019-01-07 17:03:00 +07:00
Adam Mensel
d43858078f Use the non-deprecated function name. 2019-01-04 15:32:38 -07:00
Adam Mensel
f2cf918be5 Missed one post call. 2019-01-04 15:24:28 -07:00
Adam Mensel
54dd027a64 Use the non-deprecated ASIO APIs. 2019-01-04 11:57:47 -07:00
Klemens David Morgenstern
1ea894ab30 Closes #187 2018-12-15 11:37:51 +07:00
Klemens David Morgenstern
92c45f4b61 testing for actual timing 2018-12-14 23:33:26 +07:00
Klemens Morgenstern
03cba8f5bd Merge pull request #185 from klemens-morgenstern/develop
Develop update
2018-12-14 12:17:46 +07:00
Klemens David Morgenstern
97f08ba0b3 Merge remote-tracking branch 'remotes/origin/master' into develop
# Conflicts:
#	doc/tutorial.qbk
2018-12-14 12:17:17 +07:00
Klemens David Morgenstern
c843815c6c added multithreading for osx only 2018-12-14 11:31:08 +07:00
Klemens David Morgenstern
b5785b3370 added -j8 to travis 2018-12-13 14:17:54 +07:00
Klemens David Morgenstern
a6e5a5a619 typoe fix 2018-12-13 11:45:48 +07:00
Klemens David Morgenstern
2d627f633b added group_wait 2018-12-12 00:19:14 +07:00
Klemens David Morgenstern
ef486764ac added check if forked proc is running 2018-12-11 23:13:20 +07:00
Klemens David Morgenstern
fce3962376 WNOHANG test 2018-12-11 21:58:17 +07:00
Klemens David Morgenstern
5a40a0ee9c typo fix 2018-12-11 18:24:25 +07:00
Klemens David Morgenstern
4bf795922d trying nanosleep 2018-12-11 18:05:24 +07:00
Klemens David Morgenstern
1646b240c7 trying to fix wait_for 2018-12-11 17:19:37 +07:00
Klemens David Morgenstern
d4f7bfaa6c double timeout for terminate... 2018-12-11 16:17:29 +07:00
Klemens David Morgenstern
bac06d2bc7 added timeout to terminate 2018-12-11 15:38:41 +07:00
Klemens David Morgenstern
579499d9e8 group_wait 2018-12-11 15:06:08 +07:00
Klemens David Morgenstern
b8c46bfc47 trying explicit alarm for osx 2018-12-11 14:36:04 +07:00
Klemens David Morgenstern
d234ce4f63 bumped up the log_level 2018-12-11 14:16:48 +07:00
Klemens David Morgenstern
1be807e748 Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2018-12-11 13:52:09 +07:00
Klemens David Morgenstern
f4db2613eb disabling valgrind for osx 2018-12-11 13:50:10 +07:00
Klemens Morgenstern
bae6098e91 Merge pull request #186 from jasonmccampbell/native-exit-code
Allow access to the uninterpreted exit code
2018-12-11 10:15:50 +07:00
Jason McCampbell
c40153fab1 Allow access to the uninterpreted exit code to allow calls to
distinugish between exit codes and exit due to signals (POSIX)
2018-12-11 02:41:27 +00:00
Klemens David Morgenstern
e5eec4a5dc updated develop thingy 2018-12-11 01:02:28 +07:00
Klemens David Morgenstern
887bb8c482 removed notify_fork again 2018-12-11 00:41:47 +07:00
Klemens David Morgenstern
0642bf5e70 added had SIGALARM For apple 2018-12-11 00:15:17 +07:00
Klemens David Morgenstern
513208a117 travis fix 2018-12-10 23:31:57 +07:00
Klemens David Morgenstern
49247f0a83 revamped async 2018-12-10 22:42:05 +07:00
Klemens David Morgenstern
ccb7dd482a implemented badges for OSX / Linux 2018-12-10 17:23:12 +07:00
Klemens David Morgenstern
08f40ff46b trying BOOST_TEST_CATCH_SYSTEM_ERRORS=no for osx 2018-12-10 15:21:03 +07:00
Klemens David Morgenstern
956f7b5fdf updated group_wait to remove wrong condition 2018-12-10 15:06:26 +07:00
Klemens David Morgenstern
40d0f8c401 trying to fix group wait 2018-11-20 20:40:44 +07:00
Klemens David Morgenstern
cbc7580fcd updated ansi_apps by api-guard 2018-11-20 20:15:46 +07:00
Klemens David Morgenstern
f96dfd6e8f typo fix 2018-11-15 15:55:47 +07:00
Klemens David Morgenstern
ea24ebaf92 added notify fork back into io_context_ref 2018-11-15 15:07:34 +07:00
Klemens David Morgenstern
504e760760 added timeout to wait-test 2018-11-15 14:30:11 +07:00
Klemens David Morgenstern
c5e7cfb4f5 added called-bool & time out for exit_code test 2018-11-15 13:53:01 +07:00
Klemens David Morgenstern
9904e3a5e8 removed BOOST_TEST_IGNORE_SIGCHLD from test 2018-11-15 12:54:48 +07:00
Klemens David Morgenstern
191673b049 updated waitpid functionality 2018-11-15 11:51:33 +07:00
Klemens David Morgenstern
3a6d11f9b8 damn typos 2018-11-15 11:22:43 +07:00
Klemens David Morgenstern
e022ad3742 typo fix, again 2018-11-15 11:06:09 +07:00
Klemens David Morgenstern
16d9350992 typo fix 2018-11-15 10:51:29 +07:00
Klemens David Morgenstern
5e1d7b6901 updated sigchld_service to check first check if the child is actually running 2018-11-15 10:35:52 +07:00
Klemens David Morgenstern
82d4cef182 trying to queue process creation 2018-11-13 19:06:03 +07:00
Klemens David Morgenstern
5a112ea4bb Merge branch 'develop' into travis_osx
# Conflicts:
#	.travis.yml
#	include/boost/process/detail/posix/wait_for_exit.hpp
#	include/boost/process/detail/posix/wait_group.hpp
2018-11-13 17:47:41 +07:00
Klemens David Morgenstern
b058e1cadf trying to remove BOOST_TEST_IGNORE_SIGCHLD 2018-11-13 16:57:06 +07:00
Klemens David Morgenstern
a8b28ef262 fixed timeout values 2018-11-13 14:57:29 +07:00
Klemens David Morgenstern
080f3fb074 checking if it's just an asio timing problem 2018-11-13 14:37:57 +07:00
Klemens David Morgenstern
997f10c7e9 fixed wrong timeout values 2018-11-13 14:20:39 +07:00
Klemens David Morgenstern
4ced4d0933 typo fix in wait functions 2018-11-13 13:52:17 +07:00
Klemens David Morgenstern
eafe8e327a removed auto from lambdas 2018-11-13 13:49:28 +07:00
Klemens David Morgenstern
a4c89a3dec added timeouts to async test 2018-11-13 13:30:14 +07:00
Klemens David Morgenstern
902390d57a still trying for the osx on travis 2018-11-13 11:56:38 +07:00
Klemens David Morgenstern
5c55590922 trying llvm now 2018-11-12 20:23:46 +07:00
Klemens David Morgenstern
0485932309 typo fix 2018-11-12 19:53:55 +07:00
Klemens David Morgenstern
e1a3aded4e added . output for filter for section warning 2018-11-12 19:32:21 +07:00
Klemens David Morgenstern
5b2d5c76c8 nsleep -> nanosleep 2018-11-12 18:59:18 +07:00
Klemens David Morgenstern
2c3c9e84a5 added include of unistd.h 2018-11-12 18:40:48 +07:00
Klemens David Morgenstern
ad90ca6366 CI fixes and attempt on new wait_for mechanic
Squashed commit of the following:

commit 88952f0ab2
Author: Klemens David Morgenstern <klemens.morgenstern@gmx.net>
Date:   Mon Nov 12 18:27:04 2018 +0700

    rolling back the --coverage option

commit 29cd54ea8c
Author: Klemens David Morgenstern <klemens.morgenstern@gmx.net>
Date:   Mon Nov 12 18:12:33 2018 +0700

    another attempt

commit c2ee6da367
Author: Klemens David Morgenstern <klemens.morgenstern@gmx.net>
Date:   Mon Nov 12 17:54:53 2018 +0700

    trying to get the sanitization to work here

commit 317801ca5e
Author: Klemens David Morgenstern <klemens.morgenstern@gmx.net>
Date:   Mon Nov 12 17:10:36 2018 +0700

    added -lprofile_rt

commit 3923da14f7
Author: Klemens David Morgenstern <klemens.morgenstern@gmx.net>
Date:   Mon Nov 12 16:56:32 2018 +0700

    attempting new timed wait for OSX

commit 5aa691cc3a
Author: Klemens David Morgenstern <klemens.morgenstern@gmx.net>
Date:   Mon Nov 12 16:32:11 2018 +0700

    adding valgrind to build

commit 04712d57f4
Author: Klemens David Morgenstern <klemens.morgenstern@gmx.net>
Date:   Mon Nov 12 16:09:34 2018 +0700

    changin pipe mode

commit ed4c861e78
Author: Klemens David Morgenstern <klemens.morgenstern@gmx.net>
Date:   Mon Nov 12 15:37:08 2018 +0700

    trying to filter section warnings
2018-11-12 18:39:31 +07:00
Klemens David Morgenstern
88952f0ab2 rolling back the --coverage option 2018-11-12 18:27:04 +07:00
Klemens David Morgenstern
29cd54ea8c another attempt 2018-11-12 18:12:33 +07:00
Klemens David Morgenstern
c2ee6da367 trying to get the sanitization to work here 2018-11-12 17:54:53 +07:00
Klemens David Morgenstern
317801ca5e added -lprofile_rt 2018-11-12 17:10:36 +07:00
Klemens David Morgenstern
3923da14f7 attempting new timed wait for OSX 2018-11-12 16:56:32 +07:00
Klemens David Morgenstern
5aa691cc3a adding valgrind to build 2018-11-12 16:32:11 +07:00
Klemens David Morgenstern
04712d57f4 changin pipe mode 2018-11-12 16:09:34 +07:00
Klemens David Morgenstern
ed4c861e78 trying to filter section warnings 2018-11-12 15:37:08 +07:00
Klemens David Morgenstern
587eaa8054 yaml file fix 2018-11-12 14:55:38 +07:00
Klemens David Morgenstern
78b5ea1f6b checking the sigtimedwait macro --> test should fail on OSX & work on Linux 2018-11-12 14:48:58 +07:00
Klemens David Morgenstern
6412aa3ece trying badging properly 2018-11-12 14:34:50 +07:00
Klemens David Morgenstern
68a3ba0c41 Merge branch 'develop' into travis_osx 2018-11-12 14:29:36 +07:00
Klemens David Morgenstern
ecaba9efc1 typo fix 2018-11-12 14:04:50 +07:00
Klemens David Morgenstern
fb682944d9 trying to install gcc-5 for osx 2018-11-12 13:49:55 +07:00
Klemens David Morgenstern
9c60e4987c added matrix links to readme 2018-11-09 11:06:17 +07:00
Klemens David Morgenstern
59b361fb46 trying to use osx 2018-11-09 11:01:35 +07:00
Klemens David Morgenstern
f3b2c0a67e typo fixes 2018-10-26 11:35:33 +07:00
Klemens David Morgenstern
69c04d5e29 updated doc to say io_context instead of io_service 2018-10-26 10:55:28 +07:00
Klemens David Morgenstern
78f4115a32 Implement move operations for streams, closes #173 2018-10-26 10:53:47 +07:00
Klemens David Morgenstern
9b1b83f5e7 Merge branch 'develop' of github.com:boostorg/process into develop 2018-10-26 10:38:46 +07:00
Klemens Morgenstern
bd859e98d3 Merge pull request #54 from tnixeu/develop
removes boost::asio:: from example in doc
2018-10-26 14:35:06 +11:00
tnixeu
d7accdcf0c fixes some string replacements issues in doc. Some replacements caused wrong namespaces. 2018-10-20 13:04:17 +02:00
tnixeu
d159fea7b8 removes boost::asio:: from example in doc 2018-10-20 11:50:45 +02:00
Klemens David Morgenstern
b5b91d578d Merge branch 'develop' of github.com:boostorg/process into develop 2018-10-01 10:01:40 +07:00
Klemens Morgenstern
498055bc8d Merge pull request #52 from pivotal-jbarrett/isrunning-solaris
Changes still_active constant to support Solaris.
2018-09-28 00:04:08 +07:00
Jacob Barrett
502169a5ad Changes still_active constant to support Solaris.
The use of the WIFSTOPPED bits did not go far enough on Solaris. It
is expected to also have a non-zero value in the next bytes. This
new value is tested be valid on Linux, MacOS and Solaris.

Fixes #51
2018-09-27 07:36:03 -07:00
Klemens David Morgenstern
42fbbbd8a6 Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2018-09-27 10:02:01 +07:00
Klemens David Morgenstern
dd0b26de4c closes #180 2018-09-27 10:00:29 +07:00
Klemens Morgenstern
10665bfaff Merge pull request #181 from krwalker/fix-vc-c4458-warnings
Fix warnings: decl. of 'x' hides class member
2018-09-27 09:55:41 +07:00
K. R. Walker
2576ed166f Fix warnings: decl. of 'x' hides class member
Address C4458 warnings when compiled with Visual C++
2018-09-26 16:54:46 -06:00
Klemens David Morgenstern
9ad7413189 Merge branch 'develop' 2018-09-26 15:18:30 +07:00
Klemens David Morgenstern
9cd405a66f Squashed commit of the following:
commit 4107154e8056ec3460ccd70dea6b919e8c71fc59
Author: Klemens David Morgenstern <klemens.morgenstern@gmx.net>
Date:   Wed Sep 26 14:42:00 2018 +0700

    trying to fix the coverage reporting
2018-09-26 15:17:56 +07:00
Klemens David Morgenstern
fc6773d7d3 trying to improve coverage 2018-09-26 14:03:13 +07:00
Klemens David Morgenstern
c3b707b709 Merge branch 'master' of github.com:boostorg/process 2018-09-26 13:53:10 +07:00
Klemens Morgenstern
57e9dfb705 Merge pull request #179 from klemens-morgenstern/develop
Update for master
2018-09-26 13:50:47 +07:00
Klemens David Morgenstern
4fd8887601 fixed group wait-for on windows 2018-09-26 11:50:18 +07:00
Lemmy
3cf4bf6480 Hope fully fixed group waiting 2018-09-25 17:32:32 +02:00
Lemmy
256523d36e Merge branch 'develop' of https://github.com/klemens-morgenstern/boost-process into develop 2018-09-25 11:45:23 +02:00
Lemmy
6ba8e88def wait-group fix 2018-09-25 11:45:04 +02:00
Klemens David Morgenstern
f139f863a0 typo fix in test 2018-09-25 16:10:11 +07:00
Lemmy
0938103427 Reworked wait_for_exit, concerns #99 and #112 2018-09-25 10:45:54 +02:00
Lemmy
e72127f9f8 Implemented proper wait_for for group_handles 2018-09-25 10:27:40 +02:00
Lemmy
eea73753b5 Fixed group wait in linux 2018-09-25 07:40:07 +02:00
Klemens David Morgenstern
4f3b425073 fixed group-wait, finally 2018-09-25 02:37:51 +07:00
Klemens David Morgenstern
dcb8a0266a preserving creation_flags, closes #176 2018-09-24 23:42:53 +07:00
Klemens David Morgenstern
99285a9de6 fixed windows-h variant 2018-09-24 23:27:01 +07:00
Klemens David Morgenstern
6cc31b93d8 readded BOOST_WINAPI_WINAPI_CC 2018-09-24 23:10:33 +07:00
Klemens David Morgenstern
d1ce19d848 fixes #178 2018-09-21 10:48:03 +07:00
Klemens Morgenstern
f00895a9fc Update tutorial.qbk
closes #49
2018-09-11 14:38:49 +08:00
Klemens David Morgenstern
8d2bd87707 ALternative (typeless) implementation of #177 2018-08-29 09:37:07 +08:00
Klemens David Morgenstern
44162ecf22 removed errornous noexcept 2018-06-19 18:34:39 +08:00
Klemens David Morgenstern
d709c1cd07 fixed tutorial example type 2018-06-18 09:46:15 +08:00
Klemens Morgenstern
90d2c0ceca Merge pull request #168 from klemens-morgenstern/develop
1.68 release merge
2018-06-13 22:00:09 +03:00
Klemens David Morgenstern
9549ffe7e1 capture list fix 2018-05-27 11:39:56 +02:00
Klemens David Morgenstern
dd0edb4aee Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2018-05-26 22:07:15 +02:00
Klemens David Morgenstern
3029f4623a closes #41 2018-05-26 22:06:54 +02:00
Klemens David Morgenstern
74606db379 Merge branch 'bugfixing' into develop 2018-05-26 22:00:12 +02:00
Klemens David Morgenstern
81803868a3 closes #45 2018-05-26 21:59:58 +02:00
Klemens David Morgenstern
eff42f91ef closes #42 2018-05-26 21:57:25 +02:00
Klemens David Morgenstern
a25b6ca35b closes #32 2018-05-26 21:55:07 +02:00
Klemens Morgenstern
1c8323650d Merge pull request #166 from egorpugin/patch-2
Add missing returns on windows side.
2018-05-26 20:46:14 +02:00
Klemens David Morgenstern
52f030a83c closes #167 2018-05-26 20:32:08 +02:00
Egor Pugin
9cc651bdeb Add missing returns on windows side. 2018-05-09 20:09:32 +03:00
Klemens Morgenstern
128cb0283d Merge pull request #165 from egorpugin/patch-2
Add missing returns
2018-05-09 14:41:31 +02:00
Egor Pugin
bb259f8f16 Add missing returns 2018-05-09 15:16:15 +03:00
Klemens Morgenstern
bb1bb431e5 Merge pull request #163 from tomaszjonak/develop
Fix async_pipe::async_read_some always returning 0
2018-05-04 17:22:48 +02:00
Tomasz Jonak
41b7e30c18 Add missing return to async_pipe::async_{read,write}_some 2018-05-04 14:03:54 +00:00
Klemens David Morgenstern
f1c6909eb0 Merge remote-tracking branch 'remotes/origin/develop' 2018-04-05 20:35:52 +02:00
Klemens Morgenstern
35fda5aa6a Update job_workaround.hpp 2018-04-05 20:12:51 +02:00
Klemens Morgenstern
1f7f805858 Merge pull request #158 from klemens-morgenstern/develop
Update job_workaround.hpp
2018-04-05 11:16:39 +02:00
Klemens Morgenstern
d47b7f7ac4 Update job_workaround.hpp 2018-04-05 10:08:00 +02:00
Klemens David Morgenstern
2bc2531d2a Merge branch 'develop' 2018-04-04 20:55:25 +02:00
Klemens David Morgenstern
c5798fdf7f added write_some and read_some overloads - closes #35 2018-03-13 10:11:01 +08:00
Klemens David Morgenstern
5e43e7c07c Merge branch 'develop' of github.com:boostorg/process into develop 2018-03-11 20:58:22 +01:00
Klemens David Morgenstern
6abce365c5 started on asio_no_deprecated.cpp 2018-03-11 20:57:18 +01:00
Klemens Morgenstern
4fc4784506 Merge pull request #34 from Lastique/update_winapi_cc
Switch WINAPI calling convention macros to the replacements from Boost.WinAPI
2018-03-11 20:56:06 +01:00
Andrey Semashev
900aab5d6d Switched WINAPI calling convention macros to the replacements from Boost.WinAPI
WINAPI macro definition in Boost.WinAPI is deprecated as it may clash with
the macro defined in Windows SDK.
2018-03-11 20:20:49 +03:00
Klemens Morgenstern
f61a61cf59 Merge pull request #144 from klemens-morgenstern/develop
Another master updates
2018-02-26 23:25:28 +01:00
Klemens Morgenstern
8e8d36772e Merge pull request #151 from amerry/is-running-fixes
is_running fixes
2018-02-26 13:53:41 +01:00
Alex Merry
ec04919825 Rename tests to reflect what they do 2018-02-22 14:32:54 +00:00
Alex Merry
6625999765 Check the "still running" status code does not clash with WIFSIGNALED
This makes the static_assert reflect the actual assumptions in the code.
2018-02-22 14:31:22 +00:00
Alex Merry
0d3688aca5 Ignore stopped processes
is_running should only concern itself with terminated processes, not
stopped processes (which might be continued later).
2018-02-22 14:12:46 +00:00
Klemens Morgenstern
40be786c43 Merge pull request #150 from amerry/async-exit-status
Return the same exit status in the async handler as the sync method
2018-02-22 13:43:06 +01:00
Klemens Morgenstern
d4a0444223 Merge pull request #147 from amerry/args
Always set arguments on POSIX
2018-02-22 13:05:33 +01:00
Klemens Morgenstern
f99cfe77f4 Merge pull request #148 from pepsiman/patch-1
Fix grammar in tutorial
2018-02-22 12:59:52 +01:00
Alex Merry
ed32531369 Return the same exit status in the async handler as the sync method
Previously, if the process terminated via a signal on posix, the async
handler would provide an exit status of 0.
2018-02-22 11:53:42 +00:00
Malcolm Parsons
751af041cd Fix grammar in tutorial 2018-02-22 10:29:59 +00:00
Alex Merry
a0ceebd59f Fix copyright headers
Insofar as there are copyrights on these changes, they are owned by my
employer, as I'm doing this on company time.
2018-02-22 09:02:02 +00:00
Klemens Morgenstern
b0b37f2ce6 Merge pull request #146 from amerry/test-for-sigchld-fix
Add unit tests for async exit watching with multiple io_contexts
2018-02-21 17:50:27 +01:00
Alex Merry
cf1f904ae2 Fix compilation on MSVC 2018-02-21 15:53:46 +00:00
Alex Merry
8aaf53d76d Always set arguments on POSIX
Explicitly specifying an executable (either with boost::filesystem::path
or boost::process::exe) and no arguments causes NULL to be passed as the
argument list.

Not only is this unexpected behaviour for the child process (which
doesn't even have argv[0]), it is not portable across UNIX systems. From
the execve(2) man page on Linux:

"On Linux, either argv or envp can be specified as NULL, which has the
same effect as specifying these arguments as a pointer to a list
containing a single NULL pointer.  Do not take advantage of this
misfeature!  It is nonstandard and nonportable:  on  most other UNIX
systems doing this will result in an error (EFAULT)."
2018-02-21 15:43:32 +00:00
Alex Merry
76c03ded89 Add unit tests for async exit watching with multiple io_contexts
These tests fail without the commit "Only reap children we are watching
for when handling SIGCHLD" applied, and succeed with it applied.
2018-02-21 15:13:28 +00:00
Klemens Morgenstern
e6fa19b4c5 Merge pull request #145 from amerry/async-wait-fix
Only reap children we are watching for when handling SIGCHLD
2018-02-20 19:53:54 +01:00
Alex Merry
92ee239891 Only reap children we are watching for when handling SIGCHLD
There may be other io_context instances with child instances, and child
instances with no associated io_context. If we pass 0 to ::waitpid(), we
will reap their processes as well, without updating the state of the
corresponding child instance.

Instead, we call `::waitpid` once for each child we are watching for.
This has some amount of overhead (multiple system calls), but ensures
correct behaviour (providing nothing other than an asio::signal_set is
watching for SIGCHLD).
2018-02-20 14:32:33 +00:00
Klemens Morgenstern
c37e2a7524 Merge pull request #142 from cls/search_path_returns_dir
Fix search_path not to return directories on POSIX
2018-02-14 15:41:58 +01:00
Connor Lane Smith
a610fe74ff Fix search_path not to return directories on POSIX 2018-02-14 13:56:34 +00:00
Klemens Morgenstern
ea49952da2 Merge pull request #141 from markus-t314/fix_issue139
Fix: Inconsistent behaviour in various overloaded functions/methods #139
2018-02-09 21:15:19 +01:00
Markus Tillinger
a55946eb5d Fix: Inconsistent behaviour in various overloaded functions/methods #139
Removed duplicated code in overloaded functions.
Replaced system_clock with steady_clock.
2018-02-08 21:49:49 +01:00
Klemens Morgenstern
9f6c338631 Merge pull request #140 from klemens-morgenstern/develop
master update
2018-02-07 00:19:10 +01:00
Klemens David Morgenstern
60302c0017 Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2018-02-06 20:20:18 +01:00
Klemens David Morgenstern
08eaf8b7a1 added BOOST_NO_ANSI_APIS support, closes #26 2018-02-06 20:20:02 +01:00
Klemens Morgenstern
cc70ec9362 Update pipe_in.hpp 2018-02-06 10:29:16 +01:00
Klemens Morgenstern
b58ecc7c9d Update async_in.hpp 2018-02-06 10:27:16 +01:00
Klemens Morgenstern
668cbcdaf4 Update windows.hpp 2018-02-06 10:23:02 +01:00
Klemens David Morgenstern
6d7cbd0989 closes #83 2018-02-06 00:32:55 +01:00
Klemens David Morgenstern
0764f788a6 typo fix 2018-02-06 00:24:45 +01:00
Klemens David Morgenstern
2b95dd7011 Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2018-02-06 00:08:26 +01:00
Klemens David Morgenstern
ae380c30ad added CREATE_NO_WINDOW flags, closes #129 2018-02-06 00:07:35 +01:00
Klemens Morgenstern
d2265890bd Merge pull request #138 from markus-t314/consistent_wait_handling
Fixed inconsistent posix-wait-handling
2018-02-05 23:42:04 +01:00
Klemens Morgenstern
831d49c1b3 Merge pull request #137 from markus-t314/fix_issue136
Fix: [posix] inconsistent exit status when child received signal #136
2018-02-05 23:38:59 +01:00
Klemens Morgenstern
6935c53510 Merge pull request #132 from egorpugin/patch-1
Fix initialization of atomic var. This fixes mingw build.
2018-02-05 23:34:11 +01:00
Klemens David Morgenstern
f30d90a179 Merge remote-tracking branch 'remotes/boostorg/develop' into develop 2018-02-05 23:32:17 +01:00
Klemens Morgenstern
55cfcecfb8 Merge pull request #27 from adrianimboden/develop
fix use of uninitalized variable
2018-02-05 23:16:21 +01:00
Klemens Morgenstern
233f46a2cb Merge pull request #30 from cinghiale/patch-1
update the code snippets to reflect the doc
2018-02-05 23:15:15 +01:00
Markus Tillinger
342554b3d8 Fixed inconsistent posix-wait-handling
Refactored: Removed duplicated code
Made wait_until compatible with steady_clock
2018-02-03 22:11:37 +01:00
Markus Tillinger
7aa812a0e1 Fix: [posix] inconsistent exit status when child received signal #136 2018-02-03 17:47:14 +01:00
Klemens Morgenstern
c4ffd0c18d Merge pull request #135 from klemens-morgenstern/develop
Appveyor fixes
2018-02-02 23:26:12 +01:00
Klemens David Morgenstern
a411f06dc4 Merge remote-tracking branch 'remotes/origin/master' into develop
# Conflicts:
#	test/Jamfile.jam
#	test/async_system_stackless.cpp
2018-02-02 22:37:32 +01:00
Klemens David Morgenstern
d085262076 added /bigobj flag for msvc 2018-02-02 22:14:42 +01:00
Klemens David Morgenstern
0396740467 splitted up the async_system tests 2018-02-02 21:52:14 +01:00
Klemens Morgenstern
0fd7de9481 Merge pull request #134 from hrayrbabajanyan/patch-1
eval_exit_status would return 0 in case if the child received SIBABRT
2018-02-01 20:44:00 +01:00
hrayrbabajanyan
ba790dad0a eval_exit_status would return 0 in case if the child received SIBABRT 2018-02-01 02:53:24 +04:00
David Mugnai
f2e8776965 update the code snippets to reflect the doc 2018-01-23 23:35:54 +01:00
Adrian Imboden
444d5eb702 fix use of uninitalized variable 2018-01-06 13:36:42 +01:00
Egor Pugin
3e12e989ab Fix initialization of atomic var. This fixes mingw build. 2018-01-06 14:04:32 +03:00
252 changed files with 20194 additions and 1575 deletions

75
.circleci/config.yml Normal file
View File

@@ -0,0 +1,75 @@
version: 2
jobs:
build:
environment:
- BOOST_LIBRARY=process
- CXX_STANDARD=gnu++11
docker:
- image: gcc:7
steps:
- checkout
- run:
name: Setting up Environment
command: |
echo 'export BOOST="$HOME/boost-local"' >> $BASH_ENV
if [ $CIRCLE_BRANCH = "master" ]; then
echo 'export BOOST_BRANCH="master"' >> $BASH_ENV;
else
echo 'export BOOST_BRANCH="develop"' >> $BASH_ENV;
fi
echo 'export BOOST_REMOVE="$BOOST/libs/$BOOST_LIBRARY"' >> $BASH_ENV
HOME_SED_=$(echo $HOME | sed -e 's/\//\\\//g')
echo 'export HOME_SED=$HOME_SED_' >> $BASH_ENV
- run:
name: install pre dependencies
command: |
apt-get update -yqq
apt-get install git curl valgrind -y
- run:
name: Initializing git repo for boost
command: |
git init $BOOST
cd $BOOST
echo Testing $BRANCH_TO_TEST
git remote add --no-tags -t $BOOST_BRANCH origin https://github.com/boostorg/boost.git
git fetch --depth=1
git checkout $BOOST_BRANCH
git submodule update --init --merge
git remote set-branches --add origin $BOOST_BRANCH
git pull --recurse-submodules
git submodule update --init
git checkout $BOOST_BRANCH
git submodule foreach "git reset --quiet --hard; git clean -fxd"
git reset --hard; git clean -fxd
git status
rm -rf $BOOST_REMOVE
mv $HOME/project $BOOST_REMOVE
- run:
name: Bootstrapping boost-build
command: |
cd $BOOST
./bootstrap.sh
./b2 headers
- run:
name: Building examples
command: |
cd $BOOST_REMOVE/example
../../../b2 -j2 address-model=64 architecture=x86 toolset=gcc cxxflags="-std=gnu++14" -sBOOST_BUILD_PATH=. | tee example.log || FAILED=1
sed -i -e "s/^..\/..\/..\/boost\/process\//\/root\/project\/include\/boost\/process\//gm" example.log
python <(curl -s https://report.ci/annotate.py) --tool gcc --name "Circle CI Gcc Build" --input example.log
exit $FAILED
- run:
name: Running Unit tests
command: |
cd $BOOST_REMOVE/test
../../../b2 -j2 with-valgrind address-model=64 architecture=x86 testing.launcher=valgrind valgrind=on toolset=gcc cxxflags="--coverage -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. | tee test.log || FAILED=1
../../../b2 -j2 without-valgrind address-model=64 architecture=x86 toolset=gcc cxxflags="--coverage -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. | tee no-valgrind.log || FAILED=1
sed -i -e "s/^..\/..\/..\/boost\/process\//\/root\/project\/include\/boost\/process\//gm" test.log
sed -i -e "s/^..\/..\/..\/boost\/process\//\/root\/project\/include\/boost\/process\//gm" no-valgrind.log
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
echo "BUILD_RESULT: $FAILED"
exit $FAILED

38
.drone.star Normal file
View File

@@ -0,0 +1,38 @@
# 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")

36
.drone/drone.bat Executable file
View File

@@ -0,0 +1,36 @@
@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 -j3
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/example -j3
) else if "%DRONE_JOB_BUILDTYPE%" == "standalone-windows" (
REM not used
)

199
.drone/drone.sh Executable file
View File

@@ -0,0 +1,199 @@
#!/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

375
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,375 @@
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-4.8
cxxstd: "11"
os: ubuntu-18.04
install: g++-4.8
- 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-8
cxxstd: "11,14,17,2a"
os: ubuntu-18.04
install: g++-8
- toolset: gcc-9
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
- toolset: gcc-10
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-10
- toolset: gcc-11
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-11
- toolset: gcc-12
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
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
posix-cmake-subdir:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Use library with add_subdirectory
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
- name: Install
run: |
cd ../boost-root/__build__
cmake --build . --target install
- name: Use the installed library
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
- name: Build tests
run: |
cd ../boost-root/__build__
cmake --build . --target tests
- name: Run tests
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error

1
.gitignore vendored
View File

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

View File

@@ -10,28 +10,6 @@
#
# File revision #6
env:
global:
# Autodetect Boost branch by using the following code: - BRANCH_TO_TEST=$TRAVIS_BRANCH
# or just directly specify it
- BRANCH_TO_TEST=$TRAVIS_BRANCH
# Files, which coverage results must be ignored (files from other projects).
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
- IGNORE_COVERAGE=''
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
# from `Boost.DLL` repo, while Boost already has `dll`.
#
# By default is eaual to - BOOST_REMOVE=`basename $TRAVIS_BUILD_DIR`
# This will force to use local repo content, instead of the Boost's default
# not needed because process is not yet in boost.
- BOOST_REMOVE=process
matrix:
- CXX_STANDARD=c++11 TOOLSET=gcc-5
- CXX_STANDARD=c++1y TOOLSET=gcc-5
###############################################################################################################
# From this point and below code is same for all the Boost libs
@@ -39,81 +17,120 @@ env:
sudo: false
language: cpp
compiler:
- gcc
- gcc
os:
- linux
- linux
- osx
env:
matrix:
- BADGE=linux
- BADGE=osx
global:
# Autodetect Boost branch by using the following code: - BRANCH_TO_TEST=$TRAVIS_BRANCH
# or just directly specify it
- BRANCH_TO_TEST=$TRAVIS_BRANCH
# Files, which coverage results must be ignored (files from other projects).
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
- IGNORE_COVERAGE=''
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
# from `Boost.DLL` repo, while Boost already has `dll`.
#
# By default is eaual to - BOOST_REMOVE=`basename $TRAVIS_BUILD_DIR`
# This will force to use local repo content, instead of the Boost's default
# not needed because process is not yet in boost.
- BOOST_REMOVE=process
- CXX_STANDARD=gnu++11
matrix:
exclude:
- os: linux
env: BADGE=osx
- os: osx
env: BADGE=linux
# Installing additional tools
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- ubuntu-toolchain-r-test
packages:
- valgrind
- python-yaml
- gcc-5
- g++-5
# - lcov
- clang
- valgrind
- python-yaml
- gcc-5
- g++-5
# - lcov
- clang
before_install:
# Set this to the name of the library
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
- echo "Testing $PROJECT_TO_TEST"
# Cloning Boost libraries (fast nondeep cloning)
- BOOST=$HOME/boost-local
- git init $BOOST
- cd $BOOST
- if [ $BRANCH_TO_TEST = "master" ]; then
BOOST_BRANCH=master;
else BOOST_BRANCH=develop; fi
- git remote add --no-tags -t $BOOST_BRANCH origin https://github.com/boostorg/boost.git
- git fetch --depth=1
- git checkout $BOOST_BRANCH
- git submodule update --init --merge
- git remote set-branches --add origin $BOOST_BRANCH
- git pull --recurse-submodules
- git submodule update --init
- git checkout $BOOST_BRANCH
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
- git reset --hard; git clean -fxd
- git status
- echo "Removing $BOOST/libs/$BOOST_REMOVE"
- rm -rf $BOOST/libs/$BOOST_REMOVE
- mv $TRAVIS_BUILD_DIR/../$PROJECT_TO_TEST/ $BOOST/libs/$PROJECT_TO_TEST
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
- ./bootstrap.sh
- ./b2 headers
- cd $BOOST/libs/$PROJECT_TO_TEST/test
# 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
# Cloning Boost libraries (fast nondeep cloning)
- BOOST=$HOME/boost-local
- git init $BOOST
- cd $BOOST
- echo Branch to test $BRANCH_TO_TEST
- if [ $BRANCH_TO_TEST = "master" ]; then
BOOST_BRANCH=master;
else BOOST_BRANCH=develop; fi
- git remote add --no-tags -t $BOOST_BRANCH origin https://github.com/boostorg/boost.git
- git fetch --depth=1
- git checkout $BOOST_BRANCH
- git submodule update --init --merge
- git remote set-branches --add origin $BOOST_BRANCH
- git pull --recurse-submodules || true
- git submodule update --init
- git checkout $BOOST_BRANCH
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
- git reset --hard; git clean -fxd
- git status
- echo "Removing $BOOST/libs/$BOOST_REMOVE"
- rm -rf $BOOST/libs/$BOOST_REMOVE
- mv $TRAVIS_BUILD_DIR/../$PROJECT_TO_TEST/ $BOOST/libs/$PROJECT_TO_TEST
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
- ./bootstrap.sh
- ./b2 headers
- cd $BOOST/libs/$PROJECT_TO_TEST/test
- echo BOOST_TEST_CATCH_SYSTEM_ERRORS $BOOST_TEST_CATCH_SYSTEM_ERRORS
script:
# `--coverage` flags required to generate coverage info for Coveralls
- ../../../b2 with-valgrind address-model=64 architecture=x86 testing.launcher=valgrind valgrind=on toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
- ../../../b2 without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
# `--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
after_success:
# Copying Coveralls data to a separate folder
- mkdir -p $TRAVIS_BUILD_DIR/coverals
- find ../../../bin.v2/ -name "*.gcda" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.gcno" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
# Copying Coveralls data to a separate folder
- mkdir -p $TRAVIS_BUILD_DIR/coverals
- find ../../../bin.v2/ -name "*.gcda" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
- find ../../../bin.v2/ -name "*.gcno" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
# Preparing Coveralls data by changind data format to a readable one
- git clone https://github.com/linux-test-project/lcov.git lcov_dir
- GCOV_VERSION=""
- if [[ "$TOOLSET" == *"-"* ]]; then GCOV_VERSION="--gcov-tool gcov-${TOOLSET#*-}"; fi
- LCOV="$BOOST/libs/$PROJECT_TO_TEST/test/lcov_dir/bin/lcov $GCOV_VERSION"
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory ./ --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
# Preparing Coveralls data by changind data format to a readable one
- git clone https://github.com/linux-test-project/lcov.git lcov_dir
- GCOV_VERSION=""
- if [[ "$TOOLSET" == *"-"* ]]; then GCOV_VERSION="--gcov-tool gcov-${TOOLSET#*-}"; fi
- LCOV="$BOOST/libs/$PROJECT_TO_TEST/test/lcov_dir/bin/lcov $GCOV_VERSION"
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory ./ --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
# ... erasing /test/ /example/ folder data
- cd $BOOST
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$PROJECT_TO_TEST/test/*" $IGNORE_COVERAGE "*/$PROJECT_TO_TEST/tests/*" "*/$PROJECT_TO_TEST/examples/*" "*/$PROJECT_TO_TEST/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
# ... erasing /test/ /example/ folder data
- cd $BOOST
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "*.cpp" "/usr*" "*/$PROJECT_TO_TEST/test/*" $IGNORE_COVERAGE "*/$PROJECT_TO_TEST/tests/*" "*/$PROJECT_TO_TEST/examples/*" "*/$PROJECT_TO_TEST/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
# ... erasing data that is not related to this project directly
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$PROJECT_TO_TEST\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
- echo $OTHER_LIBS
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info"
# ... erasing data that is not related to this project directly
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/process\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
- echo $OTHER_LIBS
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info" > /dev/null
# Sending data to Coveralls
- cd $TRAVIS_BUILD_DIR
- gem install coveralls-lcov
- coveralls-lcov coverals/coverage.info
# Sending data to Coveralls
- cd $TRAVIS_BUILD_DIR
- gem install coveralls-lcov
- coveralls-lcov coverals/coverage.info
after_script:
- 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"

36
CMakeLists.txt Normal file
View File

@@ -0,0 +1,36 @@
# 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 INTERFACE)
add_library(Boost::process ALIAS boost_process)
target_include_directories(boost_process INTERFACE include)
target_link_libraries(boost_process
INTERFACE
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
)
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()

View File

@@ -1,17 +1,21 @@
# [Boost Process (Boost.Process)](https://github.com/klemens-morgenstern/boost-process)
# [Boost Process (Boost.Process)](https://github.com/boostorg/process)
Boost.process is a library for comfortable management of processes, released with boost 1.64.0.
### Test results
Branches | Build | Tests coverage |
----------------|-------------- | -------------- |
Develop: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=develop)](https://travis-ci.org/klemens-morgenstern/boost-process) [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process) | [![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) |
Master: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=master)](https://travis-ci.org/klemens-morgenstern/boost-process) [![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) | [![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) |
| 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) |
[Open Issues](https://github.com/klemens-morgenstern/boost-process/issues)
[Latest developer documentation](http://klemens-morgenstern.github.io/process/)
[Open Issues](https://github.com/boostorg/process/issues)
[Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/process.html)
### 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

@@ -24,12 +24,13 @@ generators.register-standard common.copy : XML : XMLPROCESSWORKAROUND ;
xmlprocessworkaround posix_pseudocode : posix_pseudocode.xml ;
xmlprocessworkaround windows_pseudocode : windows_pseudocode.xml ;
path-constant INCLUDES : ../../.. ;
doxygen autodoc
:
../../../boost/process.hpp
[ glob ../../../boost/process/*.hpp ]
:
$(INCLUDES)/boost/process.hpp
[ glob $(INCLUDES)/boost/process/*.hpp ]
:
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
<doxygen:param>PREDEFINED=BOOST_PROCESS_DOXYGEN
<doxygen:param>HIDE_UNDOC_CLASSES=YES
@@ -42,11 +43,49 @@ doxygen autodoc
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_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>autodoc
<dependency>reference_v2
<dependency>images
<dependency>images_glob
<xsl:param>boost.root=../../../..

View File

@@ -8,4 +8,6 @@ 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 not, that if the the same thread reads and write to a pipe, it will only talk to itself.
Though please note, that if the same thread reads and writes to a pipe, it will only talk to itself.
[section:anonymous Anonymous Pipes]
The usual type of pipes, are the anonymous ones. Since the have no name,
The most common pipes are anonymous. Since they 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:
@@ -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 not such encoding currently in the library.
there are more codes associated with that, but not so on windows. Therefore there is no 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 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 do 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 an wrapper around the different OS-specific methods
This library is meant to give a 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 avaible styles will be described. Note that the
In the following section the available 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 version can be set explicitly:
several strings will yield a exe-args interpretation. Both versions 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 it wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
If the same effect is 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]

View File

@@ -5,24 +5,24 @@
[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_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]]
[def __require_io_service__ [classref boost::process::extend::require_io_service ex::require_io_service]]
[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::extend::require_io_context ex::require_io_context]]
[def __async_handler__ [classref boost::process::extend::async_handler ex::async_handler]]
[def __get_io_service__ [funcref boost::process::extend::get_io_service ex::get_io_service]]
[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 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
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::extend::handler] it will be regarded as an 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 is consists of three functions, as given below:
The basic structure consists of three functions, as given below:
* [globalref boost::process::extend::on_setup on_setup]
* [globalref boost::process::extend::on_error on_error]
@@ -50,10 +50,10 @@ So let's start with a simple hello-world example, while we use a C++14 generic l
using namespace boost::process;
namespace ex = bp::extend;
__child__ c("foo", ex::__on_success__=[](auto & exec) {std::cout << "hello world" << std::endl;});
__child__ c("foo", __on_success__=[](auto & exec) {std::cout << "hello world" << std::endl;});
```
Considering that lambda can also capture values, data can easily be shared between handlers.
Considering that lambdas can also capture values, data can easily be shared between handlers.
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].
@@ -86,7 +86,7 @@ __child__ c("foo", hello_world());
[note The implementation is done via overloading, not overriding.]
Every handler not implemented dafaults to [classref boost::process::extend::handler handler], where an empty handler is defined for each event.
Every handler not implemented defaults to [classref boost::process::extend::handler handler], where an empty handler is defined for each event.
[endsect]
@@ -95,26 +95,24 @@ Every handler not implemented dafaults to [classref boost::process::extend::hand
[section:async Asynchronous Functionality]
Since `boost.process` provides an interface for [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio],
this functionality is also available for extensions. If the class needs the io_service for some reason, the following code will do that.
this functionality is also available for extensions. If the class needs the __io_context__ for some reason, the following code will do that.
```
struct async_foo : __handler__, __require_io_service__
struct async_foo : __handler__, __require_io_context__
{
tempalte<typename Executor>
template<typename Executor>
void on_setup(Executor & exec)
{
io_service & ios = __get_io_service__(exec.seq); //gives us a reference and a compiler error if not present.
__io_context__ & ios = __get_io_context__(exec.seq); //gives us a reference and a compiler error if not present.
//do something with ios
}
};
```
[caution All async_handlers use one signal(SIGCHLD) on posix, which is only guaranteed to work when all use the same `io_service`]
[note Inheriting [globalref boost::process::extend::require_io_service require_io_service] is necessary, so [funcref boost::process::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::extend::async_handler async_handler] implies [globalref boost::process::extend::require_io_service require_io_service] .]
[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__
@@ -122,8 +120,8 @@ struct async_bar : __handler, __async_handler__
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
{
auto handler = this->handler;
return [handler](int exit_code, const std::error_code & ec)
auto handler_ = this->handler;
return [handler_](int exit_code, const std::error_code & ec)
{
std::cout << "hello world, I exited with " << exit_code << std::endl;
};
@@ -135,14 +133,16 @@ struct async_bar : __handler, __async_handler__
[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). ]
[endsect]
[section:error Error handling]
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
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
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 cofiguration of the executor, this may either throw, set an internal `error_code`, or do nothing.
Depending on the configuration 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`.
@@ -202,8 +202,8 @@ struct hello_exe : __handler__
};
```
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.
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.
[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 automatically pipe-closing in this library, because
[note It is not possible to use automatic 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

@@ -11,6 +11,8 @@
]
]
[note [link process.v2 Process V2] is available as experimental]
[include introduction.qbk]
[include concepts.qbk]
[include tutorial.qbk]
@@ -19,3 +21,4 @@
[include faq.qbk]
[xinclude autodoc.xml]
[include acknowledgements.qbk]
[include v2.qbk]

View File

@@ -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 (or the explicit form bp::cmd), it will be interpreted as a command line.
If a single string is given (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::filesystem::path`, we can do this too.
from an external source as `boost::process::filesystem::path`, we can do this too.
```
boost::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
boost::process::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
int result = bp::system(p, "main.cpp");
```
@@ -93,7 +93,7 @@ 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::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else.
boost::process::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else.
int result = bp::system(p, "main.cpp");
```
@@ -104,8 +104,8 @@ This also includes to add a file suffix on windows, such as `.exe` or `.bat`.]
[section:launch_mode Launch functions]
Given that in our example used the [funcref boost::process::system system] function,
our program will wait until the child process is completed. This maybe unwanted,
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.
@@ -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 a until a time point with __wait_for__ and __wait_until__]
[note You can also wait for a time span or 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]
@@ -151,14 +151,14 @@ This can be avoided by calling __detach__ beforehand]
Until now, we have assumed that everything works out, but it is not impossible,
that "g++" is not present. That will cause the launch of the process to fail.
The default behaviour of all functions is to throw an
The default behaviour of all functions is to throw a
[@http://en.cppreference.com/w/cpp/error/system_error std::system_error] on failure.
As with many other functions in this library, passing an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code]
will change the behaviour, so that instead of throwing an exception, the error will be a assigned to the error code.
will change the behaviour, so that instead of throwing an exception, the error will be assigned to the error code.
```
std::error_code ec;
bp::system c("g++ main.cpp", ec);
bp::system("g++ main.cpp", ec);
```
[endsect]
[section:io Synchronous I/O]
@@ -217,8 +217,7 @@ 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.
[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]]
[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
@@ -247,7 +246,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
//we just use the same pipe, so the output of nm is directly passed as input to c++filt
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);
@@ -271,7 +270,7 @@ If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boos
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. `nm` we might analyze it line by line,
Now we get back to our compiling example. For `nm` we might analyze the output 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.
@@ -288,26 +287,24 @@ asio_async_read(ap, asio_buffer(buf),
[](const boost::system::error_code &ec, std::size_t size){});
ios.run();
c.wait();
int result = c.exit_code();
```
To make it easier, boost.process provides simpler interface for that, so that the buffer can be passed directly,
To make it easier, boost.process provides a simpler interface for that, so that the buffer can be passed directly,
provided we also pass a reference to an io_service.
```
io_service ios;
std::vector<char> buf;
std::vector<char> buf(4096);
bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > asio_buffer(buf), ios);
ios.run();
c.wait();
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::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.
@@ -334,7 +331,7 @@ auto err = data.get();
[endsect]
[section:group Groups]
When launching several processes, processes can be grouped together.
When launching several processes, they 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,
@@ -345,7 +342,7 @@ 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 program like `make`, which does launch its own child processes,
If we have a 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:
@@ -415,14 +412,14 @@ bp::system("stuff", env_);
```
A more convenient way to modify the environment for the child is the
[globalref boost::process::env env] property, which the example as following:
[globalref boost::process::env env] property, which can be used in the example as following:
```
bp::system("stuff", bp::env["VALUE_1"]="foo", bp::env["VALUE_2"]+={"bar1", "bar2"});
```
Please see to the [headerref boost/process/environment.hpp reference] for more information.
Please see the [headerref boost/process/environment.hpp reference] for more information.
[endsect]
[endsect]

11
doc/v2.qbk Normal file
View File

@@ -0,0 +1,11 @@
[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]

48
doc/v2/env.qbk Normal file
View File

@@ -0,0 +1,48 @@
[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 recommented to use the environment types,
as to have the right value comparisons.
To note is the `find_executable` functions, which searches in an environment for an executable.
```
// 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++"), my_env);
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env));
```
[endsect]
[endsect]

94
doc/v2/introduction.qbk Normal file
View File

@@ -0,0 +1,94 @@
[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 adresses one logical compoent (e.g. stdio) instead of multiple ones accumulating.
Furthermore, every process has a path and arguments, instead of a confusing mixture of cmd-style and
exe-args that can be randomly spread out.
[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]

128
doc/v2/launcher.qbk Normal file
View File

@@ -0,0 +1,128 @@
[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::eror_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_initalizer
{
// 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 occured during setup or process creation
template<typename Launcher>
void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
const error_code & ec);
// 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 occured when forking, in addtion to on_error.
template<typename Launcher>
void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
const error_code & ec);
// 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 streight 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 occured during setup or process creation
template<typename Launcher>
void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
const error_code & ec);
// 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]

124
doc/v2/quickstart.qbk Normal file
View File

@@ -0,0 +1,124 @@
[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 addtional 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 demaning certain actions.
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
This is the only reliable & portable way to end a subprocess.
```
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` functons 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 timout{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]

16
doc/v2/start_dir.qbk Normal file
View File

@@ -0,0 +1,16 @@
[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]

89
doc/v2/stdio.qbk Normal file
View File

@@ -0,0 +1,89 @@
[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;
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

@@ -10,6 +10,9 @@
//[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::filesystem::path p = "input.txt";
boost::process::filesystem::path p = "input.txt";
bp::system(
"test.exe",

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/filesystem.hpp>
#include <boost/process/filesystem.hpp>
namespace bp = boost::process;
@@ -19,9 +19,9 @@ int main()
bp::start_dir="../foo"
);
boost::filesystem::path exe = "test.exe";
boost::process::filesystem::path exe = "test.exe";
bp::system(
boost::filesystem::absolute(exe),
boost::process::filesystem::absolute(exe),
bp::start_dir="../foo"
);
}

17
example/v2/Jamfile.jam Normal file
View File

@@ -0,0 +1,17 @@
# 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 ;

39
example/v2/intro.cpp Normal file
View File

@@ -0,0 +1,39 @@
// Copyright (c) 2022Klemens Morgernstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//[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

@@ -0,0 +1,36 @@
// Copyright (c) 2022Klemens Morgernstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//[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,6 +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/extend.hpp>
#include <boost/process/windows.hpp>
#include <iostream>
@@ -22,9 +23,9 @@ int main()
bp::system("test.exe",
bp::on_setup([](auto &e)
bp::extend::on_setup([](auto &e)
{ e.startup_info.dwFlags = STARTF_RUNFULLSCREEN; }),
bp::on_error([](auto&, const std::error_code & ec)
bp::extend::on_error([](auto&, const std::error_code & ec)
{ std::cerr << ec.message() << std::endl; })
);
}

14
filter_section_warning.py Normal file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/python
#
import sys
for line in sys.stdin:
# If line is a 'noisy' warning, don't print it or the following two lines.
if ('warning: section' in line and 'is deprecated' in line
or 'note: change section name to' in line):
next(sys.stdin)
next(sys.stdin)
else:
sys.stdout.write(line)
sys.stdout.flush()

View File

@@ -30,6 +30,7 @@
#include <boost/process/error.hpp>
#include <boost/process/exe.hpp>
#include <boost/process/group.hpp>
#include <boost/process/handles.hpp>
#include <boost/process/io.hpp>
#include <boost/process/pipe.hpp>
#include <boost/process/shell.hpp>

View File

@@ -138,7 +138,7 @@ struct args_
arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const
{
return arg_setter_<char>(range.begin(), range.end());
return arg_setter_<char, true>(range.begin(), range.end());
}
arg_setter_<char, true> operator+=(std::initializer_list<const char*> &&range) const
{
@@ -146,11 +146,11 @@ struct args_
}
arg_setter_<char, false> operator= (std::initializer_list<const char*> &&range) const
{
return arg_setter_<char, true>(range.begin(), range.end());
return arg_setter_<char, false>(range.begin(), range.end());
}
arg_setter_<char, true> operator()(std::initializer_list<std::string> &&range) const
{
return arg_setter_<char>(range.begin(), range.end());
return arg_setter_<char, true>(range.begin(), range.end());
}
arg_setter_<char, true> operator+=(std::initializer_list<std::string> &&range) const
{
@@ -158,12 +158,12 @@ struct args_
}
arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const
{
return arg_setter_<char, true>(range.begin(), range.end());
return arg_setter_<char, false>(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());
return arg_setter_<wchar_t, true>(range.begin(), range.end());
}
arg_setter_<wchar_t, true> operator+=(std::initializer_list<const wchar_t*> &&range) const
{
@@ -171,11 +171,11 @@ struct args_
}
arg_setter_<wchar_t, false> operator= (std::initializer_list<const wchar_t*> &&range) const
{
return arg_setter_<wchar_t, true>(range.begin(), range.end());
return arg_setter_<wchar_t, false>(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());
return arg_setter_<wchar_t, true>(range.begin(), range.end());
}
arg_setter_<wchar_t, true> operator+=(std::initializer_list<std::wstring> &&range) const
{
@@ -183,7 +183,7 @@ struct args_
}
arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const
{
return arg_setter_<wchar_t, true>(range.begin(), range.end());
return arg_setter_<wchar_t, false>(range.begin(), range.end());
}
};

View File

@@ -109,16 +109,18 @@ with `function` being a callable object with the signature `(int, const std::err
\code{.cpp}
io_context ios;
child c("ls", on_exit=[](int exit, const std::error_code& ec_in){});
child c("ls", ios, on_exit=[](int exit, const std::error_code& ec_in){});
std::future<int> exit_code;
chlid c2("ls", on_exit=exit_code);
chlid c2("ls", ios, 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 All `on_exit` use one signal(SIGCHLD) on posix, which is only guaranteed to work when all use the same `io_context`.
\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

View File

@@ -26,7 +26,7 @@ namespace boost { namespace process {
#if defined(BOOST_PROCESS_DOXYGEN)
/** Class implementing and asnychronous I/O-Object for use with boost.asio.
/** Class implementing an asnychronous I/O-Object for use with boost.asio.
* It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or
* boost::asio::posix::stream_descriptor.
*
@@ -47,6 +47,8 @@ public:
*/
typedef platform_specific handle_type;
typedef typename handle_type::executor_type executor_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.

View File

@@ -25,6 +25,7 @@
#include <type_traits>
#include <memory>
#include <boost/asio/async_result.hpp>
#include <boost/asio/post.hpp>
#include <boost/system/error_code.hpp>
#include <tuple>
@@ -37,12 +38,11 @@ namespace process {
namespace detail
{
template<typename ExitHandler>
template<typename Handler>
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;
Handler handler;
#if defined(BOOST_POSIX_API)
bool errored = false;
@@ -51,9 +51,8 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
template<typename ExitHandler_>
async_system_handler(
boost::asio::io_context & ios,
ExitHandler_ && exit_handler) : ios(ios), init(exit_handler)
ExitHandler_ && exit_handler) : ios(ios), handler(std::forward<ExitHandler_>(exit_handler))
{
}
@@ -63,18 +62,13 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
#if defined(BOOST_POSIX_API)
errored = true;
#endif
auto & h = init.completion_handler;
ios.post(
[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();
auto h = std::make_shared<Handler>(std::move(handler));
boost::asio::post(
ios.get_executor(),
[h, ec]() mutable
{
(*h)(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
});
}
template<typename Executor>
@@ -82,12 +76,12 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
{
#if defined(BOOST_POSIX_API)
if (errored)
return [](int exit_code, const std::error_code & ec){};
return [](int , const std::error_code &){};
#endif
auto & h = init.completion_handler;
auto h = std::make_shared<Handler>(std::move(handler));
return [h](int exit_code, const std::error_code & ec) mutable
{
h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
(*h)(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
};
}
};
@@ -118,21 +112,36 @@ inline boost::process::detail::dummy
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
#endif
namespace detail
{
struct async_system_init_op
{
template<typename Handler, typename ... Args>
void operator()(Handler && handler, asio::io_context & ios, Args && ... args)
{
detail::async_system_handler<typename std::decay<Handler>::type> async_h{ios, std::forward<Handler>(handler)};
child(ios, std::forward<Args>(args)..., async_h ).detach();
}
};
}
template<typename ExitHandler, typename ...Args>
inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args)
{
detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};
typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
has_err_handling;
static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
child(ios, std::forward<Args>(args)..., async_h ).detach();
return async_h.get_result();
return boost::asio::async_initiate<ExitHandler, void (boost::system::error_code, int)>(
detail::async_system_init_op{}, exit_handler, ios, std::forward<Args>(args)...
);
}

View File

@@ -92,6 +92,10 @@ class child
/** 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() */

View File

@@ -43,7 +43,7 @@ namespace boost { namespace process { namespace detail {
struct cmd_
{
constexpr cmd_() {}
constexpr cmd_() = default;
template<typename Char>
inline api::cmd_setter_<Char> operator()(const Char *s) const

View File

@@ -168,7 +168,7 @@ struct exe_builder
string_type exe;
std::vector<string_type> args;
void operator()(const boost::filesystem::path & data)
void operator()(const boost::process::filesystem::path & data)
{
not_cmd = true;
if (exe.empty())

View File

@@ -60,7 +60,7 @@ public:
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() {}
child() { } // Must be kept non defaulted for MSVC 14.1 & 14.2 #113
child& operator=(const child&) = delete;
child& operator=(child && lhs)
{
@@ -101,74 +101,62 @@ public:
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();}
bool running()
{
if (valid() && !_exited())
{
int code = -1;
auto res = boost::process::detail::api::is_running(_child_handle, code);
if (!res && !_exited())
_exit_status->store(code);
return res;
}
return false;
std::error_code ec;
bool b = running(ec);
boost::process::detail::throw_error(ec, "running error");
return b;
}
void terminate()
{
if (valid() && running())
boost::process::detail::api::terminate(_child_handle);
_terminated = true;
std::error_code ec;
terminate(ec);
boost::process::detail::throw_error(ec, "terminate error");
}
void wait()
{
if (!_exited() && valid())
{
int exit_code = 0;
boost::process::detail::api::wait(_child_handle, exit_code);
_exit_status->store(exit_code);
}
std::error_code ec;
wait(ec);
boost::process::detail::throw_error(ec, "wait error");
}
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
template< class Rep, class Period >
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
BOOST_DEPRECATED("wait_for is unreliable")
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
{
if (!_exited())
{
int exit_code = 0;
auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time);
if (!b)
return false;
_exit_status->store(exit_code);
}
return true;
std::error_code ec;
bool b = wait_for(rel_time, ec);
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 )
{
if (!_exited())
{
int exit_code = 0;
auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time);
if (!b)
return false;
_exit_status->store(exit_code);
}
return true;
std::error_code ec;
bool b = wait_until(timeout_time, ec);
boost::process::detail::throw_error(ec, "wait_until error");
return b;
}
#endif
bool running(std::error_code & ec) noexcept
{
if (valid() && !_exited())
ec.clear();
if (valid() && !_exited() && !ec)
{
int code;
auto res = boost::process::detail::api::is_running(_child_handle, code, ec);
if (!res && !_exited())
_exit_status->store(code);
int exit_code = 0;
auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec);
if (!ec && !res && !_exited())
_exit_status->store(exit_code);
return res;
}
@@ -177,10 +165,11 @@ public:
void terminate(std::error_code & ec) noexcept
{
if (valid() && running(ec))
if (valid() && running(ec) && !ec)
boost::process::detail::api::terminate(_child_handle, ec);
_terminated = true;
if (!ec)
_terminated = true;
}
void wait(std::error_code & ec) noexcept
@@ -189,38 +178,34 @@ public:
{
int exit_code = 0;
boost::process::detail::api::wait(_child_handle, exit_code, ec);
_exit_status->store(exit_code);
if (!ec)
_exit_status->store(exit_code);
}
}
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
template< class Rep, class Period >
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
BOOST_DEPRECATED("wait_for is unreliable")
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
{
if (!_exited())
{
int exit_code = 0;
auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time, ec);
if (!b)
return false;
_exit_status->store(exit_code);
}
return true;
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::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
if (!b)
if (!b || ec)
return false;
_exit_status->store(exit_code);
}
return true;
}
#endif
bool valid() const
{

View File

@@ -57,6 +57,10 @@ inline std::error_code get_last_error() noexcept
#define BOOST_POSIX_HAS_VFORK 1
#endif
#if (_POSIX_C_SOURCE >= 199309L)
#define BOOST_POSIX_HAS_SIGTIMEDWAIT 1
#endif
#elif defined(BOOST_WINDOWS_API)
namespace windows {namespace extensions {}}
namespace api = windows;
@@ -82,6 +86,17 @@ inline void throw_last_error()
throw process_error(get_last_error());
}
inline void throw_error(const std::error_code& ec)
{
if (ec)
throw process_error(ec);
}
inline void throw_error(const std::error_code& ec, const char* msg)
{
if (ec)
throw process_error(ec, msg);
}
template<typename Char> constexpr Char null_char();
template<> constexpr char null_char<char> (){return '\0';}
@@ -99,6 +114,8 @@ 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

@@ -7,6 +7,7 @@
#define BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_
#include <memory>
#include <boost/asio/ts/netfwd.hpp>
namespace boost { namespace asio {
@@ -20,33 +21,19 @@ template<typename Allocator>
class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_context;
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class signal_set_service;
template <typename SignalSetService>
template <typename Executor>
class basic_signal_set;
typedef basic_signal_set<signal_set_service> signal_set;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class signal_set;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
typedef basic_signal_set<any_io_executor> signal_set;
template <typename Handler>
class basic_yield_context;
namespace posix {
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class stream_descriptor_service;
template <typename StreamDesscriptorService>
template <typename Executor>
class basic_stream_descriptor;
typedef basic_stream_descriptor<stream_descriptor_service> stream_descriptor;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class stream_descriptor;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
typedef basic_stream_descriptor<any_io_executor> stream_descriptor;
} //posix
} //asio

View File

@@ -16,13 +16,16 @@
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
#include <boost/process/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context
::boost::process::detail::posix::require_io_context,
::boost::process::detail::uses_handles
{
Buffer & buf;
@@ -33,36 +36,37 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
fut = promise->get_future(); return std::move(*this);
}
std::shared_ptr<boost::process::async_pipe> pipe;
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &exec)
inline void on_success(Executor)
{
auto pipe = this->pipe;
auto pipe_ = this->pipe;
if (this->promise)
{
auto promise = this->promise;
auto promise_ = this->promise;
boost::asio::async_write(*pipe, buf,
[pipe, promise](const boost::system::error_code & ec, std::size_t)
boost::asio::async_write(*pipe_, buf,
[pipe_, promise_](const boost::system::error_code & ec, std::size_t)
{
if (ec && (ec.value() != EBADF) && (ec.value() != EPERM) && (ec.value() != ENOENT))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
promise_->set_exception(std::make_exception_ptr(process_error(e)));
}
else
promise->set_value();
promise_->set_value();
});
}
else
boost::asio::async_write(*pipe, buf,
[pipe](const boost::system::error_code&ec, std::size_t size){});
boost::asio::async_write(*pipe_, buf,
[pipe_](const boost::system::error_code&, std::size_t){});
std::move(*pipe).source().close();
std::move(*pipe_).source().close();
this->pipe = nullptr;
}
@@ -76,16 +80,28 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
if (!pipe)
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::detail::get_last_error(), "dup2() failed");
::close(pipe->native_source());
if (pipe->native_source() != STDIN_FILENO)
::close(pipe->native_source());
::close(pipe->native_sink());
}
};

View File

@@ -19,6 +19,8 @@
#include <memory>
#include <exception>
#include <future>
#include <array>
#include <boost/process/detail/used_handles.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -45,12 +47,24 @@ 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::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context
::boost::process::detail::posix::require_io_context,
::boost::process::detail::uses_handles
{
Buffer & buf;
std::shared_ptr<boost::process::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};
}
async_out_buffer(Buffer & buf) : buf(buf)
{
@@ -61,7 +75,7 @@ struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t size){});
[pipe](const boost::system::error_code&, std::size_t){});
this->pipe = nullptr;
std::move(*pipe).sink().close();
@@ -89,6 +103,8 @@ struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_sink());
::close(pipe->native_source());
}
};
@@ -110,32 +126,35 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
fut = promise->get_future();
}
template <typename Executor>
inline void on_success(Executor &exec)
inline void on_success(Executor &)
{
auto pipe = this->pipe;
auto pipe_ = this->pipe;
auto buffer = this->buffer;
auto promise = this->promise;
auto buffer_ = this->buffer;
auto promise_ = this->promise;
boost::asio::async_read(*pipe, *buffer,
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t size)
boost::asio::async_read(*pipe_, *buffer_,
[pipe_, buffer_, promise_](const boost::system::error_code& ec, std::size_t)
{
if (ec && (ec.value() != ENOENT))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
promise_->set_exception(std::make_exception_ptr(process_error(e)));
}
else
{
std::istream is (buffer.get());
std::istream is (buffer_.get());
Type arg;
arg.resize(buffer->size());
is.read(&*arg.begin(), buffer->size());
promise->set_value(std::move(arg));
if (buffer_->size() > 0)
{
arg.resize(buffer_->size());
is.read(&*arg.begin(), buffer_->size());
}
promise_->set_value(std::move(arg));
}
});
std::move(*pipe).sink().close();
std::move(*pipe_).sink().close();
this->pipe = nullptr;
}
@@ -161,6 +180,7 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_sink());
::close(pipe->native_source());
}
};

View File

@@ -9,6 +9,7 @@
#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>
@@ -22,6 +23,12 @@ 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) {}
@@ -43,8 +50,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.assign (-1);
lhs._sink .assign (-1);
lhs._source = ::boost::asio::posix::stream_descriptor{lhs._source.get_executor()};
lhs._sink = ::boost::asio::posix::stream_descriptor{lhs._sink. get_executor()};
}
template<class CharT, class Traits = std::char_traits<CharT>>
@@ -69,10 +76,8 @@ public:
~async_pipe()
{
if (_sink .native_handle() != -1)
::close(_sink.native_handle());
if (_source.native_handle() != -1)
::close(_source.native_handle());
boost::system::error_code ec;
close(ec);
}
template<class CharT, class Traits = std::char_traits<CharT>>
@@ -109,9 +114,9 @@ public:
void async_close()
{
if (_sink.is_open())
_sink.get_io_context(). post([this]{_sink.close();});
boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
if (_source.is_open())
_source.get_io_context().post([this]{_source.close();});
boost::asio::post(_source.get_executor(), [this]{_source.close();});
}
template<typename MutableBufferSequence>
@@ -125,6 +130,18 @@ public:
return _sink.write_some(buffers);
}
template<typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
{
return _source.read_some(buffers, ec);
}
template<typename MutableBufferSequence>
std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
{
return _sink.write_some(buffers, ec);
}
native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native_handle();}
native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native_handle();}
@@ -136,7 +153,7 @@ public:
const MutableBufferSequence & buffers,
ReadHandler &&handler)
{
_source.async_read_some(buffers, std::forward<ReadHandler>(handler));
return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
}
template<typename ConstBufferSequence,
@@ -147,7 +164,7 @@ public:
const ConstBufferSequence & buffers,
WriteHandler&& handler)
{
_sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
}
@@ -206,8 +223,8 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
}
async_pipe::async_pipe(const async_pipe & p) :
_source(const_cast<async_pipe&>(p)._source.get_io_context()),
_sink( const_cast<async_pipe&>(p)._sink.get_io_context())
_source(const_cast<async_pipe&>(p)._source.get_executor()),
_sink( const_cast<async_pipe&>(p)._sink.get_executor())
{
//cannot get the handle from a const object.
@@ -238,8 +255,8 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
int sink;
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._source).native_handle();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._sink).native_handle();
if (source_in == -1)
source = -1;
else

View File

@@ -118,12 +118,8 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
else
exec.exe = &exe.front();
if (!args.empty())
{
cmd_impl = make_cmd();
exec.cmd_line = cmd_impl.data();
}
cmd_impl = make_cmd();
exec.cmd_line = cmd_impl.data();
}
static exe_cmd_init exe_args(std::string && exe, std::vector<std::string> && args) {return exe_cmd_init(std::move(exe), std::move(args));}
static exe_cmd_init cmd (std::string && cmd)
@@ -143,7 +139,7 @@ struct exe_cmd_init<char> : boost::process::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(
@@ -159,12 +155,16 @@ 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.front());
vec.push_back(exe.empty() ? empty_string : &exe.front());
for (auto & v : args)
vec.push_back(&v.front());
if (!args.empty()) {
for (auto & v : args)
vec.push_back(v.empty() ? empty_string : &v.front());
}
vec.push_back(nullptr);

View File

@@ -11,7 +11,7 @@
#define BOOST_PROCESS_POSIX_PIPE_HPP
#include <boost/filesystem.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/process/detail/posix/compare_handles.hpp>
#include <system_error>
#include <array>
@@ -82,22 +82,30 @@ public:
int_type write(const char_type * data, int_type count)
{
auto write_len = ::write(_sink, data, count * sizeof(char_type));
if (write_len == -1)
::boost::process::detail::throw_last_error();
int_type 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::detail::throw_last_error();
}
return write_len;
}
int_type read(char_type * data, int_type count)
{
auto read_len = ::read(_source, data, count * sizeof(char_type));
if (read_len == -1)
::boost::process::detail::throw_last_error();
int_type read_len;
while ((read_len = static_cast<int_type>(::read(_source, data, count * sizeof(char_type)))) == -1)
{
//Try again if interrupted
auto err = errno;
if (err != EINTR)
::boost::process::detail::throw_last_error();
}
return read_len;
}
bool is_open()
bool is_open() const
{
return (_source != -1) ||
(_sink != -1);

View File

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

View File

@@ -10,8 +10,9 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <array>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -20,6 +21,8 @@ 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<>

View File

@@ -56,6 +56,7 @@ public:
{
_buffer = _load();
_impl = _load_var(_buffer);
_env_impl = _impl.data();
}
string_type get(const pointer_type id) { return get(string_type(id)); }
@@ -94,7 +95,7 @@ public:
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = _impl.data();
native_handle_type native_handle() const {return environ;}
native_handle_type native_handle() const {return _env_impl;}
};
template<>
@@ -230,7 +231,7 @@ 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)
[&](const string_type & st) -> bool
{
if (st.size() <= id.size())
return false;
@@ -250,7 +251,7 @@ 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)
[&](const string_type & st) -> bool
{
if (st.size() <= id.size())
return false;
@@ -270,7 +271,7 @@ 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)
[&](const string_type & st) -> bool
{
if (st.size() <= id.size())
return false;
@@ -294,7 +295,11 @@ 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;

View File

@@ -22,47 +22,14 @@
#include <errno.h>
#include <unistd.h>
#if !defined(__GLIBC__)
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#endif
#include <boost/core/ignore_unused.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
inline int execvpe(const char* filename, char * const arg_list[], char* env[])
{
#if defined(__GLIBC__)
return ::execvpe(filename, arg_list, env);
#else
//use my own implementation
std::string fn = filename;
if ((fn.find('/') == std::string::npos) && ::access(fn.c_str(), X_OK))
{
auto e = ::environ;
while ((*e != nullptr) && !boost::starts_with(*e, "PATH="))
e++;
if (e != nullptr)
{
std::vector<std::string> path;
boost::split(path, *e, boost::is_any_of(":"));
for (const std::string & pp : path)
{
auto p = pp + "/" + filename;
if (!::access(p.c_str(), X_OK))
{
fn = p;
break;
}
}
}
}
return ::execve(fn.c_str(), arg_list, env);
#endif
}
template<typename Executor>
struct on_setup_t
{
@@ -85,7 +52,7 @@ struct on_error_t
template<typename T>
void operator()(T & t) const
{
t.on_error(exec, error);
t.on_error(exec, error);
}
};
@@ -157,13 +124,13 @@ struct on_fork_success_t
};
template<typename Executor> on_setup_t <Executor> call_on_setup (Executor & exec) {return exec;}
template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
{
return on_error_t<Executor> (exec, ec);
}
template<typename Executor> on_success_t<Executor> call_on_success(Executor & exec) {return exec;}
template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
{
return on_fork_error_t<Executor> (exec, ec);
}
@@ -184,15 +151,15 @@ class executor
int _pipe_sink = -1;
void write_error(const std::error_code & ec, const char * msg)
{
//I am the child
int len = ec.value();
::write(_pipe_sink, &len, sizeof(int));
const auto len = static_cast<int>(std::strlen(msg));
int data[2] = {ec.value(), len + 1};
len = std::strlen(msg) + 1;
::write(_pipe_sink, &len, sizeof(int));
::write(_pipe_sink, msg, len);
boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2));
boost::ignore_unused(::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_)
@@ -293,13 +260,44 @@ class executor
auto err = errno;
if ((err == EBADF) || (err == EPERM))//that should occur on success, therefore return.
return;
//EAGAIN not yet forked, EINTR interrupted, i.e. try again
//EAGAIN not yet forked, EINTR interrupted, i.e. try again
else if ((err != EAGAIN ) && (err != EINTR))
set_error(std::error_code(err, std::system_category()), "Error read pipe");
}
set_error(ec, std::move(msg));
}
std::string prepare_cmd_style_fn; //buffer
inline void prepare_cmd_style() //this does what execvpe does - but we execute it in the father process, to avoid allocations.
{
//use my own implementation
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="))
e++;
if ((e != nullptr) && (*e != nullptr))
{
std::vector<std::string> path;
//the beginning of the string contains "PATH="
boost::split(path, (*e) + 5, boost::is_any_of(":"));
for (const std::string & pp : path)
{
auto p = pp + "/" + exe;
if (!::access(p.c_str(), X_OK))
{
prepare_cmd_style_fn = p;
break;
}
}
}
}
exe = prepare_cmd_style_fn.c_str();
}
std::error_code _ec;
std::string _msg;
@@ -330,6 +328,13 @@ 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>
@@ -338,6 +343,8 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
boost::fusion::for_each(seq, call_on_setup(*this));
if (_ec)
return child();
if (cmd_style)
prepare_cmd_style();
this->pid = ::fork();
if (pid == -1)
@@ -349,10 +356,7 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
else if (pid == 0)
{
boost::fusion::for_each(seq, call_on_exec_setup(*this));
if (cmd_style)
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
else
::execve(exe, cmd_line, env);
::execve(exe, cmd_line, env);
auto ec = boost::process::detail::get_last_error();
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
_exit(EXIT_FAILURE);
@@ -368,71 +372,87 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
template<typename Sequence>
child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
{
int p[2];
if (::pipe(p) == -1)
{
set_error(::boost::process::detail::get_last_error(), "pipe(2) failed");
return child();
}
if (::fcntl(p[1], F_SETFD, FD_CLOEXEC) == -1)
{
set_error(::boost::process::detail::get_last_error(), "fcntl(2) failed");
return child();
}
_ec.clear();
boost::fusion::for_each(seq, call_on_setup(*this));
struct pipe_guard
{
int p[2];
pipe_guard() : p{-1,-1} {}
~pipe_guard()
{
if (p[0] != -1)
::close(p[0]);
if (p[1] != -1)
::close(p[1]);
}
} p{};
if (::pipe(p.p) == -1)
{
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::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();
}
_ec.clear();
boost::fusion::for_each(seq, call_on_setup(*this));
if (_ec)
{
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
if (cmd_style)
prepare_cmd_style();
this->pid = ::fork();
if (pid == -1)
{
_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));
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::detail::get_last_error();
_msg = "execve failed";
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
_write_error(_pipe_sink);
::close(p.p[1]);
_exit(EXIT_FAILURE);
return child();
}
::close(p.p[1]);
p.p[1] = -1;
_read_error(p.p[0]);
}
if (_ec)
{
//if an error occured we need to reap the child process
::waitpid(this->pid, nullptr, WNOHANG);
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
this->pid = ::fork();
if (pid == -1)
{
_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));
return child();
}
else if (pid == 0)
{
_pipe_sink = p[1];
::close(p[0]);
boost::fusion::for_each(seq, call_on_exec_setup(*this));
if (cmd_style)
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
else
::execve(exe, cmd_line, env);
_ec = boost::process::detail::get_last_error();
_msg = "execve failed";
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
_write_error(p[1]);
_exit(EXIT_FAILURE);
return child();
}
child c(child_handle(pid), exit_status);
::close(p[1]);
_read_error(p[0]);
::close(p[0]);
if (_ec)
{
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
else
boost::fusion::for_each(seq, call_on_success(*this));
boost::fusion::for_each(seq, call_on_success(*this));
if (_ec)
{
@@ -485,6 +505,8 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
return child();
}
_ec.clear();
if (cmd_style)
this->prepare_cmd_style();
this->pid = ::vfork();
if (pid == -1)
@@ -500,10 +522,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
{
boost::fusion::for_each(seq, call_on_exec_setup(*this));
if (cmd_style)
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
else
::execve(exe, cmd_line, env);
::execve(exe, cmd_line, env);
_ec = boost::process::detail::get_last_error();
_msg = "execve failed";
@@ -520,6 +539,7 @@ 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();
}

View File

@@ -12,11 +12,13 @@
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
#include <boost/process/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { namespace detail { namespace posix {
struct close_fd_ : handler_base_ext
struct close_fd_ : handler_base_ext, ::boost::process::detail::uses_handles
{
close_fd_(int fd) : fd_(fd) {}
@@ -27,12 +29,15 @@ struct close_fd_ : handler_base_ext
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
struct close_fds_ : handler_base_ext, ::boost::process::detail::uses_handles
{
public:
close_fds_(const Range &fds) : fds_(fds) {}
@@ -48,6 +53,8 @@ public:
}
}
Range& get_used_handles() {return fds_;}
private:
Range fds_;
};
@@ -55,7 +62,7 @@ private:
template <class FileDescriptor>
struct bind_fd_ : handler_base_ext
struct bind_fd_ : handler_base_ext, ::boost::process::detail::uses_handles
{
public:
bind_fd_(int id, const FileDescriptor &fd) : id_(id), fd_(fd) {}
@@ -67,6 +74,9 @@ public:
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_;

View File

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

View File

@@ -13,16 +13,22 @@
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <cstdio>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct file_in : handler_base_ext
struct file_in : handler_base_ext, ::boost::process::detail::uses_handles
{
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)) {}

View File

@@ -13,12 +13,13 @@
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct file_out : handler_base_ext
struct file_out : handler_base_ext, ::boost::process::detail::uses_handles
{
file_descriptor file;
int handle = file.handle();
@@ -27,6 +28,13 @@ struct file_out : handler_base_ext
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;

View File

@@ -6,14 +6,13 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_GROUP_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 { namespace detail { namespace posix {
struct group_handle
{
pid_t grp = -1;
@@ -26,7 +25,6 @@ struct group_handle
{
}
group_handle() = default;
~group_handle() = default;
@@ -38,14 +36,13 @@ struct group_handle
group_handle &operator=(const group_handle & c) = delete;
group_handle &operator=(group_handle && c)
{
grp = c.grp;
c.grp = -1;
return *this;
}
void add(handle_t proc)
{
{
if (::setpgid(proc, grp))
throw_last_error();
}
@@ -59,26 +56,17 @@ struct group_handle
{
return ::getpgid(proc) == grp;
}
bool has(handle_t proc, std::error_code & ec) noexcept
bool has(handle_t proc, std::error_code &) noexcept
{
return ::getpgid(proc) == grp;
}
bool valid() const
{
return grp != -1;
}
};
inline void terminate(group_handle &p)
{
if (::killpg(p.grp, SIGKILL) == -1)
boost::process::detail::throw_last_error("killpg(2) failed");
p.grp = -1;
}
inline void terminate(group_handle &p, std::error_code &ec) noexcept
{
if (::killpg(p.grp, SIGKILL) == -1)
@@ -89,15 +77,18 @@ inline void terminate(group_handle &p, std::error_code &ec) noexcept
p.grp = -1;
}
inline void terminate(group_handle &p)
{
std::error_code ec;
terminate(p, ec);
boost::process::detail::throw_error(ec, "killpg(2) failed in terminate");
}
inline bool in_group()
{
return true;
}
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */

View File

@@ -0,0 +1,148 @@
// Copyright (c) 2019 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_HANDLES_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_HANDLES_HPP_
#include <vector>
#include <system_error>
#include <dirent.h>
#include <sys/stat.h>
#include <algorithm>
#include <memory>
#include <cstdlib>
#include <boost/process/detail/posix/handler.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
using native_handle_type = int;
inline std::vector<native_handle_type> get_handles(std::error_code & ec)
{
std::vector<native_handle_type> res;
std::unique_ptr<DIR, void(*)(DIR*)> dir{::opendir("/dev/fd"), +[](DIR* p){::closedir(p);}};
if (!dir)
{
ec = ::boost::process::detail::get_last_error();
return {};
}
else
ec.clear();
auto my_fd = ::dirfd(dir.get());
struct ::dirent * ent_p;
while ((ent_p = readdir(dir.get())) != nullptr)
{
if (ent_p->d_name[0] == '.')
continue;
const auto conv = std::atoi(ent_p->d_name);
if (conv == 0 && (ent_p->d_name[0] != '0' && ent_p->d_name[1] != '\0'))
continue;
if (conv == my_fd)
continue;
res.push_back(conv);
}
return res;
}
inline std::vector<native_handle_type> get_handles()
{
std::error_code ec;
auto res = get_handles(ec);
if (ec)
boost::process::detail::throw_error(ec, "open_dir(\"/dev/fd\") failed");
return res;
}
inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
{
struct ::stat stat_;
if (::fstat(handle, &stat_) != 0)
{
ec = ::boost::process::detail::get_last_error();
}
else
ec.clear();
return S_ISCHR (stat_.st_mode) //This macro returns non-zero if the file is a character special file (a device like a terminal).
|| S_ISBLK (stat_.st_mode) // This macro returns non-zero if the file is a block special file (a device like a disk).
|| S_ISREG (stat_.st_mode) // This macro returns non-zero if the file is a regular file.
|| S_ISFIFO (stat_.st_mode) // This macro returns non-zero if the file is a FIFO special file, or a pipe. See section 15. Pipes and FIFOs.
|| S_ISSOCK (stat_.st_mode) ;// This macro returns non-zero if the file is a socket. See section 16. Sockets.;
}
inline bool is_stream_handle(native_handle_type handle)
{
std::error_code ec;
auto res = is_stream_handle(handle, ec);
if (ec)
boost::process::detail::throw_error(ec, "fstat() failed");
return res;
}
struct limit_handles_ : handler_base_ext
{
limit_handles_() {}
~limit_handles_() {}
mutable std::vector<int> used_handles;
template<typename Executor>
void on_setup(Executor & exec) const
{
used_handles = get_used_handles(exec);
}
template<typename Executor>
void on_exec_setup(Executor & exec) const
{
auto dir = ::opendir("/dev/fd");
if (!dir)
{
exec.set_error(::boost::process::detail::get_last_error(), "opendir(\"/dev/fd\")");
return;
}
auto my_fd = ::dirfd(dir);
struct ::dirent * ent_p;
while ((ent_p = readdir(dir)) != nullptr)
{
if (ent_p->d_name[0] == '.')
continue;
const auto conv = std::atoi(ent_p->d_name);
if ((conv == my_fd) || (conv == -1))
continue;
if (std::find(used_handles.begin(), used_handles.end(), conv) != used_handles.end())
continue;
if (::close(conv) != 0)
{
exec.set_error(::boost::process::detail::get_last_error(), "close() failed");
return;
}
}
::closedir(dir);
}
};
}}}}
#endif //PROCESS_HANDLES_HPP

View File

@@ -18,6 +18,7 @@
#include <boost/process/detail/posix/sigchld_service.hpp>
#include <boost/process/detail/posix/is_running.hpp>
#include <functional>
#include <type_traits>
@@ -63,7 +64,7 @@ struct async_handler_collector
void operator()(T & t) const
{
handlers.push_back(t.on_exit_handler(exec));
};
}
};
//Also set's up waiting for the exit, so it can close async stuff.
@@ -78,6 +79,7 @@ struct io_context_ref : handler_base_ext
template <class Executor>
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.
auto asyncs = boost::fusion::filter_if<
is_async_handler<
@@ -95,15 +97,24 @@ struct io_context_ref : handler_base_ext
auto & es = exec.exit_status;
auto wh = [funcs, es](int val, const std::error_code & ec)
{
es->store(val);
{
es->store(val);
for (auto & func : funcs)
func(WEXITSTATUS(val), ec);
};
func(::boost::process::detail::posix::eval_exit_status(val), ec);
};
sigchld_service.async_wait(exec.pid, std::move(wh));
}
template<typename Executor>
void on_setup (Executor &) const {/*ios.notify_fork(boost::asio::io_context::fork_prepare);*/}
template<typename Executor>
void on_exec_setup (Executor &) const {/*ios.notify_fork(boost::asio::io_context::fork_child);*/}
template <class Executor>
void on_error(Executor&, const std::error_code &) const {/*ios.notify_fork(boost::asio::io_context::fork_parent);*/}
private:
boost::asio::io_context &ios;
boost::process::detail::posix::sigchld_service &sigchld_service = boost::asio::use_service<boost::process::detail::posix::sigchld_service>(ios);

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2106 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)
@@ -13,37 +13,25 @@
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
// the glibc <bits/waitstatus.h> header) is the same across systems in practice.
constexpr int still_active = 0x017f;
static_assert(WIFSTOPPED(still_active), "Expected still_active to indicate WIFSTOPPED");
static_assert(!WIFEXITED(still_active), "Expected still_active to not indicate WIFEXITED");
static_assert(!WIFSIGNALED(still_active), "Expected still_active to not indicate WIFSIGNALED");
static_assert(!WIFCONTINUED(still_active), "Expected still_active to not indicate WIFCONTINUED");
constexpr int still_active = 0x7F;
static_assert(!WIFEXITED(still_active), "Internal Error");
inline bool is_running(const child_handle &p, int & exit_code)
inline bool is_running(int code)
{
int status;
auto ret = ::waitpid(p.pid, &status, WNOHANG|WUNTRACED);
if (ret == -1)
{
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
::boost::process::detail::throw_last_error("is_running error");
return false;
}
else if (ret == 0)
return true;
else //exited
{
if (WIFEXITED(status))
exit_code = status;
return false;
}
return !WIFEXITED(code) && !WIFSIGNALED(code);
}
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
int status;
auto ret = ::waitpid(p.pid, &status, WNOHANG|WUNTRACED);
auto ret = ::waitpid(p.pid, &status, WNOHANG);
if (ret == -1)
{
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
@@ -55,22 +43,36 @@ inline bool is_running(const child_handle &p, int & exit_code, std::error_code &
else
{
ec.clear();
if (WIFEXITED(status))
if (!is_running(status))
exit_code = status;
return false;
}
}
inline bool is_running(int code)
inline bool is_running(const child_handle &p, int & exit_code)
{
return !WIFEXITED(code);
std::error_code ec;
bool b = is_running(p, exit_code, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in is_running");
return b;
}
inline int eval_exit_status(int code)
{
return WEXITSTATUS(code);
if (WIFEXITED(code))
{
return WEXITSTATUS(code);
}
else if (WIFSIGNALED(code))
{
return WTERMSIG(code);
}
else
{
return code;
}
}
}}}}

View File

@@ -14,13 +14,21 @@
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
#include <boost/process/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { namespace detail { namespace posix {
struct null_in : handler_base_ext
struct null_in : handler_base_ext, ::boost::process::detail::uses_handles
{
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

View File

@@ -13,17 +13,27 @@
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <unistd.h>
#include <array>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct null_out : handler_base_ext
struct null_out : handler_base_ext, ::boost::process::detail::uses_handles
{
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<>

View File

@@ -6,28 +6,41 @@
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#include <boost/asio/execution.hpp>
#include <boost/process/async.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 {
namespace boost { namespace process { namespace detail {
template<typename Tuple>
inline asio::io_context& get_io_context(const Tuple & tup);
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&)
std::function<void(int, const std::error_code&)> on_exit_handler(Executor& exec)
{
return handler;
auto v = boost::asio::prefer(boost::process::detail::get_io_context(exec.seq).get_executor(),
boost::asio::execution::outstanding_work.tracked);
auto handler_ = this->handler;
return
[handler_, v](int exit_code, const std::error_code & ec)
{
handler_(exit_code, ec);
};
};
}
};

View File

@@ -13,17 +13,23 @@
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
#include <boost/process/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { namespace detail { namespace posix {
struct pipe_in : handler_base_ext
struct pipe_in : handler_base_ext, ::boost::process::detail::uses_handles
{
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())
@@ -48,7 +54,9 @@ struct pipe_in : handler_base_ext
{
if (::dup2(source, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(source);
if (source != STDIN_FILENO)
::close(source);
::close(sink);
}

View File

@@ -52,8 +52,10 @@ 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::detail::get_last_error(), "dup3() failed");
::close(sink);
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (sink != STDOUT_FILENO)
::close(sink);
::close(source);
}
@@ -63,7 +65,9 @@ void pipe_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
if (sink != STDOUT_FILENO)
::close(sink);
::close(source);
}
@@ -75,8 +79,8 @@ void pipe_out<1,2>::on_exec_setup(Executor &e) const
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
if ((sink != STDOUT_FILENO) && (sink != STDERR_FILENO))
::close(sink);
}
class async_pipe;

View File

@@ -11,7 +11,7 @@
#define BOOST_PROCESS_POSIX_SEARCH_PATH_HPP
#include <boost/process/detail/config.hpp>
#include <boost/filesystem.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/tokenizer.hpp>
#include <string>
#include <stdexcept>
@@ -20,14 +20,20 @@
namespace boost { namespace process { namespace detail { namespace posix {
inline boost::filesystem::path search_path(
const boost::filesystem::path &filename,
const std::vector<boost::filesystem::path> &path)
inline boost::process::filesystem::path search_path(
const boost::process::filesystem::path &filename,
const std::vector<boost::process::filesystem::path> &path)
{
for (const boost::filesystem::path & pp : path)
for (const boost::process::filesystem::path & pp : path)
{
auto p = pp / filename;
if (!::access(p.c_str(), X_OK))
#if defined(BOOST_PROCESS_USE_STD_FS)
std::error_code ec;
#else
boost::system::error_code ec;
#endif
bool file = boost::process::filesystem::is_regular_file(p, ec);
if (!ec && file && ::access(p.c_str(), X_OK) == 0)
return p;
}
return "";

View File

@@ -12,16 +12,16 @@
#include <boost/process/detail/config.hpp>
#include <boost/system/error_code.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/process/filesystem.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
inline boost::filesystem::path shell_path()
inline boost::process::filesystem::path shell_path()
{
return "/bin/sh";
}
inline boost::filesystem::path shell_path(std::error_code &ec)
inline boost::process::filesystem::path shell_path(std::error_code &ec)
{
ec.clear();
return "/bin/sh";

View File

@@ -7,21 +7,24 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/asio/strand.hpp>
#include <boost/optional.hpp>
#include <signal.h>
#include <functional>
#include <sys/wait.h>
#include <list>
namespace boost { namespace process { namespace detail { namespace posix {
class sigchld_service : public boost::asio::detail::service_base<sigchld_service>
{
boost::asio::io_context::strand _strand{get_io_context()};
boost::asio::strand<boost::asio::io_context::executor_type> _strand{get_io_context().get_executor()};
boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
std::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
inline void _handle_signal(const boost::system::error_code & ec);
public:
sigchld_service(boost::asio::io_context & io_context)
@@ -36,22 +39,47 @@ public:
{
boost::asio::async_completion<
SignalHandler, void(boost::system::error_code)> init{handler};
auto & h = init.completion_handler;
_strand.post(
boost::asio::dispatch(
_strand,
[this, pid, h]
{
if (_receivers.empty())
_signal_set.async_wait(
[this](const boost::system::error_code & ec, int)
//check if the child actually is running first
int status;
auto pid_res = ::waitpid(pid, &status, WNOHANG);
if (pid_res < 0)
{
auto ec = get_last_error();
boost::asio::post(
_strand,
[pid_res, ec, h]
{
_strand.post([this,ec]{this->_handle_signal(ec);});
h(pid_res, ec);
});
_receivers.emplace_back(pid, h);
}
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
boost::asio::post(
_strand,
[status, h]
{
h(status, {}); //successfully exited already
});
else //still running
{
if (_receivers.empty())
_signal_set.async_wait(
[this](const boost::system::error_code &ec, int)
{
boost::asio::dispatch(_strand, [this, ec]{this->_handle_signal(ec);});
});
_receivers.emplace_back(pid, h);
}
});
return init.result.get();
}
void shutdown_service() override
void shutdown() override
{
_receivers.clear();
}
@@ -77,26 +105,34 @@ void sigchld_service::_handle_signal(const boost::system::error_code & ec)
r.second(-1, ec_);
return;
}
int status;
int pid = ::waitpid(0, &status, WNOHANG);
auto itr = std::find_if(_receivers.begin(), _receivers.end(),
[&pid](const std::pair<::pid_t, std::function<void(int, std::error_code)>> & p)
{
return p.first == pid;
});
if (itr != _receivers.cend())
{
_strand.get_io_context().wrap(itr->second)(status, ec_);
_receivers.erase(itr);
for (auto & r : _receivers) {
int status;
int pid = ::waitpid(r.first, &status, WNOHANG);
if (pid < 0) {
// error (eg: the process no longer exists)
r.second(-1, get_last_error());
r.first = 0; // mark for deletion
} else if (pid == r.first) {
r.second(status, ec_);
r.first = 0; // mark for deletion
}
// otherwise the process is still around
}
_receivers.erase(std::remove_if(_receivers.begin(), _receivers.end(),
[](const std::pair<::pid_t, std::function<void(int, std::error_code)>> & p)
{
return p.first == 0;
}),
_receivers.end());
if (!_receivers.empty())
{
_signal_set.async_wait(
[this](const boost::system::error_code & ec, int)
{
_strand.post([ec]{});
this->_handle_signal(ec);
boost::asio::post(_strand, [this, ec]{this->_handle_signal(ec);});
});
}
}

View File

@@ -13,6 +13,7 @@
#include <boost/process/detail/posix/handler.hpp>
#include <string>
#include <unistd.h>
#include <boost/core/ignore_unused.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -21,12 +22,12 @@ struct start_dir_init : handler_base_ext
{
typedef Char value_type;
typedef std::basic_string<value_type> string_type;
start_dir_init(const string_type &s) : s_(s) {}
start_dir_init(string_type s) : s_(std::move(s)) {}
template <class PosixExecutor>
void on_exec_setup(PosixExecutor&) const
{
::chdir(s_.c_str());
boost::ignore_unused(::chdir(s_.c_str()));
}
const string_type & str() const {return s_;}
private:

View File

@@ -19,15 +19,6 @@
namespace boost { namespace process { namespace detail { namespace posix {
inline void terminate(const child_handle &p)
{
if (::kill(p.pid, SIGKILL) == -1)
boost::process::detail::throw_last_error("kill(2) failed");
int status;
::waitpid(p.pid, &status, 0); //just to clean it up
}
inline void terminate(const child_handle &p, std::error_code &ec) noexcept
{
if (::kill(p.pid, SIGKILL) == -1)
@@ -36,7 +27,14 @@ inline void terminate(const child_handle &p, std::error_code &ec) noexcept
ec.clear();
int status;
::waitpid(p.pid, &status, 0); //just to clean it up
::waitpid(p.pid, &status, 0); //should not be WNOHANG, since that would allow zombies.
}
inline void terminate(const child_handle &p)
{
std::error_code ec;
terminate(p, ec);
boost::process::detail::throw_error(ec, "kill(2) failed");
}
}}}}

View File

@@ -19,21 +19,6 @@
namespace boost { namespace process { namespace detail { namespace posix {
inline void wait(const child_handle &p, int & exit_code)
{
pid_t ret;
int status;
do
{
ret = ::waitpid(p.pid, &status, 0);
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
if (WIFSIGNALED(status))
throw process_error(std::error_code(), "process terminated due to receipt of a signal");
exit_code = status;
}
inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
pid_t ret;
@@ -43,88 +28,8 @@ inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) no
{
ret = ::waitpid(p.pid, &status, 0);
}
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
exit_code = status;
}
}
template< class Rep, class Period >
inline bool wait_for(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time)
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool timed_out;
do
{
ret = ::waitpid(p.pid, &status, WNOHANG);
if (ret == 0)
{
timed_out = std::chrono::system_clock::now() >= time_out;
if (timed_out)
return false;
}
}
while ((ret == 0) ||
((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
exit_code = status;
return true;
}
template< class Rep, class Period >
inline bool wait_for(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool timed_out;
do
{
ret = ::waitpid(p.pid, &status, WNOHANG);
if (ret == 0)
{
timed_out = std::chrono::system_clock::now() >= time_out;
if (timed_out)
return false;
}
}
while ((ret == 0) ||
(((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
if (timed_out && (ret == -1))
return false;
while (((ret == -1) && (errno == EINTR)) ||
(ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
@@ -133,49 +38,15 @@ inline bool wait_for(
ec.clear();
exit_code = status;
}
return true;
}
template< class Clock, class Duration >
inline bool wait_until(
const child_handle &p,
int & exit_code,
const std::chrono::time_point<Clock, Duration>& time_out)
inline void wait(const child_handle &p, int & exit_code) noexcept
{
pid_t ret;
int status;
bool timed_out;
do
{
ret = ::waitpid(p.pid, &status, WNOHANG);
if (ret == 0)
{
timed_out = std::chrono::system_clock::now() >= time_out;
if (timed_out)
return false;
}
}
while ((ret == 0) ||
(((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
if (timed_out && !WIFEXITED(status))
return false;
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
exit_code = status;
return true;
std::error_code ec;
wait(p, exit_code, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait");
}
template< class Clock, class Duration >
inline bool wait_until(
const child_handle &p,
@@ -183,30 +54,142 @@ inline bool wait_until(
const std::chrono::time_point<Clock, Duration>& time_out,
std::error_code & ec) noexcept
{
::sigset_t sigset;
pid_t ret;
int status;
//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;
}
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;
};
int ret;
int status{0};
struct ::sigaction old_sig;
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
{
ec = get_last_error();
return false;
}
bool timed_out;
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
do
{
auto ts = get_timespec(time_out - Clock::now());
auto ret_sig = ::sigtimedwait(&sigset, nullptr, &ts);
errno = 0;
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);
if (ret == 0)
{
timed_out = std::chrono::system_clock::now() >= time_out;
timed_out = Clock::now() >= time_out;
if (timed_out)
return false;
}
}
}
while ((ret == 0) ||
(((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
#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());
::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());
}
::exit(0);
}
struct child_cleaner_t
{
pid_t pid;
~child_cleaner_t()
{
int res;
::kill(pid, SIGKILL);
::waitpid(pid, &res, 0);
}
};
child_cleaner_t child_cleaner{timeout_pid};
do
{
int sig_{0};
if ((::waitpid(timeout_pid, &status, WNOHANG) != 0)
&& (WIFEXITED(status) || WIFSIGNALED(status)))
if (timed_out && !WIFEXITED(status))
return false;
return false;
ret = ::sigwait(&sigset, &sig_);
errno = 0;
if ((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
{
timed_out = Clock::now() >= time_out;
if (timed_out)
return false;
}
}
while ((ret == 0) ||
(((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
#endif
if (ret == -1)
ec = boost::process::detail::get_last_error();
@@ -219,6 +202,40 @@ inline bool wait_until(
return true;
}
template< class Clock, class Duration >
inline bool wait_until(
const child_handle &p,
int & exit_code,
const std::chrono::time_point<Clock, Duration>& time_out)
{
std::error_code ec;
bool b = wait_until(p, exit_code, 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 child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code & ec) noexcept
{
return wait_until(p, exit_code, std::chrono::steady_clock::now() + rel_time, ec);
}
template< class Rep, class Period >
inline bool wait_for(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time)
{
std::error_code ec;
bool b = wait_for(p, exit_code, rel_time, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_for");
return b;
}
}}}}
#endif

View File

@@ -12,80 +12,92 @@
#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)
{
pid_t ret;
int status;
do
{
ret = ::waitpid(-p.grp, &status, 0);
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
if (WIFSIGNALED(status))
throw process_error(std::error_code(), "process group terminated due to receipt of a signal");
}
inline void wait(const group_handle &p, std::error_code &ec) noexcept
{
pid_t ret;
int status;
siginfo_t status;
do
{
ret = ::waitpid(-p.grp, &status, 0);
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 == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
while ((ret != -1) || (errno != ECHILD));
if (errno != ECHILD)
ec = boost::process::detail::get_last_error();
else if (WIFSIGNALED(status))
ec = std::make_error_code(std::errc::no_such_process);
else
ec.clear();
}
template< class Rep, class Period >
inline bool wait_for(
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::duration<Rep, Period>& rel_time)
const std::chrono::time_point<Clock, Duration>& time_out,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
::siginfo_t siginfo;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool timed_out = false;
int ret;
bool time_out_occured = false;
do
::timespec sleep_interval;
sleep_interval.tv_sec = 0;
sleep_interval.tv_nsec = 100000000;
while (!(timed_out = (Clock::now() > time_out)))
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WSTOPPED | WNOHANG);
if (ret == -1)
{
time_out_occured = true;
break;
if ((errno == ECHILD) || (errno == ESRCH))
{
ec.clear();
return true;
}
ec = boost::process::detail::get_last_error();
return false;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
if (WIFSIGNALED(status))
throw process_error(std::error_code(), "process group terminated due to receipt of a signal");
return !time_out_occured;
//we can wait, because unlike in the wait_for_exit, we have no race condition regarding eh exit code.
::nanosleep(&sleep_interval, nullptr);
}
return !timed_out;
}
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(
@@ -93,104 +105,18 @@ inline bool wait_for(
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else if (WIFSIGNALED(status))
ec = std::make_error_code(std::errc::no_such_process);
else
ec.clear();
return !time_out_occured;
return wait_until(p, std::chrono::steady_clock::now() + rel_time, ec);
}
template< class Rep, class Period >
inline bool wait_until(
inline bool wait_for(
const group_handle &p,
const std::chrono::duration<Rep, Period>& time_out)
const std::chrono::duration<Rep, Period>& rel_time) noexcept
{
pid_t ret;
int status;
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
if (WIFSIGNALED(status))
throw process_error(std::error_code(), "process group terminated due to receipt of a signal");
return !time_out_occured;
}
template< class Rep, class Period >
inline bool wait_until(
const group_handle &p,
const std::chrono::duration<Rep, Period>& time_out,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else if (WIFSIGNALED(status))
ec = std::make_error_code(std::errc::no_such_process);
else
ec.clear();
return !time_out_occured;
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;
}
}}}}

View File

@@ -11,7 +11,7 @@
#include <vector>
#include <type_traits>
#include <initializer_list>
#include <boost/filesystem/path.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
@@ -53,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::filesystem::path::value_type> type;
typedef cmd_or_exe_tag<typename boost::process::filesystem::path::value_type> type;
};
template<> struct initializer_tag<boost::filesystem::path>
template<> struct initializer_tag<boost::process::filesystem::path>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
typedef cmd_or_exe_tag<typename boost::process::filesystem::path::value_type> type;
};
template <typename Char>

View File

@@ -7,6 +7,8 @@
#ifndef BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_
#include <algorithm>
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/env.hpp>
@@ -18,7 +20,7 @@ namespace boost { namespace process { namespace detail {
template<typename T> struct is_wchar_t : std::false_type {};
template<> struct is_wchar_t<boost::filesystem::path> : std::is_same<typename boost::filesystem::path::value_type, wchar_t>
template<> struct is_wchar_t<boost::process::filesystem::path> : std::is_same<typename boost::process::filesystem::path::value_type, wchar_t>
{
};

View File

@@ -0,0 +1,81 @@
// 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_USED_HANDLES_HPP_
#define BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_
#include <type_traits>
#include <boost/fusion/include/filter_if.hpp>
#include <boost/fusion/include/for_each.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handles.hpp>
#include <boost/process/detail/posix/asio_fwd.hpp>
#else
#include <boost/process/detail/windows/handles.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#endif
namespace boost { namespace process { namespace detail {
struct uses_handles
{
//If you get an error here, you must add a `get_handles` function that returns a range or a single handle value
void get_used_handles() const;
};
template<typename T>
struct does_use_handle: std::is_base_of<uses_handles, T> {};
template<typename T>
struct does_use_handle<T&> : std::is_base_of<uses_handles, T> {};
template<typename T>
struct does_use_handle<const T&> : std::is_base_of<uses_handles, T> {};
template<typename Char, typename Sequence>
class executor;
template<typename Func>
struct foreach_handle_invocator
{
Func & func;
foreach_handle_invocator(Func & func) : func(func) {}
template<typename Range>
void invoke(const Range & range) const
{
for (auto handle_ : range)
func(handle_);
}
void invoke(::boost::process::detail::api::native_handle_type handle) const {func(handle);};
template<typename T>
void operator()(T & val) const {invoke(val.get_used_handles());}
};
template<typename Executor, typename Function>
void foreach_used_handle(Executor &exec, Function &&func)
{
boost::fusion::for_each(boost::fusion::filter_if<does_use_handle<boost::mpl::_>>(exec.seq),
foreach_handle_invocator<Function>(func));
}
template<typename Executor>
std::vector<::boost::process::detail::api::native_handle_type>
get_used_handles(Executor &exec)
{
std::vector<::boost::process::detail::api::native_handle_type> res = exec.get_used_handles();
foreach_used_handle(exec, [&](::boost::process::detail::api::native_handle_type handle){res.push_back(handle);});
return res;
}
}}}
#endif /* BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_ */

View File

@@ -7,6 +7,7 @@
#define BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_
#include <memory>
#include <boost/asio/ts/netfwd.hpp>
namespace boost { namespace asio {
@@ -19,35 +20,19 @@ template<typename Allocator>
class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_context;
template <typename Handler>
class basic_yield_context;
namespace windows {
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class stream_handle_service;
template <typename StreamHandleService>
template <typename Executor>
class basic_stream_handle;
typedef basic_stream_handle<any_io_executor> stream_handle;
typedef basic_stream_handle<stream_handle_service> stream_handle;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class stream_handle;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class object_handle_service;
template <typename ObjectHandleService>
template <typename Executor>
class basic_object_handle;
typedef basic_object_handle<object_handle_service> object_handle;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class object_handle;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
typedef basic_object_handle<any_io_executor> object_handle;
} //windows
} //asio

View File

@@ -17,19 +17,20 @@
#include <boost/asio/write.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_context
::boost::process::detail::windows::require_io_context,
::boost::process::detail::uses_handles
{
Buffer & buf;
@@ -42,34 +43,39 @@ struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
std::shared_ptr<boost::process::async_pipe> pipe;
::boost::winapi::HANDLE_ get_used_handles() const
{
return std::move(*pipe).source().native_handle();
}
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe = this->pipe;
auto pipe_ = this->pipe;
if (this->promise)
{
auto promise = this->promise;
auto promise_ = this->promise;
boost::asio::async_write(*pipe, buf,
[promise](const boost::system::error_code & ec, std::size_t)
boost::asio::async_write(*pipe_, buf,
[promise_](const boost::system::error_code & ec, std::size_t)
{
if (ec && (ec.value() != ::boost::winapi::ERROR_BROKEN_PIPE_))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
promise_->set_exception(std::make_exception_ptr(process_error(e)));
}
promise->set_value();
promise_->set_value();
});
}
else
boost::asio::async_write(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t){});
boost::asio::async_write(*pipe_, buf,
[pipe_](const boost::system::error_code&, std::size_t){});
std::move(*pipe).source().close();
std::move(*pipe_).source().close();
this->pipe = nullptr;

View File

@@ -16,6 +16,7 @@
#include <boost/winapi/error_codes.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <istream>
@@ -80,10 +81,10 @@ struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t){});
std::move(*pipe).sink().close();
auto pipe_ = this->pipe;
boost::asio::async_read(*pipe_, buf,
[pipe_](const boost::system::error_code&, std::size_t){});
std::move(*pipe_).sink().close();
this->pipe = nullptr;
}
@@ -108,12 +109,18 @@ struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_context
::boost::process::detail::windows::require_io_context,
::boost::process::detail::uses_handles
{
std::shared_ptr<boost::process::async_pipe> pipe;
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>();
::boost::winapi::HANDLE_ get_used_handles() const
{
return std::move(*pipe).sink().native_handle();
}
async_out_future(std::future<Type> & fut)
{
@@ -122,34 +129,34 @@ struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe = this->pipe;
auto buffer = this->buffer;
auto promise = this->promise;
std::move(*pipe).sink().close();
boost::asio::async_read(*pipe, *buffer,
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t)
auto pipe_ = this->pipe;
auto buffer_ = this->buffer;
auto promise_ = this->promise;
std::move(*pipe_).sink().close();
boost::asio::async_read(*pipe_, *buffer_,
[pipe_, buffer_, promise_](const boost::system::error_code& ec, std::size_t)
{
if (ec && (ec.value() != ::boost::winapi::ERROR_BROKEN_PIPE_))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
promise_->set_exception(std::make_exception_ptr(process_error(e)));
}
else
{
std::istream is (buffer.get());
std::istream is (buffer_.get());
Type arg;
if (buffer->size() > 0)
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));
promise_->set_value(std::move(arg));
}
});
this->pipe = nullptr;
this->pipe = nullptr;
this->buffer = nullptr;
this->promise = nullptr;

View File

@@ -14,6 +14,7 @@
#include <boost/winapi/access_rights.hpp>
#include <boost/winapi/process.hpp>
#include <boost/process/detail/windows/basic_pipe.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/windows/stream_handle.hpp>
#include <atomic>
#include <system_error>
@@ -27,7 +28,7 @@ inline std::string make_pipe_name()
auto pid = ::boost::winapi::GetCurrentProcessId();
static std::atomic_size_t cnt = 0;
static std::atomic_size_t cnt{0};
name += std::to_string(pid);
name += "_";
name += std::to_string(cnt++);
@@ -39,23 +40,31 @@ class async_pipe
{
::boost::asio::windows::stream_handle _source;
::boost::asio::windows::stream_handle _sink ;
public:
typedef ::boost::winapi::HANDLE_ native_handle_type;
typedef ::boost::asio::windows::stream_handle handle_type;
inline async_pipe(boost::asio::io_context & ios,
const std::string & name = make_pipe_name())
: async_pipe(ios, ios, name) {}
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
const std::string & name = make_pipe_name());
const std::string & name, bool private_);
public:
typedef ::boost::winapi::HANDLE_ native_handle_type;
typedef ::boost::asio::windows::stream_handle handle_type;
typedef typename handle_type::executor_type executor_type;
async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios, make_pipe_name(), true) {}
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink)
: async_pipe(ios_source, ios_sink, make_pipe_name(), true) {}
async_pipe(boost::asio::io_context & ios, const std::string & name)
: async_pipe(ios, ios, name, false) {}
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name)
: async_pipe(ios_source, ios_sink, name, false) {}
inline async_pipe(const async_pipe& rhs);
async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
{
rhs._source.assign (::boost::winapi::INVALID_HANDLE_VALUE_);
rhs._sink .assign (::boost::winapi::INVALID_HANDLE_VALUE_);
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(::boost::asio::io_context & ios_source,
@@ -99,12 +108,12 @@ public:
if (_sink.is_open())
{
_sink.close();
_sink = handle_type(_sink.get_io_context());
_sink = handle_type(_sink.get_executor());
}
if (_source.is_open())
{
_source.close();
_source = handle_type(_source.get_io_context());
_source = handle_type(_source.get_executor());
}
}
void close(boost::system::error_code & ec)
@@ -112,12 +121,12 @@ public:
if (_sink.is_open())
{
_sink.close(ec);
_sink = handle_type(_sink.get_io_context());
_sink = handle_type(_sink.get_executor());
}
if (_source.is_open())
{
_source.close(ec);
_source = handle_type(_source.get_io_context());
_source = handle_type(_source.get_executor());
}
}
@@ -128,9 +137,9 @@ public:
void async_close()
{
if (_sink.is_open())
_sink.get_io_context(). post([this]{_sink.close();});
boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
if (_source.is_open())
_source.get_io_context().post([this]{_source.close();});
boost::asio::post(_source.get_executor(), [this]{_source.close();});
}
template<typename MutableBufferSequence>
@@ -144,6 +153,18 @@ public:
return _sink.write_some(buffers);
}
template<typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
{
return _source.read_some(buffers, ec);
}
template<typename MutableBufferSequence>
std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
{
return _sink.write_some(buffers, ec);
}
native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native_handle();}
native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native_handle();}
@@ -155,7 +176,7 @@ public:
const MutableBufferSequence & buffers,
ReadHandler &&handler)
{
_source.async_read_some(buffers, std::forward<ReadHandler>(handler));
return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
}
template<typename ConstBufferSequence,
@@ -166,7 +187,7 @@ public:
const ConstBufferSequence & buffers,
WriteHandler && handler)
{
_sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
}
const handle_type & sink () const & {return _sink;}
@@ -177,14 +198,16 @@ public:
handle_type source(::boost::asio::io_context& ios) &&
{
::boost::asio::windows::stream_handle stolen(ios, _source.native_handle());
_source.assign(::boost::winapi::INVALID_HANDLE_VALUE_);
::boost::asio::windows::stream_handle stolen(ios.get_executor(), _source.native_handle());
boost::system::error_code ec;
_source.assign(::boost::winapi::INVALID_HANDLE_VALUE_, ec);
return stolen;
}
handle_type sink (::boost::asio::io_context& ios) &&
{
::boost::asio::windows::stream_handle stolen(ios, _sink.native_handle());
_sink.assign(::boost::winapi::INVALID_HANDLE_VALUE_);
::boost::asio::windows::stream_handle stolen(ios.get_executor(), _sink.native_handle());
boost::system::error_code ec;
_sink.assign(::boost::winapi::INVALID_HANDLE_VALUE_, ec);
return stolen;
}
@@ -202,7 +225,7 @@ public:
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return ::boost::asio::windows::stream_handle(ios, source);
return ::boost::asio::windows::stream_handle(ios.get_executor(), source);
}
handle_type sink (::boost::asio::io_context& ios) const &
{
@@ -218,16 +241,15 @@ public:
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return ::boost::asio::windows::stream_handle(ios, sink);
return ::boost::asio::windows::stream_handle(ios.get_executor(), sink);
}
};
async_pipe::async_pipe(const async_pipe& p) :
_source(const_cast<handle_type&>(p._source).get_io_context()),
_sink (const_cast<handle_type&>(p._sink).get_io_context())
_source(const_cast<handle_type&>(p._source).get_executor()),
_sink (const_cast<handle_type&>(p._sink).get_executor())
{
auto proc = ::boost::winapi::GetCurrentProcess();
::boost::winapi::HANDLE_ source;
@@ -253,22 +275,28 @@ async_pipe::async_pipe(const async_pipe& p) :
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
_source.assign(source);
_sink. assign(sink);
if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
_source.assign(source);
if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
_sink. assign(sink);
}
async_pipe::async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
const std::string & name) : _source(ios_source), _sink(ios_sink)
const std::string & name, bool private_) : _source(ios_source), _sink(ios_sink)
{
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe(
#if defined(BOOST_NO_ANSI_APIS)
::boost::process::detail::convert(name).c_str(),
#else
name.c_str(),
#endif
::boost::winapi::PIPE_ACCESS_INBOUND_
| FILE_FLAG_OVERLAPPED_, //write flag
0, 1, 8192, 8192, 0, nullptr);
0, private_ ? 1 : ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
@@ -277,7 +305,11 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
_source.assign(source);
::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
#if defined(BOOST_NO_ANSI_APIS)
::boost::process::detail::convert(name).c_str(),
#else
name.c_str(),
#endif
::boost::winapi::GENERIC_WRITE_, 0, nullptr,
::boost::winapi::OPEN_EXISTING_,
FILE_FLAG_OVERLAPPED_, //to allow read
@@ -289,6 +321,44 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
_sink.assign(sink);
}
template<class CharT, class Traits>
async_pipe& async_pipe::operator=(const basic_pipe<CharT, Traits> & p)
{
auto proc = ::boost::winapi::GetCurrentProcess();
::boost::winapi::HANDLE_ source;
::boost::winapi::HANDLE_ sink;
//cannot get the handle from a const object.
auto source_in = p.native_source();
auto sink_in = p.native_sink();
if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, source_in.native_handle(), proc, &source, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, sink_in.native_handle(), proc, &sink, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
//so we also assign the io_context
if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
_source.assign(source);
if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
_sink.assign(sink);
return *this;
}
async_pipe& async_pipe::operator=(const async_pipe & p)
{
auto proc = ::boost::winapi::GetCurrentProcess();
@@ -300,6 +370,8 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
auto &source_in = const_cast<::boost::asio::windows::stream_handle &>(p._source);
auto &sink_in = const_cast<::boost::asio::windows::stream_handle &>(p._sink);
source_in.get_executor();
if (source_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
@@ -317,24 +389,23 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
throw_last_error("Duplicate Pipe Failed");
//so we also assign the io_context
_source = ::boost::asio::windows::stream_handle(source_in.get_io_context(), source);
_sink = ::boost::asio::windows::stream_handle(source_in.get_io_context(), sink);
if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::asio::windows::stream_handle(source_in.get_executor(), source);
else
_source = ::boost::asio::windows::stream_handle(source_in.get_executor());
if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::asio::windows::stream_handle(source_in.get_executor(), sink);
else
_sink = ::boost::asio::windows::stream_handle(source_in.get_executor());
return *this;
}
async_pipe& async_pipe::operator=(async_pipe && rhs)
{
if (_source.native_handle() != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_source.native_handle());
if (_sink.native_handle() != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_sink.native_handle());
_source.assign(rhs._source.native_handle());
_sink .assign(rhs._sink .native_handle());
rhs._source.assign(::boost::winapi::INVALID_HANDLE_VALUE_);
rhs._sink .assign(::boost::winapi::INVALID_HANDLE_VALUE_);
_source = std::move(rhs._source);
_sink = std::move(rhs._sink);
return *this;
}

View File

@@ -30,14 +30,17 @@ inline std::string build_args(const std::string & exe, std::vector<std::string>
{
std::string st = exe;
//put in quotes if it has spaces
//put in quotes if it has spaces or double quotes
if(!exe.empty())
{
boost::replace_all(st, "\"", "\\\"");
auto it = st.find_first_of(" \"");
auto it = std::find(st.begin(), st.end(), ' ');
if (it != st.end())//contains spaces.
if(it != st.npos)//contains spaces.
{
// double existing quotes
boost::replace_all(st, "\"", "\"\"");
// surround with quotes
st.insert(st.begin(), '"');
st += '"';
}
@@ -45,15 +48,18 @@ inline std::string build_args(const std::string & exe, std::vector<std::string>
for (auto & arg : data)
{
boost::replace_all(arg, "\"", "\\\"");
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
if (it != arg.end())//ok, contains spaces.
if(!arg.empty())
{
//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 += '"'; //thats the post one.
auto it = arg.find_first_of(" \"");//contains space or double quotes?
if(it != arg.npos)//yes
{
// double existing quotes
boost::replace_all(arg, "\"", "\"\"");
// surround with quotes
arg.insert(arg.begin(), '"');
arg += '"';
}
}
if (!st.empty())//first one does not need a preceeding space
@@ -68,30 +74,36 @@ inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstrin
{
std::wstring st = exe;
//put in quotes if it has spaces
//put in quotes if it has spaces or double quotes
if(!exe.empty())
{
boost::replace_all(st, L"\"", L"\\\"");
auto it = st.find_first_of(L" \"");
auto it = std::find(st.begin(), st.end(), L' ');
if (it != st.end())//contains spaces.
if(it != st.npos)//contains spaces or double quotes.
{
// double existing quotes
boost::replace_all(st, L"\"", L"\"\"");
// surround with quotes
st.insert(st.begin(), L'"');
st += L'"';
}
}
for (auto & arg : data)
for(auto & arg : data)
{
boost::replace_all(arg, L"\"", L"\\\"");
auto it = std::find(arg.begin(), arg.end(), L' ');//contains space?
if (it != arg.end())//ok, contains spaces.
if(!arg.empty())
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), L'"');
arg += L'"'; //thats the post one.
auto it = arg.find_first_of(L" \"");//contains space or double quotes?
if(it != arg.npos)//yes
{
// double existing quotes
boost::replace_all(arg, L"\"", L"\"\"");
// surround with quotes
arg.insert(arg.begin(), L'"');
arg += '"';
}
}
if (!st.empty())//first one does not need a preceeding space
@@ -147,8 +159,13 @@ struct exe_cmd_init : handler_base_ext
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
}
#ifdef BOOST_PROCESS_USE_STD_FS
static std:: string get_shell(char) {return shell(). string(); }
static std::wstring get_shell(wchar_t) {return shell().wstring(); }
#else
static std:: string get_shell(char) {return shell(). string(codecvt()); }
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
#endif
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
{

View File

@@ -98,7 +98,7 @@ public:
return static_cast<int_type>(read_len);
}
bool is_open()
bool is_open() const
{
return (_source != ::boost::winapi::INVALID_HANDLE_VALUE_) ||
(_sink != ::boost::winapi::INVALID_HANDLE_VALUE_);
@@ -143,11 +143,16 @@ basic_pipe<Char, Traits>::basic_pipe(const std::string & name)
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
//static constexpr int FILE_ATTRIBUTE_NORMAL_ = 0x00000080; //temporary
#if BOOST_NO_ANSI_APIS
std::wstring name_ = boost::process::detail::convert(name);
#else
auto &name_ = name;
#endif
::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe(
name.c_str(),
name_.c_str(),
::boost::winapi::PIPE_ACCESS_INBOUND_
| FILE_FLAG_OVERLAPPED_, //write flag
0, 1, 8192, 8192, 0, nullptr);
0, ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_named_pipe() failed");

View File

@@ -17,7 +17,7 @@
namespace boost { namespace process { namespace detail { namespace windows {
typedef int pid_t;
typedef ::boost::winapi::DWORD_ pid_t;
struct child_handle
{
@@ -66,7 +66,7 @@ struct child_handle
pid_t id() const
{
return static_cast<int>(proc_info.dwProcessId);
return static_cast<pid_t>(proc_info.dwProcessId);
}
typedef ::boost::winapi::HANDLE_ process_handle_t;

View File

@@ -90,12 +90,12 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
else
return std::basic_string<Char>(
buf.data(), buf.data()+ size + 1);
buf.data(), buf.data()+ size);
}
}
return std::basic_string<Char>(buf, buf+size+1);
return std::basic_string<Char>(buf, buf+size);
}
template<typename Char>
@@ -232,6 +232,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
{
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
return string_type(_data.data());
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
return string_type(_data.data()); //null-char is handled by the string.

View File

@@ -84,7 +84,7 @@ struct startup_info_impl
void set_startup_info_ex()
{
startup_info.cb = sizeof(startup_info_ex_t);
creation_flags = ::boost::winapi::EXTENDED_STARTUPINFO_PRESENT_;
creation_flags |= ::boost::winapi::EXTENDED_STARTUPINFO_PRESENT_;
}
};

View File

@@ -10,7 +10,8 @@
#include <boost/winapi/handles.hpp>
#include <boost/winapi/file_management.hpp>
#include <string>
#include <boost/filesystem/path.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/core/exchange.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
@@ -39,17 +40,25 @@ struct file_descriptor
}
file_descriptor() = default;
file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
file_descriptor(const boost::process::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
file_descriptor(const std::string & path , mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
#if defined(BOOST_NO_ANSI_APIS)
: file_descriptor(::boost::process::detail::convert(path), mode)
#else
: file_descriptor(path.c_str(), mode)
#endif
{}
file_descriptor(const std::wstring & path, mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
file_descriptor(const char* path, mode_t mode = read_write)
#if defined(BOOST_NO_ANSI_APIS)
: file_descriptor(std::string(path), mode)
#else
: _handle(
::boost::winapi::create_file(
path,
@@ -62,8 +71,8 @@ struct file_descriptor
::boost::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr
))
#endif
{
}
file_descriptor(const wchar_t * path, mode_t mode = read_write)
: _handle(
@@ -82,10 +91,19 @@ struct file_descriptor
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
file_descriptor(file_descriptor &&other)
: _handle( boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_) )
{
}
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
file_descriptor& operator=(file_descriptor &&other)
{
if (_handle != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_handle);
_handle = boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_);
return *this;
}
~file_descriptor()
{

View File

@@ -13,16 +13,20 @@
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
#include <io.h>
namespace boost { namespace process { namespace detail { namespace windows {
struct file_in : public ::boost::process::detail::handler_base
struct file_in : public ::boost::process::detail::handler_base,
::boost::process::detail::uses_handles
{
file_descriptor file;
::boost::winapi::HANDLE_ handle = file.handle();
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
template<typename T>
file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {}
file_in(FILE * f) : handle(reinterpret_cast<::boost::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}

View File

@@ -14,16 +14,21 @@
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct file_out : public ::boost::process::detail::handler_base
struct file_out : public ::boost::process::detail::handler_base,
::boost::process::detail::uses_handles
{
file_descriptor file;
::boost::winapi::HANDLE_ handle = file.handle();
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write) {}
file_out(FILE * f) : handle(reinterpret_cast<void*>(_get_osfhandle(_fileno(f)))) {}

View File

@@ -84,41 +84,62 @@ inline void enable_break_away(::boost::winapi::HANDLE_ h, std::error_code & ec)
ec = get_last_error();
return;
}
}
inline void associate_completion_port(::boost::winapi::HANDLE_ job,
::boost::winapi::HANDLE_ io_port)
{
workaround::JOBOBJECT_ASSOCIATE_COMPLETION_PORT_ port;
port.CompletionKey = job;
port.CompletionPort = io_port;
if (!workaround::set_information_job_object(
job,
workaround::JobObjectAssociateCompletionPortInformation_,
static_cast<void*>(&port),
sizeof(port)))
throw_last_error("SetInformationJobObject() failed");
}
struct group_handle
{
::boost::winapi::HANDLE_ _job_object;
::boost::winapi::HANDLE_ _io_port;
typedef ::boost::winapi::HANDLE_ handle_t;
handle_t handle() const { return _job_object; }
explicit group_handle(handle_t h) :
_job_object(h)
_job_object(h),
_io_port(::CreateIoCompletionPort(::boost::winapi::INVALID_HANDLE_VALUE_, nullptr, 0, 1))
{
enable_break_away(_job_object);
associate_completion_port(_job_object, _io_port);
}
group_handle() : group_handle(::boost::winapi::CreateJobObjectA(nullptr, nullptr))
group_handle() : group_handle(::boost::winapi::CreateJobObjectW(nullptr, nullptr))
{
}
~group_handle()
{
::boost::winapi::CloseHandle(_job_object);
::boost::winapi::CloseHandle(_io_port);
}
group_handle(const group_handle & c) = delete;
group_handle(group_handle && c) : _job_object(c._job_object)
group_handle(group_handle && c) : _job_object(c._job_object),
_io_port(c._io_port)
{
c._job_object = ::boost::winapi::invalid_handle_value;
c._io_port = ::boost::winapi::invalid_handle_value;
}
group_handle &operator=(const group_handle & c) = delete;
group_handle &operator=(group_handle && c)
{
::boost::winapi::CloseHandle(_io_port);
_io_port = c._io_port;
c._io_port = ::boost::winapi::invalid_handle_value;
::boost::winapi::CloseHandle(_job_object);
_job_object = c._job_object;

View File

@@ -6,9 +6,10 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_
#include <boost/winapi/process.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/windows/group_handle.hpp>
#include <boost/winapi/process.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/handler.hpp>
namespace boost { namespace process {
@@ -17,10 +18,12 @@ namespace detail { namespace windows {
struct group_ref : handler_base_ext
struct group_ref : handler_base_ext, ::boost::process::detail::uses_handles
{
::boost::winapi::HANDLE_ handle;
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
explicit group_ref(group_handle &g) :
handle(g.handle())
{}

View File

@@ -0,0 +1,262 @@
// Copyright (c) 2018 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_WINDOWS_HANDLE_WORKAROUND_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLE_WORKAROUND_HPP_
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/dll.hpp>
#include <boost/winapi/access_rights.hpp>
//#define BOOST_USE_WINDOWS_H 1
#if defined( BOOST_USE_WINDOWS_H )
#include <winternl.h>
#endif
namespace boost { namespace process { namespace detail { namespace windows { namespace workaround
{
typedef struct _SYSTEM_HANDLE_ENTRY_
{
::boost::winapi::ULONG_ OwnerPid;
::boost::winapi::BYTE_ ObjectType;
::boost::winapi::BYTE_ HandleFlags;
::boost::winapi::USHORT_ HandleValue;
::boost::winapi::PVOID_ ObjectPointer;
::boost::winapi::ULONG_ AccessMask;
} SYSTEM_HANDLE_ENTRY_, *PSYSTEM_HANDLE_ENTRY_;
typedef struct _SYSTEM_HANDLE_INFORMATION_
{
::boost::winapi::ULONG_ Count;
SYSTEM_HANDLE_ENTRY_ Handle[1];
} SYSTEM_HANDLE_INFORMATION_, *PSYSTEM_HANDLE_INFORMATION_;
#if defined( BOOST_USE_WINDOWS_H )
using UNICODE_STRING_ = ::UNICODE_STRING;
using GENERIC_MAPPING_ = ::GENERIC_MAPPING;
using OBJECT_INFORMATION_CLASS_ = ::OBJECT_INFORMATION_CLASS;
constexpr static OBJECT_INFORMATION_CLASS_ ObjectTypeInformation = ::OBJECT_INFORMATION_CLASS::ObjectTypeInformation;
typedef struct _OBJECT_TYPE_INFORMATION_ {
UNICODE_STRING TypeName;
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
ULONG TotalPagedPoolUsage;
ULONG TotalNonPagedPoolUsage;
ULONG TotalNamePoolUsage;
ULONG TotalHandleTableUsage;
ULONG HighWaterNumberOfObjects;
ULONG HighWaterNumberOfHandles;
ULONG HighWaterPagedPoolUsage;
ULONG HighWaterNonPagedPoolUsage;
ULONG HighWaterNamePoolUsage;
ULONG HighWaterHandleTableUsage;
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccessMask;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
UCHAR TypeIndex;
CHAR ReservedByte;
ULONG PoolType;
ULONG DefaultPagedPoolCharge;
ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION_, *POBJECT_TYPE_INFORMATION_;
#else
typedef enum _OBJECT_INFORMATION_CLASS_
{
ObjectBasicInformation,
ObjectNameInformation,
ObjectTypeInformation,
ObjectAllInformation,
ObjectDataInformation
} OBJECT_INFORMATION_CLASS_, *POBJECT_INFORMATION_CLASS_;
typedef struct _UNICODE_STRING_ {
::boost::winapi::USHORT_ Length;
::boost::winapi::USHORT_ MaximumLength;
::boost::winapi::LPWSTR_ Buffer;
} UNICODE_STRING_, *PUNICODE_STRING_;
typedef struct _GENERIC_MAPPING_ {
::boost::winapi::ACCESS_MASK_ GenericRead;
::boost::winapi::ACCESS_MASK_ GenericWrite;
::boost::winapi::ACCESS_MASK_ GenericExecute;
::boost::winapi::ACCESS_MASK_ GenericAll;
} GENERIC_MAPPING_;
#endif
typedef struct _OBJECT_BASIC_INFORMATION {
::boost::winapi::ULONG_ Attributes;
::boost::winapi::ACCESS_MASK_ GrantedAccess;
::boost::winapi::ULONG_ HandleCount;
::boost::winapi::ULONG_ PointerCount;
::boost::winapi::ULONG_ PagedPoolUsage;
::boost::winapi::ULONG_ NonPagedPoolUsage;
::boost::winapi::ULONG_ Reserved[3];
::boost::winapi::ULONG_ NameInformationLength;
::boost::winapi::ULONG_ TypeInformationLength;
::boost::winapi::ULONG_ SecurityDescriptorLength;
::boost::winapi::LARGE_INTEGER_ CreateTime;
} OBJECT_BASIC_INFORMATION_, *POBJECT_BASIC_INFORMATION_;
typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING_ Name;
} OBJECT_NAME_INFORMATION_, *POBJECT_NAME_INFORMATION_;
#if defined( BOOST_USE_WINDOWS_H )
extern "C"
{
using SYSTEM_INFORMATION_CLASS_ = ::SYSTEM_INFORMATION_CLASS;
constexpr static SYSTEM_INFORMATION_CLASS_ SystemHandleInformation_ = static_cast<SYSTEM_INFORMATION_CLASS_>(16);
inline ::boost::winapi::NTSTATUS_ nt_system_query_information(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
void * SystemInformation,
::boost::winapi::ULONG_ SystemInformationLength,
::boost::winapi::PULONG_ ReturnLength)
{
return ::NtQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
}
inline ::boost::winapi::NTSTATUS_ nt_query_object(
::boost::winapi::HANDLE_ Handle,
OBJECT_INFORMATION_CLASS_ ObjectInformationClass,
::boost::winapi::PVOID_ ObjectInformation,
::boost::winapi::ULONG_ ObjectInformationLength,
::boost::winapi::PULONG_ ReturnLength
)
{
return ::NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength);
}
}
#else
//this import workaround is to keep it a header-only library. and enums cannot be imported from the winapi.
extern "C"
{
typedef enum _SYSTEM_INFORMATION_CLASS_
{
SystemBasicInformation_ = 0,
SystemProcessorInformation_ = 1,
SystemPerformanceInformation_ = 2,
SystemTimeOfDayInformation_ = 3,
SystemProcessInformation_ = 5,
SystemProcessorPerformanceInformation_ = 8,
SystemHandleInformation_ = 16,
SystemPagefileInformation_ = 18,
SystemInterruptInformation_ = 23,
SystemExceptionInformation_ = 33,
SystemRegistryQuotaInformation_ = 37,
SystemLookasideInformation_ = 45
} SYSTEM_INFORMATION_CLASS_;
typedef struct _OBJECT_TYPE_INFORMATION_ {
UNICODE_STRING_ TypeName;
::boost::winapi::ULONG_ TotalNumberOfObjects;
::boost::winapi::ULONG_ TotalNumberOfHandles;
::boost::winapi::ULONG_ TotalPagedPoolUsage;
::boost::winapi::ULONG_ TotalNonPagedPoolUsage;
::boost::winapi::ULONG_ TotalNamePoolUsage;
::boost::winapi::ULONG_ TotalHandleTableUsage;
::boost::winapi::ULONG_ HighWaterNumberOfObjects;
::boost::winapi::ULONG_ HighWaterNumberOfHandles;
::boost::winapi::ULONG_ HighWaterPagedPoolUsage;
::boost::winapi::ULONG_ HighWaterNonPagedPoolUsage;
::boost::winapi::ULONG_ HighWaterNamePoolUsage;
::boost::winapi::ULONG_ HighWaterHandleTableUsage;
::boost::winapi::ULONG_ InvalidAttributes;
GENERIC_MAPPING_ GenericMapping;
::boost::winapi::ULONG_ ValidAccessMask;
::boost::winapi::BOOLEAN_ SecurityRequired;
::boost::winapi::BOOLEAN_ MaintainHandleCount;
::boost::winapi::UCHAR_ TypeIndex;
::boost::winapi::CHAR_ ReservedByte;
::boost::winapi::ULONG_ PoolType;
::boost::winapi::ULONG_ DefaultPagedPoolCharge;
::boost::winapi::ULONG_ DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION_, *POBJECT_TYPE_INFORMATION_;
/*
NTSTATUS NtQuerySystemInformation(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength
);
*/
typedef ::boost::winapi::NTSTATUS_ (*nt_system_query_information_p )(
SYSTEM_INFORMATION_CLASS_,
void *,
::boost::winapi::ULONG_,
::boost::winapi::PULONG_);
/*
NTSYSCALLAPI NTSTATUS NtQueryObject(
HANDLE Handle,
OBJECT_INFORMATION_CLASS ObjectInformationClass,
PVOID ObjectInformation,
ULONG ObjectInformationLength,
PULONG ReturnLength
);
*/
typedef ::boost::winapi::NTSTATUS_ (*nt_query_object_p )(
::boost::winapi::HANDLE_,
OBJECT_INFORMATION_CLASS_,
void *,
::boost::winapi::ULONG_,
::boost::winapi::PULONG_);
}
inline ::boost::winapi::NTSTATUS_ nt_system_query_information(
SYSTEM_INFORMATION_CLASS_ SystemInformationClass,
void *SystemInformation,
::boost::winapi::ULONG_ SystemInformationLength,
::boost::winapi::PULONG_ ReturnLength)
{
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Ntdll.dll");
static nt_system_query_information_p f = reinterpret_cast<nt_system_query_information_p>(::boost::winapi::get_proc_address(h, "NtQuerySystemInformation"));
return (*f)(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
}
inline ::boost::winapi::BOOL_ nt_query_object(
::boost::winapi::HANDLE_ Handle,
OBJECT_INFORMATION_CLASS_ ObjectInformationClass,
void *ObjectInformation,
::boost::winapi::ULONG_ ObjectInformationLength,
::boost::winapi::PULONG_ ReturnLength)
{
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(L"Ntdll.dll");
static nt_query_object_p f = reinterpret_cast<nt_query_object_p>(::boost::winapi::get_proc_address(h, "NtQueryObject"));
return (*f)(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength);
}
#endif
}}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */

View File

@@ -0,0 +1,177 @@
// Copyright (c) 2019 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_WINDOWS_HANDLES_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLES_HPP_
#include <vector>
#include <system_error>
#include <boost/process/detail/windows/handle_workaround.hpp>
#include <boost/process/detail/windows/handler.hpp>
#include <boost/winapi/get_current_process_id.hpp>
#include <boost/winapi/handles.hpp>
namespace boost { namespace process { namespace detail {
template<typename Executor, typename Function>
void foreach_used_handle(Executor &exec, Function &&func);
namespace windows {
using native_handle_type = ::boost::winapi::HANDLE_ ;
inline std::vector<native_handle_type> get_handles(std::error_code & ec)
{
auto pid = ::boost::winapi::GetCurrentProcessId();
std::vector<char> buffer(2048);
constexpr static auto STATUS_INFO_LENGTH_MISMATCH_ = static_cast<::boost::winapi::NTSTATUS_>(0xC0000004l);
auto info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
::boost::winapi::NTSTATUS_ nt_status = STATUS_INFO_LENGTH_MISMATCH_;
for (;
nt_status == STATUS_INFO_LENGTH_MISMATCH_;
nt_status = workaround::nt_system_query_information(
workaround::SystemHandleInformation_,
info_pointer, static_cast<::boost::winapi::ULONG_>(buffer.size()),
nullptr))
{
buffer.resize(buffer.size() * 2);
info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
}
if (nt_status < 0 || nt_status > 0x7FFFFFFF)
{
ec = ::boost::process::detail::get_last_error();
return {};
}
else
ec.clear();
std::vector<native_handle_type> res;
for (auto itr = info_pointer->Handle; itr != (info_pointer->Handle + info_pointer->Count); itr++)
{
if (itr->OwnerPid == pid)
res.push_back(reinterpret_cast<native_handle_type>(static_cast<std::uintptr_t>(itr->HandleValue)));
}
return res;
}
inline std::vector<native_handle_type> get_handles()
{
std::error_code ec;
auto res = get_handles(ec);
if (ec)
boost::process::detail::throw_error(ec, "NtQuerySystemInformation failed");
return res;
}
inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
{
::boost::winapi::ULONG_ actual_size;
auto nt_status = workaround::nt_query_object(
handle,
workaround::ObjectTypeInformation,
NULL,
0, &actual_size);
std::vector<char> vec;
vec.resize(actual_size);
workaround::OBJECT_TYPE_INFORMATION_ * type_info_p = reinterpret_cast<workaround::OBJECT_TYPE_INFORMATION_*>(vec.data());
nt_status = workaround::nt_query_object(
handle,
workaround::ObjectTypeInformation,
type_info_p,
actual_size, &actual_size);
if (nt_status < 0 || nt_status > 0x7FFFFFFF)
{
ec = ::boost::process::detail::get_last_error();
return false;
}
else
ec.clear();
auto &nm = type_info_p->TypeName.Buffer;
return type_info_p->TypeName.Length >= 5 &&
nm[0] == L'F' &&
nm[1] == L'i' &&
nm[2] == L'l' &&
nm[3] == L'e' &&
nm[4] == L'\0';
}
inline bool is_stream_handle(native_handle_type handle)
{
std::error_code ec;
auto res = is_stream_handle(handle, ec);
if (ec)
boost::process::detail::throw_error(ec, "NtQueryObject failed");
return res;
}
struct limit_handles_ : handler_base_ext
{
mutable std::vector<::boost::winapi::HANDLE_> handles_with_inherit_flag;
template<typename Executor>
void on_setup(Executor & exec) const
{
auto all_handles = get_handles();
foreach_used_handle(exec,
[&](::boost::winapi::HANDLE_ handle)
{
auto itr = std::find(all_handles.begin(), all_handles .end(), handle);
::boost::winapi::DWORD_ flags = 0u;
if (itr != all_handles.end())
*itr = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if ((::boost::winapi::GetHandleInformation(*itr, &flags) != 0)
&&((flags & ::boost::winapi::HANDLE_FLAG_INHERIT_) == 0)) //it is NOT inherited anyhow, so ignore too
*itr = ::boost::winapi::INVALID_HANDLE_VALUE_;
});
auto part_itr = std::partition(all_handles.begin(), all_handles.end(),
[](::boost::winapi::HANDLE_ handle) {return handle != ::boost::winapi::INVALID_HANDLE_VALUE_;});
all_handles.erase(part_itr, all_handles.end()); //remove invalid handles
handles_with_inherit_flag = std::move(all_handles);
for (auto handle : handles_with_inherit_flag)
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, 0);
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code & ec) const
{
for (auto handle : handles_with_inherit_flag)
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);
}
template<typename Executor>
void on_sucess(Executor & exec) const
{
for (auto handle : handles_with_inherit_flag)
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);
}
};
}}}}
#endif //PROCESS_HANDLES_HPP

View File

@@ -3,12 +3,14 @@
// 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_WINDOWS_IO_SERVICE_REF_HPP_
#define BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
#ifndef BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_
#define BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/process/detail/windows/is_running.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/windows/object_handle.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
@@ -114,6 +116,15 @@ struct io_context_ref : boost::process::detail::handler_base
wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status);
::boost::winapi::DWORD_ code;
if(::boost::winapi::GetExitCodeProcess(process_handle, &code)
&& code != still_active)
{
::boost::asio::post(wh.handle->get_executor(), std::move(wh));
return;
}
auto handle_p = wh.handle.get();
handle_p->async_wait(std::move(wh));
}
@@ -130,12 +141,13 @@ struct io_context_ref : boost::process::detail::handler_base
boost::asio::io_context & ios, void * handle,
const std::shared_ptr<std::atomic<int>> &exit_status)
: funcs(std::move(funcs)),
handle(new boost::asio::windows::object_handle(ios, handle)),
handle(new boost::asio::windows::object_handle(
asio::prefer(ios.get_executor(), asio::execution::outstanding_work.tracked), handle)),
exit_status(exit_status)
{
}
void operator()(const boost::system::error_code & ec_in)
void operator()(const boost::system::error_code & ec_in = {})
{
std::error_code ec;
if (ec_in)
@@ -157,4 +169,4 @@ private:
}}}}
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
#endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2106 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)
@@ -7,6 +7,7 @@
#define BOOST_PROCESS_WINDOWS_IS_RUNNING_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/windows/child_handle.hpp>
#include <system_error>
#include <cstdlib>
#include <boost/winapi/process.hpp>
@@ -18,22 +19,6 @@ constexpr static ::boost::winapi::DWORD_ still_active = 259;
struct child_handle;
inline bool is_running(const child_handle &p, int & exit_code)
{
::boost::winapi::DWORD_ code;
//single value, not needed in the winapi.
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &code))
::boost::process::detail::throw_last_error("GetExitCodeProcess() failed");
if (code == still_active)
return true;
else
{
exit_code = code;
return false;
}
}
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
::boost::winapi::DWORD_ code;
@@ -49,7 +34,15 @@ inline bool is_running(const child_handle &p, int & exit_code, std::error_code &
{
exit_code = code;
return false;
}
}
}
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::detail::throw_error(ec, "GetExitCodeProcess() failed in is_running");
return b;
}
inline bool is_running(int code)

View File

@@ -9,68 +9,184 @@
#include <boost/winapi/config.hpp>
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/dll.hpp>
#include <boost/winapi/overlapped.hpp>
#if defined( BOOST_USE_WINDOWS_H )
#include <windows.h>
#else
extern "C"
{
BOOST_SYMBOL_IMPORT ::boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC CreateIoCompletionPort(
::boost::winapi::HANDLE_ FileHandle,
::boost::winapi::HANDLE_ ExistingCompletionPort,
::boost::winapi::ULONG_PTR_ CompletionKey,
::boost::winapi::DWORD_ NumberOfConcurrentThreads
);
BOOST_SYMBOL_IMPORT ::boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC GetQueuedCompletionStatus(
::boost::winapi::HANDLE_ CompletionPort,
::boost::winapi::LPDWORD_ lpNumberOfBytes,
::boost::winapi::ULONG_PTR_ *lpCompletionKey,
_OVERLAPPED **lpOverlapped,
::boost::winapi::DWORD_ dwMilliseconds
);
}
#endif
namespace boost { namespace process { namespace detail { namespace windows { namespace workaround {
extern "C"
{
struct JOBOBJECT_ASSOCIATE_COMPLETION_PORT_
{
::boost::winapi::PVOID_ CompletionKey;
::boost::winapi::HANDLE_ CompletionPort;
};
constexpr static int JOB_OBJECT_MSG_END_OF_JOB_TIME_ = 1;
constexpr static int JOB_OBJECT_MSG_END_OF_PROCESS_TIME_ = 2;
constexpr static int JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT_ = 3;
constexpr static int JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO_ = 4;
constexpr static int JOB_OBJECT_MSG_NEW_PROCESS_ = 6;
constexpr static int JOB_OBJECT_MSG_EXIT_PROCESS_ = 7;
constexpr static int JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS_ = 8;
constexpr static int JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT_ = 9;
constexpr static int JOB_OBJECT_MSG_JOB_MEMORY_LIMIT_ = 10;
constexpr static int JOB_OBJECT_MSG_NOTIFICATION_LIMIT_ = 11;
constexpr static int JOB_OBJECT_MSG_JOB_CYCLE_TIME_LIMIT_ = 12;
constexpr static int JOB_OBJECT_MSG_SILO_TERMINATED_ = 13;
}
BOOST_FORCEINLINE ::boost::winapi::BOOL_ get_queued_completion_status(
::boost::winapi::HANDLE_ CompletionPort,
::boost::winapi::LPDWORD_ lpNumberOfBytes,
::boost::winapi::ULONG_PTR_ *lpCompletionKey,
::boost::winapi::LPOVERLAPPED_ *lpOverlapped,
::boost::winapi::DWORD_ dwMilliseconds)
{
return ::GetQueuedCompletionStatus(
CompletionPort,
lpNumberOfBytes,
lpCompletionKey,
reinterpret_cast<::_OVERLAPPED**>(lpOverlapped),
dwMilliseconds);
}
#if defined( BOOST_USE_WINDOWS_H )
constexpr auto static JobObjectExtendedLimitInformation_ = ::JobObjectExtendedLimitInformation;
constexpr auto static JobObjectAssociateCompletionPortInformation_ = ::JobObjectAssociateCompletionPortInformation;
constexpr auto static JobObjectBasicAccountingInformation_ = ::JobObjectBasicAccountingInformation;
using JOBOBJECT_BASIC_LIMIT_INFORMATION_ = ::JOBOBJECT_BASIC_LIMIT_INFORMATION;
using JOBOBJECTINFOCLASS_ = ::JOBOBJECTINFOCLASS;
using IO_COUNTERS_ = ::IO_COUNTERS;
using JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ = ::JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
using JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ = ::JOBOBJECT_BASIC_ACCOUNTING_INFORMATION;
inline ::boost::winapi::BOOL_ query_information_job_object(
::boost::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
void * lpJobObjectInfo,
::boost::winapi::DWORD_ cbJobObjectInfoLength,
::boost::winapi::DWORD_ *lpReturnLength)
{
return ::QueryInformationJobObject(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength);
}
inline ::boost::winapi::BOOL_ set_information_job_object(
::boost::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
void * lpJobObjectInfo,
::boost::winapi::DWORD_ cbJobObjectInfoLength)
{
return ::SetInformationJobObject(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength);
}
#else
//this import workaround is to keep it a header-only library. and enums cannot be imported from the winapi.
extern "C"
{
typedef enum _JOBOBJECTINFOCLASS_ {
JobObjectBasicAccountingInformation_ = 1, JobObjectBasicLimitInformation_,
JobObjectBasicProcessIdList_, JobObjectBasicUIRestrictions_,
JobObjectSecurityLimitInformation_, JobObjectEndOfJobTimeInformation_,
JobObjectAssociateCompletionPortInformation_, JobObjectBasicAndIoAccountingInformation_,
JobObjectExtendedLimitInformation_, JobObjectJobSetInformation_,
JobObjectGroupInformation_,
JobObjectNotificationLimitInformation_,
JobObjectLimitViolationInformation_,
JobObjectGroupInformationEx_,
JobObjectCpuRateControlInformation_,
JobObjectCompletionFilter_,
JobObjectCompletionCounter_,
JobObjectReserved1Information_ = 18,
JobObjectReserved2Information_,
JobObjectReserved3Information_,
JobObjectReserved4Information_,
JobObjectReserved5Information_,
JobObjectReserved6Information_,
JobObjectReserved7Information_,
JobObjectReserved8Information_,
MaxJobObjectInfoClass_
} JOBOBJECTINFOCLASS_;
typedef enum _JOBOBJECTINFOCLASS_
{
JobObjectBasicAccountingInformation_ = 1,
JobObjectBasicLimitInformation_,
JobObjectBasicProcessIdList_,
JobObjectBasicUIRestrictions_,
JobObjectSecurityLimitInformation_,
JobObjectEndOfJobTimeInformation_,
JobObjectAssociateCompletionPortInformation_,
JobObjectBasicAndIoAccountingInformation_,
JobObjectExtendedLimitInformation_,
JobObjectJobSetInformation_,
JobObjectGroupInformation_,
JobObjectNotificationLimitInformation_,
JobObjectLimitViolationInformation_,
JobObjectGroupInformationEx_,
JobObjectCpuRateControlInformation_,
JobObjectCompletionFilter_,
JobObjectCompletionCounter_,
JobObjectReserved1Information_ = 18,
JobObjectReserved2Information_,
JobObjectReserved3Information_,
JobObjectReserved4Information_,
JobObjectReserved5Information_,
JobObjectReserved6Information_,
JobObjectReserved7Information_,
JobObjectReserved8Information_,
MaxJobObjectInfoClass_
} JOBOBJECTINFOCLASS_;
typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION_ {
::boost::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit;
::boost::winapi::LARGE_INTEGER_ PerJobUserTimeLimit;
::boost::winapi::DWORD_ LimitFlags;
::boost::winapi::SIZE_T_ MinimumWorkingSetSize;
::boost::winapi::SIZE_T_ MaximumWorkingSetSize;
::boost::winapi::DWORD_ ActiveProcessLimit;
::boost::winapi::ULONG_PTR_ Affinity;
::boost::winapi::DWORD_ PriorityClass;
::boost::winapi::DWORD_ SchedulingClass;
typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION_
{
::boost::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit;
::boost::winapi::LARGE_INTEGER_ PerJobUserTimeLimit;
::boost::winapi::DWORD_ LimitFlags;
::boost::winapi::SIZE_T_ MinimumWorkingSetSize;
::boost::winapi::SIZE_T_ MaximumWorkingSetSize;
::boost::winapi::DWORD_ ActiveProcessLimit;
::boost::winapi::ULONG_PTR_ Affinity;
::boost::winapi::DWORD_ PriorityClass;
::boost::winapi::DWORD_ SchedulingClass;
} JOBOBJECT_BASIC_LIMIT_INFORMATION_;
typedef struct _IO_COUNTERS_ {
::boost::winapi::ULONGLONG_ ReadOperationCount;
::boost::winapi::ULONGLONG_ WriteOperationCount;
::boost::winapi::ULONGLONG_ OtherOperationCount;
::boost::winapi::ULONGLONG_ ReadTransferCount;
::boost::winapi::ULONGLONG_ WriteTransferCount;
::boost::winapi::ULONGLONG_ OtherTransferCount;
typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ {
::boost::winapi::LARGE_INTEGER_ TotalUserTime;
::boost::winapi::LARGE_INTEGER_ TotalKernelTime;
::boost::winapi::LARGE_INTEGER_ ThisPeriodTotalUserTime;
::boost::winapi::LARGE_INTEGER_ ThisPeriodTotalKernelTime;
::boost::winapi::DWORD_ TotalPageFaultCount;
::boost::winapi::DWORD_ TotalProcesses;
::boost::winapi::DWORD_ ActiveProcesses;
::boost::winapi::DWORD_ TotalTerminatedProcesses;
} JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_;
typedef struct _IO_COUNTERS_
{
::boost::winapi::ULONGLONG_ ReadOperationCount;
::boost::winapi::ULONGLONG_ WriteOperationCount;
::boost::winapi::ULONGLONG_ OtherOperationCount;
::boost::winapi::ULONGLONG_ ReadTransferCount;
::boost::winapi::ULONGLONG_ WriteTransferCount;
::boost::winapi::ULONGLONG_ OtherTransferCount;
} IO_COUNTERS_;
typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ {
JOBOBJECT_BASIC_LIMIT_INFORMATION_ BasicLimitInformation;
IO_COUNTERS_ IoInfo;
::boost::winapi::SIZE_T_ ProcessMemoryLimit;
::boost::winapi::SIZE_T_ JobMemoryLimit;
::boost::winapi::SIZE_T_ PeakProcessMemoryUsed;
::boost::winapi::SIZE_T_ PeakJobMemoryUsed;
typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_
{
JOBOBJECT_BASIC_LIMIT_INFORMATION_ BasicLimitInformation;
IO_COUNTERS_ IoInfo;
::boost::winapi::SIZE_T_ ProcessMemoryLimit;
::boost::winapi::SIZE_T_ JobMemoryLimit;
::boost::winapi::SIZE_T_ PeakProcessMemoryUsed;
::boost::winapi::SIZE_T_ PeakJobMemoryUsed;
} JOBOBJECT_EXTENDED_LIMIT_INFORMATION_;
@@ -82,7 +198,7 @@ typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ {
_Out_opt_ LPDWORD lpReturnLength
);
*/
typedef ::boost::winapi::BOOL_ ( WINAPI *query_information_job_object_p)(
typedef ::boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *query_information_job_object_p)(
::boost::winapi::HANDLE_,
JOBOBJECTINFOCLASS_,
void *,
@@ -90,17 +206,20 @@ typedef ::boost::winapi::BOOL_ ( WINAPI *query_information_job_object_p)(
::boost::winapi::DWORD_ *);
inline ::boost::winapi::BOOL_ WINAPI query_information_job_object(
inline ::boost::winapi::BOOL_ query_information_job_object(
::boost::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
void * lpJobObjectInfo,
void *lpJobObjectInfo,
::boost::winapi::DWORD_ cbJobObjectInfoLength,
::boost::winapi::DWORD_ *lpReturnLength)
{
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle("Kernel32.dll");
static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::winapi::get_proc_address(h, "QueryInformationJobObject"));
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(
L"Kernel32.dll");
static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::winapi::get_proc_address(
h, "QueryInformationJobObject"));
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength);
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo,
cbJobObjectInfoLength, lpReturnLength);
}
/*BOOL WINAPI SetInformationJobObject(
@@ -110,7 +229,7 @@ inline ::boost::winapi::BOOL_ WINAPI query_information_job_object(
_In_ DWORD cbJobObjectInfoLength
);*/
typedef ::boost::winapi::BOOL_ ( WINAPI *set_information_job_object_p)(
typedef ::boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *set_information_job_object_p)(
::boost::winapi::HANDLE_,
JOBOBJECTINFOCLASS_,
void *,
@@ -118,22 +237,25 @@ typedef ::boost::winapi::BOOL_ ( WINAPI *set_information_job_object_p)(
}
inline ::boost::winapi::BOOL_ WINAPI set_information_job_object(
inline ::boost::winapi::BOOL_ set_information_job_object(
::boost::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
void * lpJobObjectInfo,
void *lpJobObjectInfo,
::boost::winapi::DWORD_ cbJobObjectInfoLength)
{
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle("Kernel32.dll");
static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::winapi::get_proc_address(h, "SetInformationJobObject"));
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle(
L"Kernel32.dll");
static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::winapi::get_proc_address(
h, "SetInformationJobObject"));
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength);
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo,
cbJobObjectInfoLength);
}
#endif
constexpr static ::boost::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800;
}}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */

View File

@@ -41,11 +41,15 @@ class windows_file_codecvt
wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const override
{
boost::ignore_unused(state);
::boost::winapi::UINT_ codepage = AreFileApisANSI() ?
::boost::winapi::CP_ACP_ :
::boost::winapi::CP_OEMCP_;
int count;
auto codepage =
#if !defined(BOOST_NO_ANSI_APIS)
::boost::winapi::AreFileApisANSI() ?
::boost::winapi::CP_ACP_ :
#endif
::boost::winapi::CP_OEMCP_;
int count = 0;
if ((count = ::boost::winapi::MultiByteToWideChar(codepage,
::boost::winapi::MB_PRECOMPOSED_, from,
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to))) == 0)
@@ -64,11 +68,15 @@ class windows_file_codecvt
char* to, char* to_end, char*& to_next) const override
{
boost::ignore_unused(state);
auto codepage = ::boost::winapi::AreFileApisANSI() ?
auto codepage =
#if !defined(BOOST_NO_ANSI_APIS)
::boost::winapi::AreFileApisANSI() ?
::boost::winapi::CP_ACP_ :
#endif
::boost::winapi::CP_OEMCP_;
int count = 0;
int count;
if ((count = ::boost::winapi::WideCharToMultiByte(codepage,
::boost::winapi::WC_NO_BEST_FIT_CHARS_, from,
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to), 0, 0)) == 0)

View File

@@ -14,14 +14,18 @@
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct null_in : public ::boost::process::detail::handler_base
struct null_in : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
{
file_descriptor source{"NUL", file_descriptor::read};
::boost::winapi::HANDLE_ get_used_handles() const { return source.handle(); }
public:
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const

View File

@@ -14,15 +14,18 @@
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct null_out : public ::boost::process::detail::handler_base
struct null_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
{
file_descriptor sink {"NUL", file_descriptor::write}; //works because it gets destroyed AFTER launch.
::boost::winapi::HANDLE_ get_used_handles() const { return sink.handle(); }
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &e) const;
};

View File

@@ -6,13 +6,20 @@
#ifndef BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
#define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
#include <boost/process/async.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/asio/execution.hpp>
#include <system_error>
#include <functional>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail {
template<typename Tuple>
inline asio::io_context& get_io_context(const Tuple & tup);
namespace windows {
struct on_exit_ : boost::process::detail::windows::async_handler
{
@@ -23,12 +30,14 @@ struct on_exit_ : boost::process::detail::windows::async_handler
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
std::function<void(int, const std::error_code&)> on_exit_handler(Executor& exec)
{
auto handler = this->handler;
return [handler](int exit_code, const std::error_code & ec)
auto v = boost::asio::prefer(boost::process::detail::get_io_context(exec.seq).get_executor(),
boost::asio::execution::outstanding_work.tracked);
auto handler_ = this->handler;
return [v, handler_](int exit_code, const std::error_code & ec)
{
handler(static_cast<int>(exit_code), ec);
handler_(static_cast<int>(exit_code), ec);
};
}

View File

@@ -12,14 +12,17 @@
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct pipe_in : public ::boost::process::detail::handler_base
struct pipe_in : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
{
::boost::winapi::HANDLE_ handle;
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
pipe_in(::boost::winapi::HANDLE_ handle) : handle(handle) {}
template<typename T> //async_pipe

View File

@@ -13,6 +13,7 @@
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
@@ -20,10 +21,12 @@ namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct pipe_out : public ::boost::process::detail::handler_base
struct pipe_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
{
::boost::winapi::HANDLE_ handle;
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
pipe_out(::boost::winapi::HANDLE_ handle) : handle(handle) {}
template<typename T>
pipe_out(T & p) : handle(p.native_sink())

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