2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-19 16:32:15 +00:00

Compare commits

...

216 Commits

Author SHA1 Message Date
Klemens David Morgenstern
83c2a986cb trait & fwd decl fixes 2019-04-10 13:41:08 +08:00
Klemens David Morgenstern
41fff78e00 Trying to add dynamic_buffer with sfinae as proposed in boostorg/process#56 2019-04-10 12:51:46 +08:00
Klemens David Morgenstern
e85f0d0816 Closes klemens-morgenstern/boost-process#139 2019-04-10 12:18:02 +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
14b294c10c Merge branch 'develop' of github.com:boostorg/process into develop 2019-03-04 12:14:56 +08: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
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 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
9f6c338631 Merge pull request #140 from klemens-morgenstern/develop
master update
2018-02-07 00:19:10 +01:00
Klemens Morgenstern
c4ffd0c18d Merge pull request #135 from klemens-morgenstern/develop
Appveyor fixes
2018-02-02 23:26:12 +01:00
75 changed files with 1786 additions and 645 deletions

76
.circleci/config.yml Normal file
View File

@@ -0,0 +1,76 @@
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
python <(curl -s https://report.ci/upload.py) --name "Circle CI Gcc Tests" --framework boost
bash <(curl -s https://codecov.io/bash) -x gcov || true
echo "BUILD_RESULT: $FAILED"
exit $FAILED

View File

@@ -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,122 @@ env:
sudo: false
language: cpp
compiler:
- gcc
- gcc
os:
- linux
- linux
- osx
secure: "vs7qgXb0lQg8CTyDPSi3RQtOIOtssaCkBIx86UoEvTXwJCTOLPe7ZufQ0lobn0OVWo261AMx9GbumBBzqfsvJc1G6ixGBVwymiGli/R8DZDvvg9UdljsEk65s/XbujE/9qh97zKGGioFyCn1Bmf5+SdDAxsuXTZm/cBny5VxYaaCR7s2cFUmp4up/djqg1GI7uwBh3ceodT3OL1X3dlMV59gOJWWNsB+RO9b9DPhTW7nOlMNRiEFik4rweecQB0JS8LaHDjYwzIRrGYHX+lR9cE/O8GCCHcUOmq9jCozDdxx+HZRu4rb1ST1RiDbvYaoeTif0Df1fVXHWOoO2D4NlXB6tJPXw2mkop00j6zkcydUJYid6T1lwfEpXAhd5A9FvOIXO5hoju1wlqfkU2eFQ9Na8z8bCIX2niZmveZWp4Ag52gEPzJMFx9hHGT8J4FWMvkqTWezux1sPZrjZjc0kXdJrIp84D9MsBc1sKrxOAOb5ekSfIK5n4JDkgUtuwMSTvEdWqNJXFPZq1rEu4GTwX99z3/XF+pM5XaCDQtZ/zUA5SPHhy0dKLH/BvceUqLJt53+lMcpsltJDB+XxQ/CFL7IdgR91OKGus/z4dbVWiSdkoNvcuZqjQLFLOMVNxoqC6PRvDAEhpy21j/5GUPvM5baQS7IEin0NF7bOTtXJdY="
env:
matrix:
- BADGE=linux
- 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; 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
- 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=.
- ../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
after_success:
# Copying Coveralls data to a separate folder
- mkdir -p $TRAVIS_BUILD_DIR/coverals
- 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
after_script:
- curl -s https://report.ci/upload.py | python - --token=$REPORT_CI_TOKEN --name="$BADGE test run"
- bash <(curl -s https://codecov.io/bash)
# Sending data to Coveralls
- cd $TRAVIS_BUILD_DIR
- gem install coveralls-lcov
- coveralls-lcov coverals/coverage.info

View File

@@ -4,10 +4,11 @@ Boost.process is a library for comfortable management of processes, released wit
### 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 | OSX | Windows | Code coverage | Matrix |
----------------|-------|-----|---------| ------------- |--------|
Develop: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=develop&env=BADGE=linux)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=develop&build=linux)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=linux) | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=develop&env=BADGE=osx)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=develop&build=osx)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=osx) | [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba/branch/develop?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/develop) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=develop&build=windows)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=windows) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=develop)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=develop) | [![Matrix](https://img.shields.io/badge/matrix-develop-lightgray.svg)](http://www.boost.org/development/tests/develop/developer/process.html)
Master: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=master&env=BADGE=linux)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=master&build=linux)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=linux) | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=master&env=BADGE=osx)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=master&build=osx)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=osx) | [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba/branch/master?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=master&build=windows)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=windows) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=master)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) | [![Matrix](https://img.shields.io/badge/matrix-master-lightgray.svg)](http://www.boost.org/development/tests/master/developer/process.html)
[Open Issues](https://github.com/klemens-morgenstern/boost-process/issues)

View File

@@ -5,10 +5,10 @@
[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.
@@ -50,7 +50,7 @@ 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.
@@ -95,24 +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>
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
}
};
```
[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__
@@ -120,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;
};

View File

@@ -158,7 +158,7 @@ will change the behaviour, so that instead of throwing an exception, the error w
```
std::error_code ec;
bp::system c("g++ main.cpp", ec);
bp::system("g++ main.cpp", ec);
```
[endsect]
[section:io Synchronous I/O]
@@ -296,7 +296,7 @@ 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);

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

@@ -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>
@@ -64,11 +65,12 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
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::post(
ios.get_executor(),
[h, ec]() mutable
{
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
});
}
BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
@@ -82,7 +84,7 @@ 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;
return [h](int exit_code, const std::error_code & ec) mutable

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

@@ -101,6 +101,8 @@ 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()
{
std::error_code ec;
@@ -143,11 +145,12 @@ public:
bool running(std::error_code & ec) noexcept
{
if (valid() && !_exited())
ec.clear();
if (valid() && !_exited() && !ec)
{
int exit_code = 0;
auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec);
if (!res && !_exited())
if (!ec && !res && !_exited())
_exit_status->store(exit_code);
return res;
@@ -157,10 +160,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
@@ -169,7 +173,8 @@ 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);
}
}
@@ -186,7 +191,7 @@ public:
{
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);
}

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;

View File

@@ -10,11 +10,13 @@
namespace boost { namespace asio {
class mutable_buffer;
class mutable_buffers_1;
template<typename T>
struct is_mutable_buffer_sequence;
template<typename T>
struct is_const_buffer_sequence;
class const_buffer;
class const_buffers_1;
template<typename Allocator>
class basic_streambuf;
@@ -22,6 +24,8 @@ class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_context;
class executor;
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class signal_set_service;
@@ -30,7 +34,9 @@ template <typename SignalSetService>
class basic_signal_set;
typedef basic_signal_set<signal_set_service> signal_set;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class signal_set;
template <typename Executor>
class basic_signal_set;
typedef basic_signal_set<executor> signal_set;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
template <typename Handler>
@@ -45,7 +51,9 @@ template <typename StreamDesscriptorService>
class basic_stream_descriptor;
typedef basic_stream_descriptor<stream_descriptor_service> stream_descriptor;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class stream_descriptor;
template <typename Executor>
class basic_stream_descriptor;
typedef basic_stream_descriptor<executor> stream_descriptor;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
} //posix

View File

@@ -39,30 +39,30 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
{
}
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;
}

View File

@@ -61,7 +61,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();
@@ -112,32 +112,32 @@ 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));
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;
}

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>
@@ -109,9 +110,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 +126,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 +149,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 +160,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 +219,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 +251,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

@@ -22,47 +22,12 @@
#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
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 +50,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 +122,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);
}
@@ -293,13 +258,43 @@ 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))
{
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 + "/" + 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;
@@ -338,6 +333,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 +346,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 +362,85 @@ 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(p.p[1]);
::close(p.p[1]);
_exit(EXIT_FAILURE);
return child();
}
::close(p.p[1]);
p.p[1] = -1;
_read_error(p.p[0]);
}
if (_ec)
{
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 +493,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 +510,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";

View File

@@ -56,7 +56,7 @@ 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;
}

View File

@@ -64,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.
@@ -79,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<
@@ -105,6 +106,15 @@ struct io_context_ref : handler_base_ext
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

@@ -16,8 +16,11 @@ 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 = 0x7F;
static_assert(!WIFEXITED(still_active) && !WIFSIGNALED(still_active), "Internal Error");
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");
inline bool is_running(int code)
{

View File

@@ -27,7 +27,7 @@ struct on_exit_ : boost::process::detail::posix::async_handler
{
return handler;
};
}
};

View File

@@ -7,6 +7,8 @@
#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>
@@ -36,22 +38,34 @@ 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)
{
_strand.post([this,ec]{this->_handle_signal(ec);});
});
_receivers.emplace_back(pid, h);
//check if the child actually is running first
int status;
auto pid_res = ::waitpid(pid, &status, WNOHANG);
if (pid_res < 0)
h(-1, get_last_error());
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
h(status, {}); //successfully exited already
else //still running
{
if (_receivers.empty())
_signal_set.async_wait(
[this](const boost::system::error_code &ec, int)
{
boost::asio::dispatch(_strand, [this, ec]{this->_handle_signal(ec);});
});
_receivers.emplace_back(pid, h);
}
});
return init.result.get();
}
void shutdown_service() override
void shutdown() override
{
_receivers.clear();
}
@@ -104,8 +118,7 @@ void sigchld_service::_handle_signal(const boost::system::error_code & ec)
_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

@@ -28,7 +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)));
while (((ret == -1) && (errno == EINTR)) ||
(ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
@@ -53,14 +54,43 @@ inline bool wait_until(
const std::chrono::time_point<Clock, Duration>& time_out,
std::error_code & ec) noexcept
{
::sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGCHLD);
auto get_timespec =
[](const Duration & dur)
{
::timespec ts;
ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(dur).count() % 1000000000;
return ts;
};
pid_t ret;
int status;
bool timed_out;
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 = Clock::now() >= time_out;
@@ -71,6 +101,61 @@ inline bool wait_until(
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;
::nanosleep(&ts, &rem);
while (rem.tv_sec > 0 || rem.tv_nsec > 0)
::nanosleep(&rem, &rem);
::exit(0);
}
struct child_cleaner_t
{
pid_t pid;
~child_cleaner_t()
{
int res;
::kill(pid, -15);
::waitpid(pid, &res, WNOHANG);
}
};
child_cleaner_t child_cleaner{timeout_pid};
do
{
int ret_sig = 0;
if ((::waitpid(timeout_pid, &status, WNOHANG) != 0)
&& (WIFEXITED(status) || WIFSIGNALED(status)))
ret_sig = ::sigwait(&sigset, nullptr);
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 = 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();
@@ -87,7 +172,7 @@ 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) noexcept
const std::chrono::time_point<Clock, Duration>& time_out)
{
std::error_code ec;
bool b = wait_until(p, exit_code, time_out, ec);
@@ -109,7 +194,7 @@ template< class Rep, class Period >
inline bool wait_for(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time) noexcept
const std::chrono::duration<Rep, Period>& rel_time)
{
std::error_code ec;
bool b = wait_for(p, exit_code, rel_time, ec);

View File

@@ -16,21 +16,30 @@
#include <system_error>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
inline void wait(const group_handle &p, std::error_code &ec) noexcept
{
pid_t ret;
int status;
siginfo_t status;
do
{
ret = ::waitpid(-p.grp, &status, 0);
}
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
ret = ::waitpid(-p.grp, &status.si_status, 0);
if (ret == -1)
{
ec = get_last_error();
return;
}
if (ret == -1)
//ECHILD --> no child processes left.
ret = ::waitid(P_PGID, p.grp, &status, WEXITED | WNOHANG);
}
while ((ret != -1) || (errno != ECHILD));
if (errno != ECHILD)
ec = boost::process::detail::get_last_error();
else
ec.clear();
@@ -49,31 +58,119 @@ inline bool wait_until(
const std::chrono::time_point<Clock, Duration>& time_out,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
bool timed_out;
::sigset_t sigset;
::siginfo_t siginfo;
sigemptyset(&sigset);
sigaddset(&sigset, SIGCHLD);
auto get_timespec =
[](const Duration & dur)
{
::timespec ts;
ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(dur).count() % 1000000000;
return ts;
};
bool timed_out = false;
int ret;
struct ::sigaction old_sig;
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
{
ec = get_last_error();
return false;
}
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
do
{
auto ts = get_timespec(time_out - Clock::now());
ret = ::sigtimedwait(&sigset, nullptr, &ts);
errno = 0;
if ((ret == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
old_sig.sa_handler(ret);
ret = ::waitpid(-p.grp, &siginfo.si_status, 0); //so in case it exited, we wanna reap it first
if (ret == -1)
{
ec = get_last_error();
return false;
}
//check if we're done
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG);
}
while (((ret != -1) || (errno != ECHILD)) && !(timed_out = (Clock::now() > time_out)));
#else
//if we do not have sigtimedwait, we fork off a child process to get the signal in time
pid_t timeout_pid = ::fork();
if (timeout_pid == -1)
{
ec = boost::process::detail::get_last_error();
return true;
}
else if (timeout_pid == 0)
{
auto ts = get_timespec(time_out - Clock::now());
::setpgid(0, p.grp);
::nanosleep(&ts, nullptr);
::exit(0);
}
struct child_cleaner_t
{
pid_t pid;
~child_cleaner_t()
{
int res;
::kill(pid, -15);
::waitpid(pid, &res, WNOHANG);
}
};
child_cleaner_t child_cleaner{timeout_pid};
do
{
ret = ::waitpid(-p.grp, &status, WNOHANG);
if (ret == 0)
int status;
if ((::waitpid(timeout_pid, &status, WNOHANG) != 0)
&& (WIFEXITED(status) || WIFSIGNALED(status)))
ret = ::sigwait(&sigset, nullptr);
errno = 0;
if ((ret == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
old_sig.sa_handler(ret);
ret = ::waitpid(-p.grp, &siginfo.si_status, 0); //so in case it exited, we wanna reap it first
if (ret == -1)
{
timed_out = Clock::now() >= time_out;
if (timed_out)
return false;
ec = get_last_error();
return false;
}
//check if we're done
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG);
}
while ((ret == 0) ||
(((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
while (((ret != -1) || (errno != ECHILD)) && !(timed_out = (Clock::now() > time_out)));
if (ret == -1)
#endif
if (errno != ECHILD)
{
ec = boost::process::detail::get_last_error();
return !timed_out;
}
else
{
ec.clear();
return true; //even if timed out, there are no child proccessess left
}
return true;
}
template< class Clock, class Duration >

View File

@@ -10,10 +10,12 @@
namespace boost { namespace asio {
class mutable_buffer;
class mutable_buffers_1;
class const_buffer;
class const_buffers_1;
template<typename T>
struct is_mutable_buffer_sequence;
template<typename T>
struct is_const_buffer_sequence;
template<typename Allocator>
class basic_streambuf;
@@ -21,6 +23,9 @@ class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_context;
class executor;
template <typename Handler>
class basic_yield_context;
@@ -34,7 +39,10 @@ class basic_stream_handle;
typedef basic_stream_handle<stream_handle_service> stream_handle;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class stream_handle;
template <typename Executor>
class basic_stream_handle;
typedef basic_stream_handle<executor> stream_handle;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
@@ -46,7 +54,9 @@ class basic_object_handle;
typedef basic_object_handle<object_handle_service> object_handle;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class object_handle;
template <typename Executor>
class basic_object_handle;
typedef basic_object_handle<executor> object_handle;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
} //windows

View File

@@ -48,28 +48,28 @@ struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
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

@@ -80,10 +80,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;
}
@@ -122,34 +122,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>
@@ -54,8 +55,6 @@ public:
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 +98,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 +111,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 +127,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 +143,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 +166,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 +177,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 +188,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 +215,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 +231,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,8 +265,10 @@ 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);
}
@@ -297,6 +311,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();
@@ -308,6 +360,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(
@@ -325,24 +379,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

@@ -143,8 +143,13 @@ 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);

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

@@ -84,22 +84,37 @@ 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);
}
@@ -110,15 +125,21 @@ struct group_handle
~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

@@ -3,8 +3,8 @@
// 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>
@@ -130,7 +130,7 @@ 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(ios.get_executor(), handle)),
exit_status(exit_status)
{
@@ -157,4 +157,4 @@ private:
}}}}
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
#endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */

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(L"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(L"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

@@ -25,10 +25,10 @@ struct on_exit_ : boost::process::detail::windows::async_handler
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
{
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)
{
handler(static_cast<int>(exit_code), ec);
handler_(static_cast<int>(exit_code), ec);
};
}

View File

@@ -55,9 +55,9 @@ inline boost::filesystem::path search_path(
for (auto & ext : extensions)
boost::to_lower(ext);
for (const boost::filesystem::path & pp : path)
for (const boost::filesystem::path & pp_ : path)
{
auto p = pp / filename;
auto p = pp_ / filename;
for (boost::filesystem::path ext : extensions)
{
boost::filesystem::path pp = p;

View File

@@ -34,7 +34,7 @@ struct create_no_window_ : public ::boost::process::detail::handler_base
template <class Executor>
void on_setup(Executor &exec) const
{
exec.creation_flags |= ::boost::detail::winapi::CREATE_NO_WINDOW_;
exec.creation_flags |= ::boost::winapi::CREATE_NO_WINDOW_;
}
};

View File

@@ -7,6 +7,7 @@
#define BOOST_PROCESS_DETAIL_WINDOWS_WAIT_GROUP_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/windows/group_handle.hpp>
#include <boost/winapi/jobs.hpp>
#include <boost/winapi/wait.hpp>
#include <chrono>
@@ -15,11 +16,61 @@ namespace boost { namespace process { namespace detail { namespace windows {
struct group_handle;
inline bool wait_impl(const group_handle & p, std::error_code & ec, std::chrono::system_clock::rep wait_time)
{
::boost::winapi::DWORD_ completion_code;
::boost::winapi::ULONG_PTR_ completion_key;
::boost::winapi::LPOVERLAPPED_ overlapped;
auto start_time = std::chrono::system_clock::now();
while (workaround::get_queued_completion_status(
p._io_port, &completion_code,
&completion_key, &overlapped, wait_time))
{
if (reinterpret_cast<::boost::winapi::HANDLE_>(completion_key) == p._job_object &&
completion_code == workaround::JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO_)
{
//double check, could be a different handle from a child
workaround::JOBOBJECT_BASIC_ACCOUNTING_INFORMATION_ info;
if (!workaround::query_information_job_object(
p._job_object,
workaround::JobObjectBasicAccountingInformation_,
static_cast<void *>(&info),
sizeof(info), nullptr))
{
ec = get_last_error();
return false;
}
else if (info.ActiveProcesses == 0)
return false; //correct, nothing left.
}
//reduce the remaining wait time -> in case interrupted by something else
if (wait_time != static_cast<int>(::boost::winapi::infinite))
{
auto now = std::chrono::system_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
wait_time -= static_cast<std::chrono::system_clock::rep>(diff.count());
start_time = now;
if (wait_time <= 0)
return true; //timeout with other source
}
}
auto ec_ = get_last_error();
if (ec_.value() == ::boost::winapi::wait_timeout)
return true; //timeout
ec = ec_;
return false;
}
inline void wait(const group_handle &p, std::error_code &ec)
{
if (::boost::winapi::WaitForSingleObject(p.handle(),
::boost::winapi::infinite) == ::boost::winapi::wait_failed)
ec = get_last_error();
wait_impl(p, ec, ::boost::winapi::infinite);
}
inline void wait(const group_handle &p)
@@ -39,16 +90,8 @@ inline bool wait_until(
std::chrono::duration_cast<std::chrono::milliseconds>(
timeout_time - Clock::now());
::boost::winapi::DWORD_ wait_code;
wait_code = ::boost::winapi::WaitForSingleObject(p.handle(), ms.count());
if (wait_code == ::boost::winapi::wait_failed)
ec = get_last_error();
else if (wait_code == ::boost::winapi::wait_timeout)
return false; //
return true;
auto timeout = wait_impl(p, ec, ms.count());
return !ec && !timeout;
}
template< class Clock, class Duration >
@@ -68,7 +111,9 @@ inline bool wait_for(
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code &ec)
{
return wait_until(p, std::chrono::steady_clock::now() + rel_time, ec);
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
auto timeout = wait_impl(p, ec, ms.count());
return !ec && !timeout;
}
template< class Rep, class Period >

View File

@@ -94,8 +94,8 @@ struct entry : const_entry<Char, Environment>
explicit entry(string_type&& name, pointer data, environment_t & env) :
father(std::move(name), data, env) {}
explicit entry(string_type &&name, environment_t & env) :
father(std::move(name), env) {}
explicit entry(string_type &&name, environment_t & env_) :
father(std::move(name), env_) {}
entry(const entry&) = default;
entry& operator=(const entry&) = default;

View File

@@ -26,10 +26,28 @@ namespace boost {
</programlisting>
\endxmlonly
*/
namespace boost { namespace process { namespace detail {
namespace boost {
namespace filesystem { class path; }
namespace process {
namespace detail {
struct exe_
{
template<typename = void>
inline exe_setter_<typename boost::filesystem::path::value_type> operator()(const boost::filesystem::path & pth) const
{
return exe_setter_<typename boost::filesystem::path::value_type>(pth.native());
}
template<typename = void>
inline exe_setter_<typename boost::filesystem::path::value_type> operator=(const boost::filesystem::path & pth) const
{
return exe_setter_<typename boost::filesystem::path::value_type>(pth.native());
}
template<typename Char>
inline exe_setter_<Char> operator()(const Char *s) const
{

View File

@@ -164,10 +164,10 @@ struct require_io_context {};
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)
{
handler(static_cast<int>(exit_code), ec);
handler_(static_cast<int>(exit_code), ec);
};
}

View File

@@ -122,20 +122,6 @@ system("b2", std_out > null);
namespace boost { namespace process { namespace detail {
template<typename T> using is_streambuf = typename std::is_same<T, boost::asio::streambuf>::type;
template<typename T> using is_const_buffer =
std::integral_constant<bool,
std::is_same< boost::asio::const_buffer, T>::value |
std::is_base_of<boost::asio::const_buffer, T>::value
>;
template<typename T> using is_mutable_buffer =
std::integral_constant<bool,
std::is_same< boost::asio::mutable_buffer, T>::value |
std::is_base_of<boost::asio::mutable_buffer, T>::value
>;
struct null_t {constexpr null_t() {}};
struct close_t;
@@ -177,19 +163,25 @@ struct std_in_
api::async_pipe_in operator=(async_pipe & p) const {return p;}
api::async_pipe_in operator<(async_pipe & p) const {return p;}
template<typename T, typename = typename std::enable_if<
is_const_buffer<T>::value || is_mutable_buffer<T>::value
>::type>
api::async_in_buffer<const T> operator=(const T & buf) const {return buf;}
template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
api::async_in_buffer<T> operator=(T & buf) const {return buf;}
template<typename T>
auto operator=(const T & buf) const -> typename std::enable_if<asio::is_const_buffer_sequence<T>::value, api::async_in_buffer<const T>>::type {return buf;}
template<typename T>
auto operator<(const T & buf) const -> typename std::enable_if<asio::is_const_buffer_sequence<T>::value, api::async_in_buffer<const T>>::type {return buf;}
template<typename T, typename = typename std::enable_if<
is_const_buffer<T>::value || is_mutable_buffer<T>::value
>::type>
api::async_in_buffer<const T> operator<(const T & buf) const {return buf;}
template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
api::async_in_buffer<T> operator<(T & buf) const {return buf;}
template<typename T>
auto operator=(T & buf) const -> typename std::enable_if<asio::is_const_buffer_sequence<T>::value, api::async_in_buffer<T>>::type {return buf;}
template<typename T>
auto operator<(T & buf) const -> typename std::enable_if<asio::is_const_buffer_sequence<T>::value, api::async_in_buffer<T>>::type {return buf;}
template<typename Allocator>
api::async_in_buffer<asio::basic_streambuf<Allocator>> operator<(boost::asio::basic_streambuf<Allocator> & p) const {return p;}
template<typename Allocator>
api::async_in_buffer<asio::basic_streambuf<Allocator>> operator=(boost::asio::basic_streambuf<Allocator> & p) const {return p;}
template<typename Allocator>
api::async_in_buffer<asio::basic_streambuf<Allocator>> operator<(const boost::asio::basic_streambuf<Allocator> & p) const {return p;}
template<typename Allocator>
api::async_in_buffer<asio::basic_streambuf<Allocator>> operator=(const boost::asio::basic_streambuf<Allocator> & p) const {return p;}
};
@@ -234,13 +226,24 @@ struct std_out_
api::async_pipe_out<p1, p2> operator=(async_pipe & p) const {return p;}
api::async_pipe_out<p1, p2> operator>(async_pipe & p) const {return p;}
api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator=(const asio::mutable_buffer & buf) const {return buf;}
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator=(const asio::mutable_buffers_1 & buf) const {return buf;}
api::async_out_buffer<p1, p2, asio::streambuf> operator=(asio::streambuf & os) const {return os ;}
template<typename Allocator>
api::async_out_buffer<p1, p2, asio::basic_streambuf<Allocator>> operator=(boost::asio::basic_streambuf<Allocator> & p) const {return p;}
template<typename Allocator>
api::async_out_buffer<p1, p2, asio::basic_streambuf<Allocator>> operator>(boost::asio::basic_streambuf<Allocator> & p) const {return p;}
api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator>(const asio::mutable_buffer & buf) const {return buf;}
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator>(const asio::mutable_buffers_1 & buf) const {return buf;}
api::async_out_buffer<p1, p2, asio::streambuf> operator>(asio::streambuf & os) const {return os ;}
template<typename Buffer>
auto operator=(const Buffer & buf) const
-> typename std::enable_if<asio::is_mutable_buffer_sequence<Buffer>::value, api::async_out_buffer<p1, p2, Buffer>>::type
{
return buf;
}
template<typename Buffer>
auto operator>(const Buffer & buf) const
-> typename std::enable_if<asio::is_mutable_buffer_sequence<Buffer>::value, api::async_out_buffer<p1, p2, Buffer>>::type
{
return buf;
}
api::async_out_future<p1,p2, std::string> operator=(std::future<std::string> & fut) const { return fut;}
api::async_out_future<p1,p2, std::string> operator>(std::future<std::string> & fut) const { return fut;}

View File

@@ -223,7 +223,7 @@ private:
return false;
auto base = this->pbase();
auto wrt = _pipe.write(base,
std::ptrdiff_t wrt = _pipe.write(base,
static_cast<typename pipe_type::int_type>(this->pptr() - base));
std::ptrdiff_t diff = this->pptr() - base;
@@ -250,7 +250,7 @@ template<
>
class basic_ipstream : public std::basic_istream<CharT, Traits>
{
basic_pipebuf<CharT, Traits> _buf;
mutable basic_pipebuf<CharT, Traits> _buf;
public:
typedef basic_pipe<CharT, Traits> pipe_type;
@@ -262,7 +262,7 @@ public:
typedef typename Traits::off_type off_type ;
///Get access to the underlying stream_buf
basic_pipebuf<CharT, Traits>* rdbuf() {return &_buf;};
basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
///Default constructor.
basic_ipstream() : std::basic_istream<CharT, Traits>(nullptr)
@@ -272,7 +272,10 @@ public:
///Copy constructor.
basic_ipstream(const basic_ipstream & ) = delete;
///Move constructor.
basic_ipstream(basic_ipstream && ) = default;
basic_ipstream(basic_ipstream && lhs) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
{
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
}
///Move construct from a pipe.
basic_ipstream(pipe_type && p) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(p))
@@ -289,7 +292,12 @@ public:
///Copy assignment.
basic_ipstream& operator=(const basic_ipstream & ) = delete;
///Move assignment
basic_ipstream& operator=(basic_ipstream && ) = default;
basic_ipstream& operator=(basic_ipstream && lhs)
{
std::basic_istream<CharT, Traits>::operator=(std::move(lhs));
_buf = std::move(lhs);
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
};
///Move assignment of a pipe.
basic_ipstream& operator=(pipe_type && p)
{
@@ -326,7 +334,7 @@ template<
>
class basic_opstream : public std::basic_ostream<CharT, Traits>
{
basic_pipebuf<CharT, Traits> _buf;
mutable basic_pipebuf<CharT, Traits> _buf;
public:
typedef basic_pipe<CharT, Traits> pipe_type;
@@ -338,7 +346,7 @@ public:
///Get access to the underlying stream_buf
basic_pipebuf<CharT, Traits>* rdbuf() const {return _buf;};
basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
///Default constructor.
basic_opstream() : std::basic_ostream<CharT, Traits>(nullptr)
@@ -348,8 +356,10 @@ public:
///Copy constructor.
basic_opstream(const basic_opstream & ) = delete;
///Move constructor.
basic_opstream(basic_opstream && ) = default;
basic_opstream(basic_opstream && lhs) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
{
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
}
///Move construct from a pipe.
basic_opstream(pipe_type && p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(p))
{
@@ -363,7 +373,13 @@ public:
///Copy assignment.
basic_opstream& operator=(const basic_opstream & ) = delete;
///Move assignment
basic_opstream& operator=(basic_opstream && ) = default;
basic_opstream& operator=(basic_opstream && lhs)
{
std::basic_ostream<CharT, Traits>::operator=(std::move(lhs));
_buf = std::move(lhs);
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
};
///Move assignment of a pipe.
basic_opstream& operator=(pipe_type && p)
{
@@ -401,7 +417,7 @@ template<
>
class basic_pstream : public std::basic_iostream<CharT, Traits>
{
basic_pipebuf<CharT, Traits> _buf;
mutable basic_pipebuf<CharT, Traits> _buf;
public:
typedef basic_pipe<CharT, Traits> pipe_type;
@@ -413,7 +429,7 @@ public:
///Get access to the underlying stream_buf
basic_pipebuf<CharT, Traits>* rdbuf() const {return _buf;};
basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
///Default constructor.
basic_pstream() : std::basic_iostream<CharT, Traits>(nullptr)
@@ -423,8 +439,10 @@ public:
///Copy constructor.
basic_pstream(const basic_pstream & ) = delete;
///Move constructor.
basic_pstream(basic_pstream && ) = default;
basic_pstream(basic_pstream && lhs) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
{
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
}
///Move construct from a pipe.
basic_pstream(pipe_type && p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(p))
{
@@ -438,7 +456,12 @@ public:
///Copy assignment.
basic_pstream& operator=(const basic_pstream & ) = delete;
///Move assignment
basic_pstream& operator=(basic_pstream && ) = default;
basic_pstream& operator=(basic_pstream && lhs)
{
std::basic_istream<CharT, Traits>::operator=(std::move(lhs));
_buf = std::move(lhs);
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
};
///Move assignment of a pipe.
basic_pstream& operator=(pipe_type && p)
{

View File

@@ -13,6 +13,7 @@
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler.hpp>
#include <boost/process/locale.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#if defined (BOOST_POSIX_API)
#include <boost/process/detail/posix/start_dir.hpp>

View File

@@ -22,6 +22,7 @@
#include <boost/process/child.hpp>
#include <boost/process/detail/async_handler.hpp>
#include <boost/process/detail/execute_impl.hpp>
#include <boost/asio/post.hpp>
#include <type_traits>
#include <mutex>
#include <condition_variable>
@@ -62,7 +63,7 @@ inline int system_impl(
::boost::process::on_exit(
[&](int, const std::error_code&)
{
ios.post([&]{exited.store(true);});
boost::asio::post(ios.get_executor(), [&]{exited.store(true);});
}));
if (!c.valid() || !check.succeeded)
return -1;
@@ -85,6 +86,8 @@ inline int system_impl(
return -1;
ios.run();
if (c.running())
c.wait();
return c.exit_code();
}

View File

@@ -19,6 +19,7 @@ if [ os.name ] = NT
}
project : requirements
<define>BOOST_ASIO_NO_DEPRECATED
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
<toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
<toolset>msvc:<cxxflags>/bigobj
@@ -52,10 +53,17 @@ exe exit_argc : exit_argc.cpp :
exe sub_launch : sub_launcher.cpp program_options iostreams system filesystem : <warnings>off <target-os>windows:<source>shell32 ;
rule test-options ( name )
{
return --log_sink=log_$(name).xml --log_format=XML --log_level=error --report_sink=report_$(name).xml --report_format=XML --report_level=detailed -- ;
#return --log_level=error --report_level=detailed -- ;
}
test-suite bare :
[ run environment.cpp system filesystem ]
[ run async_pipe.cpp system filesystem ]
[ run pipe.cpp system filesystem ]
[ run environment.cpp system filesystem : [ test-options environment ] ]
[ run async_pipe.cpp system filesystem : [ test-options async_pipe ] ]
[ run pipe.cpp system filesystem : [ test-options pipe ] ]
[ compile no_ansi_apps.cpp ]
[ compile-fail spawn_fail.cpp ]
[ compile-fail async_system_fail.cpp ]
@@ -63,53 +71,55 @@ test-suite bare :
;
test-suite with-valgrind :
[ run async.cpp system thread filesystem : : sparring_partner ]
[ run async_fut.cpp system thread filesystem : : sparring_partner ]
[ run args_handling.cpp system thread filesystem : : exit_argc ]
[ run args_cmd.cpp system filesystem : : sparring_partner ]
[ run wargs_cmd.cpp system filesystem : : sparring_partner ]
[ run bind_stderr.cpp filesystem : : sparring_partner ]
[ run bind_stdin.cpp system filesystem : : sparring_partner ]
[ run bind_stdin_stdout.cpp system filesystem : : sparring_partner ]
[ run bind_stdout.cpp system filesystem : : sparring_partner ]
[ run bind_stdout_stderr.cpp system filesystem : : sparring_partner ]
[ run pipe_fwd.cpp system filesystem : : sparring_partner ]
[ run cmd_test.cpp system filesystem : : sparring_partner ]
[ run close_stderr.cpp system filesystem : : sparring_partner ]
[ run close_stdin.cpp system filesystem : : sparring_partner ]
[ run close_stdout.cpp system filesystem : : sparring_partner ]
[ run error.cpp system filesystem : : sparring_partner ]
[ run exit_code.cpp program_options system filesystem : : sparring_partner ]
[ run extensions.cpp system filesystem : : sparring_partner ]
[ run env.cpp program_options system filesystem : : sparring_partner ]
[ run group.cpp system thread filesystem : : sub_launch ]
[ run async.cpp system thread filesystem : [ test-options async ] : sparring_partner ]
[ run async_fut.cpp system thread filesystem : [ test-options async_fut ] : sparring_partner ]
[ run args_handling.cpp system thread filesystem : [ test-options args_handling ] : exit_argc ]
[ run args_cmd.cpp system filesystem : [ test-options args_cmd ] : sparring_partner ]
[ run wargs_cmd.cpp system filesystem : [ test-options wargs_cmd ] : sparring_partner ]
[ run bind_stderr.cpp filesystem : [ test-options bind_stderr ] : sparring_partner ]
[ run bind_stdin.cpp system filesystem : [ test-options bind_stdin ] : sparring_partner ]
[ run bind_stdin_stdout.cpp system filesystem : [ test-options bind_stdin_stdout ] : sparring_partner ]
[ run bind_stdout.cpp system filesystem : [ test-options bind_stdout ] : sparring_partner ]
[ run bind_stdout_stderr.cpp system filesystem : [ test-options bind_stdout_stderr ] : sparring_partner ]
[ run pipe_fwd.cpp system filesystem : [ test-options pipe_fwd ] : sparring_partner ]
[ run cmd_test.cpp system filesystem : [ test-options cmd_test ] : sparring_partner ]
[ run close_stderr.cpp system filesystem : [ test-options close_stderr ] : sparring_partner ]
[ run close_stdin.cpp system filesystem : [ test-options close_stdin ] : sparring_partner ]
[ run close_stdout.cpp system filesystem : [ test-options close_stdout ] : sparring_partner ]
[ run error.cpp system filesystem : [ test-options error ] : sparring_partner ]
[ run exit_code.cpp program_options system filesystem : [ test-options exit_code ] : sparring_partner ]
[ run extensions.cpp system filesystem : [ test-options extensions ] : sparring_partner ]
[ run env.cpp program_options system filesystem : [ test-options env ] : sparring_partner ]
[ run group.cpp system thread filesystem : [ test-options group ] : sub_launch ]
[ run group.cpp system thread filesystem : [ test-options group ] : sub_launch : <build>no <target-os>windows:<build>yes <define>BOOST_USE_WINDOWS_H=1 : group-windows-h ]
[ run group_wait.cpp system thread filesystem : [ test-options group_wait ] : sparring_partner ]
[ run run_exe.cpp filesystem : : sparring_partner ]
[ run run_exe_path.cpp filesystem : : sparring_partner ]
[ run search_path.cpp filesystem system : : : <target-os>windows:<source>shell32 ]
[ run shell.cpp filesystem system : : sparring_partner ]
[ run shell_path.cpp filesystem system ]
[ run system_test1.cpp filesystem system : : sparring_partner ]
[ run system_test2.cpp filesystem system : : sparring_partner ]
[ run spawn.cpp filesystem system : : sparring_partner ]
[ run start_dir.cpp filesystem system : : sparring_partner ]
[ run terminate.cpp system filesystem : : sparring_partner ]
[ run throw_on_error.cpp system filesystem : : sparring_partner ]
[ run wait.cpp system filesystem : : sparring_partner ]
[ run wait_for.cpp system filesystem : : sparring_partner ]
[ run on_exit.cpp system filesystem : : sparring_partner ]
[ run on_exit2.cpp system filesystem : : sparring_partner ]
[ run on_exit3.cpp system filesystem : : sparring_partner ]
[ run posix_specific.cpp system filesystem : : sparring_partner : <build>no <target-os>linux:<build>yes ]
[ run windows_specific.cpp filesystem system : : sparring_partner : <build>no <target-os>windows:<build>yes ]
[ run run_exe_path.cpp filesystem : [ test-options run_exe_path ] : sparring_partner ]
[ run search_path.cpp filesystem system : [ test-options search_path ] : : <target-os>windows:<source>shell32 ]
[ run shell.cpp filesystem system : [ test-options shell ] : sparring_partner ]
[ run shell_path.cpp filesystem system : [ test-options shell_path ] ]
[ run system_test1.cpp filesystem system : [ test-options system_test1 ] : sparring_partner ]
[ run system_test2.cpp filesystem system : [ test-options system_test2 ] : sparring_partner ]
[ run spawn.cpp filesystem system : [ test-options spawn ] : sparring_partner ]
[ run start_dir.cpp filesystem system : [ test-options start_dir ] : sparring_partner ]
[ run terminate.cpp system filesystem : [ test-options terminate ] : sparring_partner ]
[ run throw_on_error.cpp system filesystem : [ test-options throw_on_error ] : sparring_partner ]
[ run wait.cpp system filesystem : [ test-options wait ] : sparring_partner ]
[ run wait_for.cpp system filesystem : [ test-options wait_for ] : sparring_partner ]
[ run on_exit.cpp system filesystem : [ test-options on_exit ] : sparring_partner ]
[ run on_exit2.cpp system filesystem : [ test-options on_exit2 ] : sparring_partner ]
[ run on_exit3.cpp system filesystem : [ test-options on_exit3 ] : sparring_partner ]
[ run posix_specific.cpp system filesystem : [ test-options posix_specific ] : sparring_partner : <build>no <target-os>linux:<build>yes ]
[ run windows_specific.cpp filesystem system : [ test-options windows_specific ] : sparring_partner : <build>no <target-os>windows:<build>yes ]
: <dependency>bare ;
test-suite without-valgrind :
[ run async_system_future.cpp filesystem system coroutine : : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
[ run async_system_stackful.cpp filesystem system coroutine : : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
[ run async_system_stackful_error.cpp filesystem system coroutine : : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
[ run async_system_stackful_except.cpp filesystem system coroutine : : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
[ run async_system_stackless.cpp filesystem system coroutine : : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
[ run vfork.cpp system filesystem : : sparring_partner : <build>no <target-os>linux:<build>yes ]
[ run async_system_future.cpp filesystem system coroutine : [ test-options async_system_future ] : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
[ run async_system_stackful.cpp filesystem system coroutine : [ test-options async_system_stackful ] : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
[ run async_system_stackful_error.cpp filesystem system coroutine : [ test-options async_system_stackful_error ] : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
[ run async_system_stackful_except.cpp filesystem system coroutine : [ test-options async_system_stackful_except ] : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
[ run async_system_stackless.cpp filesystem system coroutine : [ test-options async_system_stackless ] : sparring_partner : <link>static <toolset>msvc:<cxxflags>/bigobj ]
[ run vfork.cpp system filesystem : [ test-options vfork ] : sparring_partner : <build>no <target-os>linux:<build>yes ]
;

View File

@@ -17,12 +17,13 @@ init:
os: Visual Studio 2015
configuration: Debug
platform: x64
build: off
###############################################################################################################
# From this point and below code is same for all the Boost libs
###############################################################################################################
version: 1.61.{build}-{branch}
version: 1.69.{build}-{branch}
# branches to build
branches:
@@ -72,3 +73,5 @@ after_test:
on_success:
on_failure:
on_finish:
- curl -s https://report.ci/upload.py | python - --name "windows test run" --root_dir=%BOOST%/libs/%PROJECT_TO_TEST%/test

View File

@@ -8,6 +8,6 @@ int main() {}
#if defined(BOOST_POSIX_API)
#include <boost/process/posix.hpp>
#elif
#else
#include <boost/process/windows.hpp>
#endif

View File

@@ -8,7 +8,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_TEST_MAIN
#define BOOST_TEST_IGNORE_SIGCHLD
//#define BOOST_TEST_IGNORE_SIGCHLD
#include <boost/test/included/unit_test.hpp>
#include <boost/process/error.hpp>
@@ -20,15 +20,21 @@
#include <future>
#include <boost/system/error_code.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/asio/deadline_timer.hpp>
using namespace std;
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(2))
#if __APPLE__
auto abort_sig = signal(SIGALRM, +[](int){std::terminate();});
#endif
BOOST_AUTO_TEST_SUITE( async );
BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(5))
{
using boost::unit_test::framework::master_test_suite;
using namespace boost::asio;
@@ -39,34 +45,34 @@ BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(2))
bool exit_called_for_c1 = false;
int exit_code_c1 = 0;
bp::child c1(
master_test_suite().argv[1],
"test", "--exit-code", "123",
ec,
io_context,
bp::on_exit([&](int exit, const std::error_code& ec_in)
{
BOOST_CHECK(!exit_called_for_c1);
exit_code_c1 = exit; exit_called_for_c1=true;
BOOST_CHECK(!ec_in);
})
);
boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
bp::child c1(master_test_suite().argv[1],
"test", "--exit-code", "123",
ec, io_context,
bp::on_exit([&](int exit, const std::error_code& ec_in)
{
BOOST_CHECK(!exit_called_for_c1);
exit_code_c1 = exit; exit_called_for_c1=true;
BOOST_CHECK(!ec_in);
timeout.cancel();
}));
BOOST_REQUIRE(!ec);
bool exit_called_for_c2 = false;
int exit_code_c2 = 0;
bp::child c2(
master_test_suite().argv[1],
"test", "--exit-code", "21",
ec,
io_context,
bp::on_exit([&](int exit, const std::error_code& ec_in)
{
BOOST_CHECK(!exit_called_for_c2);
exit_code_c2 = exit; exit_called_for_c2=true;
BOOST_CHECK(!ec_in);
})
);
bp::child c2(master_test_suite().argv[1],
"test", "--exit-code", "21",
ec, io_context,
bp::on_exit([&](int exit, const std::error_code& ec_in)
{
BOOST_CHECK(!exit_called_for_c2);
exit_code_c2 = exit; exit_called_for_c2=true;
BOOST_CHECK(!ec_in);
})
);
BOOST_REQUIRE(!ec);
io_context.run();
@@ -80,7 +86,7 @@ BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(2))
BOOST_CHECK_EQUAL(c2.exit_code(), 21);
}
BOOST_AUTO_TEST_CASE(async_wait_sync_wait, *boost::unit_test::timeout(3))
BOOST_AUTO_TEST_CASE(async_wait_sync_wait, *boost::unit_test::timeout(5))
{
using boost::unit_test::framework::master_test_suite;
using namespace boost::asio;
@@ -90,6 +96,10 @@ BOOST_AUTO_TEST_CASE(async_wait_sync_wait, *boost::unit_test::timeout(3))
bool exit_called = false;
int exit_code = 0;
std::error_code ec;
boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(3)};
timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
bp::child c1(
master_test_suite().argv[1],
"test", "--exit-code", "1",
@@ -106,6 +116,7 @@ BOOST_AUTO_TEST_CASE(async_wait_sync_wait, *boost::unit_test::timeout(3))
{
exit_code = exit; exit_called=true;
BOOST_CHECK(!ec_in);
timeout.cancel();
})
);
BOOST_REQUIRE(!ec);
@@ -121,7 +132,7 @@ BOOST_AUTO_TEST_CASE(async_wait_sync_wait, *boost::unit_test::timeout(3))
BOOST_CHECK_EQUAL(c2.exit_code(), 2);
}
BOOST_AUTO_TEST_CASE(async_wait_different_contexts, *boost::unit_test::timeout(3))
BOOST_AUTO_TEST_CASE(async_wait_different_contexts, *boost::unit_test::timeout(10))
{
using boost::unit_test::framework::master_test_suite;
using namespace boost::asio;
@@ -129,6 +140,11 @@ BOOST_AUTO_TEST_CASE(async_wait_different_contexts, *boost::unit_test::timeout(3
boost::asio::io_context io_context1;
boost::asio::io_context io_context2;
boost::asio::deadline_timer timeout1{io_context1, boost::posix_time::seconds(2)};
timeout1.async_wait([&](boost::system::error_code ec){if (!ec) io_context1.stop();});
boost::asio::deadline_timer timeout2{io_context2, boost::posix_time::seconds(7)};
timeout2.async_wait([&](boost::system::error_code ec){if (!ec) io_context2.stop();});
std::error_code ec;
bool exit_called_for_c1 = false;
@@ -143,6 +159,7 @@ BOOST_AUTO_TEST_CASE(async_wait_different_contexts, *boost::unit_test::timeout(3
BOOST_CHECK(!exit_called_for_c1);
exit_code_c1 = exit; exit_called_for_c1=true;
BOOST_CHECK(!ec_in);
timeout1.cancel();
})
);
BOOST_REQUIRE(!ec);
@@ -151,7 +168,7 @@ BOOST_AUTO_TEST_CASE(async_wait_different_contexts, *boost::unit_test::timeout(3
int exit_code_c2 = 0;
bp::child c2(
master_test_suite().argv[1],
"test", "--exit-code", "2", "--wait", "1",
"test", "--exit-code", "2", "--wait", "4",
ec,
io_context2,
bp::on_exit([&](int exit, const std::error_code& ec_in)
@@ -159,13 +176,17 @@ BOOST_AUTO_TEST_CASE(async_wait_different_contexts, *boost::unit_test::timeout(3
BOOST_CHECK(!exit_called_for_c2);
exit_code_c2 = exit; exit_called_for_c2=true;
BOOST_CHECK(!ec_in);
timeout2.cancel();
})
);
BOOST_REQUIRE(!ec);
// Regression test for #143: make sure each io_context handles its own children
io_context2.run();
io_context1.run();
std::thread thr1{[&]{io_context1.run();}};
std::thread thr2{[&]{io_context2.run();}};
thr1.join();
thr2.join();
c1.wait(ec);
BOOST_REQUIRE(!ec);
@@ -177,7 +198,7 @@ BOOST_AUTO_TEST_CASE(async_wait_different_contexts, *boost::unit_test::timeout(3
BOOST_CHECK_EQUAL(c2.exit_code(), 2);
}
BOOST_AUTO_TEST_CASE(async_wait_abort, *boost::unit_test::timeout(2))
BOOST_AUTO_TEST_CASE(async_wait_abort, *boost::unit_test::timeout(5))
{
using boost::unit_test::framework::master_test_suite;
using namespace boost::asio;
@@ -186,6 +207,9 @@ BOOST_AUTO_TEST_CASE(async_wait_abort, *boost::unit_test::timeout(2))
std::error_code ec;
boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(5)};
timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
bool exit_called = false;
int exit_code = 0;
bp::child c(
@@ -196,9 +220,11 @@ BOOST_AUTO_TEST_CASE(async_wait_abort, *boost::unit_test::timeout(2))
bp::on_exit([&](int exit, const std::error_code& ec_in)
{
BOOST_CHECK(!exit_called);
exit_code = exit; exit_called=true;
exit_code = exit;
exit_called=true;
BOOST_TEST_MESSAGE(ec_in.message());
BOOST_CHECK(!ec_in);
timeout.cancel();
})
);
BOOST_REQUIRE(!ec);
@@ -206,18 +232,21 @@ BOOST_AUTO_TEST_CASE(async_wait_abort, *boost::unit_test::timeout(2))
io_context.run();
BOOST_CHECK(exit_called);
BOOST_CHECK(exit_code != 0);
BOOST_CHECK_NE(exit_code, 0);
BOOST_CHECK_EQUAL(c.exit_code(), exit_code);
}
BOOST_AUTO_TEST_CASE(async_future, *boost::unit_test::timeout(2))
BOOST_AUTO_TEST_CASE(async_future, *boost::unit_test::timeout(3))
{
using boost::unit_test::framework::master_test_suite;
using namespace boost::asio;
boost::asio::io_context io_context;
boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
std::error_code ec;
std::future<int> fut;
bp::child c(
@@ -229,13 +258,15 @@ BOOST_AUTO_TEST_CASE(async_future, *boost::unit_test::timeout(2))
);
BOOST_REQUIRE(!ec);
io_context.run();
BOOST_REQUIRE(fut.valid());
BOOST_CHECK_EQUAL(fut.get(), 42);
}
BOOST_AUTO_TEST_CASE(async_out_stream, *boost::unit_test::timeout(2))
BOOST_AUTO_TEST_CASE(async_out_stream, *boost::unit_test::timeout(5))
{
using boost::unit_test::framework::master_test_suite;
@@ -246,6 +277,9 @@ BOOST_AUTO_TEST_CASE(async_out_stream, *boost::unit_test::timeout(2))
boost::asio::streambuf buf;
boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
bp::child c(master_test_suite().argv[1],
"test", "--echo-stdout", "abc",
bp::std_out > buf,
@@ -253,8 +287,8 @@ BOOST_AUTO_TEST_CASE(async_out_stream, *boost::unit_test::timeout(2))
ec);
BOOST_REQUIRE(!ec);
io_context.run();
std::istream istr(&buf);
std::string line;
@@ -266,7 +300,7 @@ BOOST_AUTO_TEST_CASE(async_out_stream, *boost::unit_test::timeout(2))
BOOST_AUTO_TEST_CASE(async_in_stream, *boost::unit_test::timeout(2))
BOOST_AUTO_TEST_CASE(async_in_stream, *boost::unit_test::timeout(5))
{
using boost::unit_test::framework::master_test_suite;
@@ -283,6 +317,9 @@ BOOST_AUTO_TEST_CASE(async_in_stream, *boost::unit_test::timeout(2))
std::ostream ostr(&in_buf);
ostr << "-string" << endl ;
boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
bp::child c(
master_test_suite().argv[1],
"test", "--prefix-once", "test",
@@ -293,8 +330,8 @@ BOOST_AUTO_TEST_CASE(async_in_stream, *boost::unit_test::timeout(2))
);
BOOST_REQUIRE(!ec);
io_context.run();
std::istream istr(&buf);
std::string line;
@@ -310,13 +347,16 @@ BOOST_AUTO_TEST_CASE(async_in_stream, *boost::unit_test::timeout(2))
}
BOOST_AUTO_TEST_CASE(async_error, *boost::unit_test::timeout(2))
BOOST_AUTO_TEST_CASE(async_error, *boost::unit_test::timeout(3))
{
using boost::unit_test::framework::master_test_suite;
using namespace boost::asio;
boost::asio::io_context io_context;
boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
bool exit_called = false;
std::error_code ec;
bp::child c(
@@ -330,7 +370,47 @@ BOOST_AUTO_TEST_CASE(async_error, *boost::unit_test::timeout(2))
);
BOOST_REQUIRE(ec);
io_context.run();
BOOST_CHECK(!exit_called);
}
/*
BOOST_AUTO_TEST_CASE(mixed_async, *boost::unit_test::timeout(5))
{
using boost::unit_test::framework::master_test_suite;
using namespace boost::asio;
boost::asio::io_context io_context;
boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
bool exit_called = false;
std::error_code ec;
bp::child c(master_test_suite().argv[1],
"--wait", "1", "--exit-code", "42",
ec,
io_context,
bp::on_exit([&](int exit, const std::error_code& ec_in)
{
timeout.cancel();
exit_called=true;
BOOST_CHECK_EQUAL(exit, 42);
})
);
BOOST_REQUIRE(!ec);
std::thread thr([&]{c.wait();});
io_context.run();
BOOST_CHECK(exit_called);
BOOST_CHECK_EQUAL(c.exit_code(), 42);
thr.join();
}*/
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -24,6 +24,8 @@
#include <boost/algorithm/string/predicate.hpp>
BOOST_AUTO_TEST_SUITE( async );
using namespace std;
@@ -101,3 +103,4 @@ BOOST_AUTO_TEST_CASE(emtpy_out, *boost::unit_test::timeout(2))
BOOST_CHECK_EQUAL(fut.get(), "");
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -23,6 +23,9 @@ using namespace std;
namespace bp = boost::process;
namespace asio = boost::asio;
BOOST_AUTO_TEST_SUITE( async );
BOOST_AUTO_TEST_CASE(plain_async, *boost::unit_test::timeout(5))
{
asio::io_context ios;
@@ -83,3 +86,57 @@ BOOST_AUTO_TEST_CASE(multithreaded_async_pipe)
for (auto &t : threads)
t.join();
}
BOOST_AUTO_TEST_CASE(move_pipe)
{
asio::io_context ios;
bp::async_pipe ap{ios};
BOOST_TEST_CHECKPOINT("First move");
bp::async_pipe ap2{std::move(ap)};
BOOST_CHECK_EQUAL(ap.native_source(), ::boost::winapi::INVALID_HANDLE_VALUE_);
BOOST_CHECK_EQUAL(ap.native_sink (), ::boost::winapi::INVALID_HANDLE_VALUE_);
BOOST_TEST_CHECKPOINT("Second move");
ap = std::move(ap2);
{
BOOST_TEST_CHECKPOINT("Third move, from closed");
bp::async_pipe ap_inv{ios};
ap_inv.close();
ap = std::move(ap_inv);
}
{
BOOST_TEST_CHECKPOINT("Fourth move, from closed");
bp::async_pipe ap_inv{ios};
ap_inv.close();
const auto ap3 = std::move(ap_inv);
}
{
//copy an a closed pipe
BOOST_TEST_CHECKPOINT("Copy assign");
BOOST_TEST_CHECKPOINT("Fourth move, from closed");
bp::async_pipe ap_inv{ios};
ap_inv.close();
ap = ap_inv; //copy an invalid pipe
}
{
//copy an a closed pipe
BOOST_TEST_CHECKPOINT("Copy assign");
BOOST_TEST_CHECKPOINT("Fourth move, from closed");
bp::async_pipe ap_inv{ios};
ap_inv.close();
BOOST_TEST_CHECKPOINT("Copy construct");
bp::async_pipe ap4{ap_inv};
}
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -24,6 +24,7 @@
#include <array>
namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( async );
BOOST_AUTO_TEST_CASE(future, *boost::unit_test::timeout(15))
{
@@ -59,3 +60,5 @@ BOOST_AUTO_TEST_CASE(future_error, *boost::unit_test::timeout(15))
int exit_code = 0;
BOOST_CHECK_THROW(exit_code = fut.get(), boost::system::system_error);
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -15,13 +15,16 @@
#include <string>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/asio/yield.hpp>
#include <vector>
#include <array>
BOOST_AUTO_TEST_SUITE( async );
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15))
@@ -44,9 +47,12 @@ BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15))
BOOST_CHECK(did_something_else);
};
boost::asio::spawn(ios, stackful);
ios.post([&]{did_something_else = true;});
boost::asio::io_context::strand str{ios};
boost::asio::post(str, [&]{boost::asio::spawn(ios, stackful);});
boost::asio::post(str, [&]{did_something_else = true;});
ios.run();
BOOST_CHECK(did_something_else);
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -15,6 +15,7 @@
#include <string>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/use_future.hpp>
@@ -22,6 +23,7 @@
#include <vector>
#include <array>
BOOST_AUTO_TEST_SUITE( async );
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15))
@@ -45,7 +47,7 @@ BOOST_AUTO_TEST_CASE(stackful, *boost::unit_test::timeout(15))
};
boost::asio::spawn(ios, stackful);
ios.post([&]{did_something_else = true;});
boost::asio::post(ios.get_executor(), [&]{did_something_else = true;});
ios.run();
BOOST_CHECK(did_something_else);
@@ -71,7 +73,7 @@ BOOST_AUTO_TEST_CASE(stackful_except, *boost::unit_test::timeout(15))
};
boost::asio::spawn(ios, stackful);
ios.post([&]{did_something_else = true;});
boost::asio::post(ios.get_executor(), [&]{did_something_else = true;});
ios.run();
BOOST_CHECK(did_something_else);
@@ -100,8 +102,10 @@ BOOST_AUTO_TEST_CASE(stackful_error, *boost::unit_test::timeout(15))
};
boost::asio::spawn(ios, stackful);
ios.post([&]{did_something_else = true;});
boost::asio::post(ios.get_executor(), [&]{did_something_else = true;});
ios.run();
BOOST_CHECK(did_something_else);
}
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -15,6 +15,7 @@
#include <string>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/use_future.hpp>
@@ -22,6 +23,7 @@
#include <vector>
#include <array>
BOOST_AUTO_TEST_SUITE( async );
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(stackful_except, *boost::unit_test::timeout(15))
@@ -44,10 +46,10 @@ BOOST_AUTO_TEST_CASE(stackful_except, *boost::unit_test::timeout(15))
};
boost::asio::spawn(ios, stackful);
ios.post([&]{did_something_else = true;});
boost::asio::post(ios.get_executor(), [&]{did_something_else = true;});
ios.run();
BOOST_CHECK(did_something_else);
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -15,6 +15,7 @@
#include <string>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/use_future.hpp>
@@ -22,6 +23,7 @@
#include <vector>
#include <array>
BOOST_AUTO_TEST_SUITE( async );
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(stackless, *boost::unit_test::timeout(15))
@@ -57,10 +59,13 @@ BOOST_AUTO_TEST_CASE(stackless, *boost::unit_test::timeout(15))
}
} stackless{ios, did_something_else};
ios.post([&]{stackless();});
ios.post([&]{did_something_else = true;});
boost::asio::post(ios.get_executor(), [&]{stackless();});
boost::asio::post(ios.get_executor(), [&]{did_something_else = true;});
ios.run();
BOOST_CHECK(did_something_else);
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -39,6 +39,7 @@ typedef boost::asio::posix::stream_descriptor pipe_end;
namespace fs = boost::filesystem;
namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( bind_stderr );
BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(2))
{
@@ -150,3 +151,5 @@ BOOST_AUTO_TEST_CASE(file_io, *boost::unit_test::timeout(2))
boost::filesystem::remove(pth);
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -29,6 +29,7 @@
#include <boost/config.hpp>
BOOST_AUTO_TEST_SUITE( bind_stdin );
#if defined(BOOST_WINDOWS_API)
# include <windows.h>
@@ -255,3 +256,5 @@ BOOST_AUTO_TEST_CASE(file_io_C, *boost::unit_test::timeout(2))
c.wait();
boost::filesystem::remove(pth);
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -22,6 +22,7 @@
#include <iostream>
namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( bind_stdin_stdout );
BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(10))
{
@@ -53,3 +54,5 @@ BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(10))
BOOST_CHECK(c.wait_for(std::chrono::seconds(3)));
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -37,6 +37,9 @@ typedef boost::asio::windows::stream_handle pipe_end;
typedef boost::asio::posix::stream_descriptor pipe_end;
#endif
BOOST_AUTO_TEST_SUITE( bind_stdout );
namespace fs = boost::filesystem;
namespace bp = boost::process;
@@ -164,3 +167,5 @@ BOOST_AUTO_TEST_CASE(file_io, *boost::unit_test::timeout(2))
boost::filesystem::remove(pth);
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -35,6 +35,9 @@ typedef boost::asio::posix::stream_descriptor pipe_end;
namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( bind_stdout_stderr );
BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(2))
{
using boost::unit_test::framework::master_test_suite;
@@ -131,3 +134,5 @@ BOOST_AUTO_TEST_CASE(nul, *boost::unit_test::timeout(2))
BOOST_CHECK_EQUAL(EXIT_SUCCESS, exit_code);
#endif
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -25,7 +25,7 @@
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(closed)
BOOST_AUTO_TEST_CASE(close_stderr)
{
using boost::unit_test::framework::master_test_suite;

View File

@@ -24,7 +24,7 @@
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(closed)
BOOST_AUTO_TEST_CASE(close_stdin)
{
using boost::unit_test::framework::master_test_suite;

View File

@@ -24,7 +24,7 @@
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(closed)
BOOST_AUTO_TEST_CASE(close_stdout)
{
using boost::unit_test::framework::master_test_suite;

View File

@@ -8,7 +8,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_TEST_MAIN
#define BOOST_TEST_IGNORE_SIGCHLD
#include <boost/test/included/unit_test.hpp>
#include <boost/process/error.hpp>
@@ -72,11 +72,12 @@ BOOST_AUTO_TEST_CASE(sync_wait_abort)
struct wait_handler
{
HANDLE handle_;
wait_handler(HANDLE handle) : handle_(handle) {}
bool &called_;
wait_handler(HANDLE handle, bool &called) : handle_(handle), called_(called) {}
void operator()(const boost::system::error_code &ec)
{
called_ = true;
BOOST_REQUIRE(!ec);
DWORD exit_code;
BOOST_REQUIRE(GetExitCodeProcess(handle_, &exit_code));
@@ -86,8 +87,13 @@ struct wait_handler
#elif defined(BOOST_POSIX_API)
struct wait_handler
{
bool &called_;
wait_handler (bool & called) : called_(called) {}
void operator()(const boost::system::error_code &ec, int signal)
{
called_ = true;
BOOST_REQUIRE(!ec);
BOOST_REQUIRE_EQUAL(SIGCHLD, signal);
int status;
@@ -104,9 +110,14 @@ BOOST_AUTO_TEST_CASE(async_wait)
boost::asio::io_context io_context;
boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(3)};
timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
bool wh_called = false;
#if defined(BOOST_POSIX_API)
signal_set set(io_context, SIGCHLD);
set.async_wait(wait_handler());
set.async_wait(wait_handler(wh_called));
#endif
std::error_code ec;
@@ -118,10 +129,31 @@ BOOST_AUTO_TEST_CASE(async_wait)
BOOST_REQUIRE(!ec);
#if defined(BOOST_WINDOWS_API)
windows::object_handle handle(io_context, c.native_handle());
handle.async_wait(wait_handler(handle.native_handle()));
windows::object_handle handle(io_context.get_executor(), c.native_handle());
handle.async_wait(wait_handler(handle.native_handle(), wh_called));
#endif
std::cout << "async_wait 1" << std::endl;
io_context.run();
std::cout << "async_wait 2" << std::endl;
BOOST_CHECK_MESSAGE(wh_called, "Wait handler not called");
}
BOOST_AUTO_TEST_CASE(async_nowait)
{
// No need to call wait when passing an io_context
using boost::unit_test::framework::master_test_suite;
using namespace boost::asio;
std::error_code ec;
boost::asio::io_context io_context;
bp::child c(
master_test_suite().argv[1],
"test", "--exit-code", "221",
ec,
bp::on_exit=[](int exit_code, std::error_code) mutable {},
io_context
);
BOOST_REQUIRE(!ec);
io_context.run();
BOOST_CHECK_EQUAL(221, c.exit_code());
}

View File

@@ -28,14 +28,6 @@
#include <istream>
#include <iostream>
#include <cstdlib>
#if defined(BOOST_WINDOWS_API)
# include <windows.h>
typedef boost::asio::windows::stream_handle pipe_end;
#elif defined(BOOST_POSIX_API)
# include <sys/wait.h>
# include <unistd.h>
typedef boost::asio::posix::stream_descriptor pipe_end;
#endif
namespace bp = boost::process;

135
test/group_wait.cpp Normal file
View File

@@ -0,0 +1,135 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_TEST_MAIN
#define BOOST_TEST_IGNORE_SIGCHLD
#include <boost/test/included/unit_test.hpp>
#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/process/error.hpp>
#include <boost/process/io.hpp>
#include <boost/process/args.hpp>
#include <boost/process/child.hpp>
#include <boost/process/group.hpp>
#include <system_error>
#include <string>
#include <thread>
#include <istream>
#include <iostream>
#include <cstdlib>
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(wait_group_test, *boost::unit_test::timeout(5))
{
std::atomic<bool> done{false};
std::thread thr{
[&]
{
for (int i = 0; i < 50 && !done.load(); i++)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
BOOST_REQUIRE(done.load());
}};
using boost::unit_test::framework::master_test_suite;
std::error_code ec;
bp::group g;
bp::child c1(
master_test_suite().argv[1],
"--wait", "2",
g,
ec
);
bp::child c2(
master_test_suite().argv[1],
"--wait", "2",
g,
ec
);
BOOST_CHECK(c1.running());
BOOST_CHECK(c2.running());
BOOST_REQUIRE(!ec);
BOOST_REQUIRE(c1.in_group(ec));
BOOST_CHECK_MESSAGE(!ec, ec.message());
BOOST_REQUIRE(c2.in_group(ec));
BOOST_CHECK_MESSAGE(!ec, ec.message());
g.wait();
BOOST_CHECK(!c1.running());
BOOST_CHECK(!c2.running());
done.store(true);
thr.join();
}
BOOST_AUTO_TEST_CASE(wait_group_test_timeout, *boost::unit_test::timeout(15))
{
using boost::unit_test::framework::master_test_suite;
std::atomic<bool> done{false};
std::thread thr{
[&]
{
for (int i = 0; i < 150 && !done.load(); i++)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
BOOST_REQUIRE(done.load());
}};
std::error_code ec;
bp::group g;
bp::child c1(
master_test_suite().argv[1],
"--wait", "1",
g,
ec
);
bp::child c2(
master_test_suite().argv[1],
"--wait", "3",
g,
ec
);
BOOST_CHECK(c1.running());
BOOST_CHECK(c2.running());
BOOST_REQUIRE(!ec);
BOOST_REQUIRE(c1.in_group());
BOOST_REQUIRE(c2.in_group());
BOOST_CHECK(!g.wait_for(std::chrono::seconds(2), ec));
BOOST_CHECK_MESSAGE(!ec, std::to_string(ec.value()) + " == " + ec.message());
BOOST_CHECK(!c1.running());
BOOST_CHECK(c2.running());
BOOST_CHECK(g.wait_for(std::chrono::seconds(5), ec));
BOOST_CHECK_MESSAGE(!ec, std::to_string(ec.value()) + " == " + ec.message());
BOOST_CHECK(!c1.running());
BOOST_CHECK(!c2.running());
done.store(true);
thr.join();
}

View File

@@ -3,5 +3,8 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/system/api_config.hpp>
#if defined(BOOST_WINDOWS_API)
#define BOOST_NO_ANSI_APIS 1
#endif
#include <boost/process.hpp>

View File

@@ -11,10 +11,14 @@
#include <thread>
#include <boost/process/pipe.hpp>
#include <boost/process/environment.hpp>
using namespace std;
namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( pipe_tests );
BOOST_AUTO_TEST_CASE(plain, *boost::unit_test::timeout(2))
{
bp::pipe pipe;
@@ -35,7 +39,8 @@ BOOST_AUTO_TEST_CASE(named, *boost::unit_test::timeout(2))
#if defined( BOOST_WINDOWS_API )
bp::pipe pipe("\\\\.\\pipe\\pipe_name");
#elif defined( BOOST_POSIX_API )
bp::pipe pipe("./test_pipe");
const auto home_path = boost::this_process::environment()["HOME"].to_string();
bp::pipe pipe(home_path + "/.boost_process_test_pipe");
#endif
std::string in = "xyz";
@@ -230,3 +235,4 @@ BOOST_AUTO_TEST_CASE(coverage, *boost::unit_test::timeout(5))
}
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -27,6 +27,7 @@
#include <iostream>
#include <cstdlib>
BOOST_AUTO_TEST_SUITE( pipe_tests );
namespace bp = boost::process;
@@ -50,6 +51,8 @@ BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(5))
);
BOOST_REQUIRE(!ec);
BOOST_TEST_INFO("Launching child 2");
bp::child c2(
master_test_suite().argv[1],
bp::args={"test", "--prefix-once", "hello "},
@@ -74,3 +77,4 @@ BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(5))
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -14,6 +14,8 @@
#include <boost/process.hpp>
#include <boost/process/posix.hpp>
#include <boost/filesystem.hpp>
#include <system_error>
@@ -21,6 +23,7 @@
#include <sys/wait.h>
#include <errno.h>
namespace fs = boost::filesystem;
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(bind_fd, *boost::unit_test::timeout(2))
@@ -99,3 +102,67 @@ BOOST_AUTO_TEST_CASE(execve_throw_on_error, *boost::unit_test::timeout(2))
BOOST_CHECK_EQUAL(e.code().value(), ENOENT);
}
}
BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5))
{
using boost::unit_test::framework::master_test_suite;
std::error_code ec;
const auto pid = boost::this_process::get_id();
const auto fd_path = fs::path("/proc") / std::to_string(pid) / "fd";
auto get_fds = [&]{
std::vector<int> fds;
for (auto && fd : fs::directory_iterator(fd_path))
fds.push_back(std::stoi(fd.path().filename().string()));
return fds;
};
std::vector<int> fd_list = get_fds();
if (fd_list.empty()) //then there's no /proc in the current linux distribution.
return;
BOOST_CHECK(std::find(fd_list.begin(), fd_list.end(), STDOUT_FILENO) != fd_list.end());
BOOST_CHECK(std::find(fd_list.begin(), fd_list.end(), STDIN_FILENO) != fd_list.end());
BOOST_CHECK(std::find(fd_list.begin(), fd_list.end(), STDERR_FILENO) != fd_list.end());
bp::pipe p; //should add two descriptors.
auto fd_list_new = get_fds();
BOOST_CHECK_EQUAL(fd_list_new.size(), fd_list.size() + 2);
fd_list.push_back(p.native_source());
fd_list.push_back(p.native_sink());
BOOST_CHECK_EQUAL(
bp::system(
master_test_suite().argv[1],
"test", "--exit-code", "123", ec), 123);
fd_list_new = get_fds();
BOOST_CHECK_EQUAL(fd_list.size(), fd_list_new.size());
const int native_source = p.native_source();
BOOST_CHECK_EQUAL(
bp::system(
master_test_suite().argv[1],
bp::std_in < p,
"test", "--exit-code", "123", ec), 123);
BOOST_CHECK(!ec);
////now, p.source should be closed, so we remove it from fd_list
const auto itr = std::find(fd_list.begin(), fd_list.end(), native_source);
if (itr != fd_list.end())
fd_list.erase(itr);
fd_list_new = get_fds();
BOOST_CHECK_EQUAL(fd_list.size(), fd_list_new.size());
}

View File

@@ -41,7 +41,7 @@ typedef boost::asio::posix::stream_descriptor pipe_end;
namespace fs = boost::filesystem;
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(sync_io, *boost::unit_test::timeout(5))
BOOST_AUTO_TEST_CASE(sync_spawn, *boost::unit_test::timeout(5))
{
using boost::unit_test::framework::master_test_suite;
@@ -83,7 +83,7 @@ struct read_handler
}
};
BOOST_AUTO_TEST_CASE(async_io, *boost::unit_test::timeout(2))
BOOST_AUTO_TEST_CASE(async_spawn, *boost::unit_test::timeout(2))
{
using boost::unit_test::framework::master_test_suite;

View File

@@ -46,7 +46,7 @@ typedef boost::asio::posix::stream_descriptor pipe_end;
namespace fs = boost::filesystem;
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(exit_code, *boost::unit_test::timeout(5))
BOOST_AUTO_TEST_CASE(system_exit_code, *boost::unit_test::timeout(5))
{
using boost::unit_test::framework::master_test_suite;
@@ -67,15 +67,15 @@ BOOST_AUTO_TEST_CASE(implicit_async_io, *boost::unit_test::timeout(2))
std::future<std::string> fut;
std::error_code ec;
bp::system(
int res = bp::system(
master_test_suite().argv[1],
"test", "--echo-stdout", "abc",
bp::std_out > fut,
ec
);
BOOST_REQUIRE(!ec);
BOOST_REQUIRE(fut.valid());
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK(boost::starts_with(
fut.get(), "abc"));
}

View File

@@ -70,17 +70,19 @@ BOOST_AUTO_TEST_CASE(explicit_async_io_running, *boost::unit_test::timeout(10))
std::future<std::string> fut;
std::error_code ec;
ios.post([&]
{
bp::system(
master_test_suite().argv[1],
"test", "--echo-stdout", "abc",
bp::std_out > fut,
ios,
ec
);
BOOST_REQUIRE(!ec);
});
boost::asio::post(
ios.get_executor(),
[&] {
bp::system(
master_test_suite().argv[1],
"test", "--echo-stdout", "abc",
bp::std_out > fut,
ios,
ec
);
BOOST_REQUIRE(!ec);
}
);
ios.run();

View File

@@ -22,8 +22,17 @@
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(terminate_set_on_error)
BOOST_AUTO_TEST_CASE(terminate_set_on_error, *boost::unit_test::timeout(5))
{
std::atomic<bool> done{false};
std::thread thr{
[&]
{
for (int i = 0; i < 50 && !done.load(); i++)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
BOOST_REQUIRE(done.load());
}};
using boost::unit_test::framework::master_test_suite;
std::error_code ec;
bp::child c(
@@ -44,10 +53,22 @@ BOOST_AUTO_TEST_CASE(terminate_set_on_error)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
BOOST_CHECK(!c.running(ec));
BOOST_CHECK(!ec);
done.store(true);
thr.join();
}
BOOST_AUTO_TEST_CASE(terminate_throw_on_error)
BOOST_AUTO_TEST_CASE(terminate_throw_on_error, *boost::unit_test::timeout(5))
{
std::atomic<bool> done{false};
std::thread thr{
[&]
{
for (int i = 0; i < 50 && !done.load(); i++)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
BOOST_REQUIRE(done.load());
}};
using boost::unit_test::framework::master_test_suite;
std::error_code ec;
@@ -68,4 +89,7 @@ BOOST_AUTO_TEST_CASE(terminate_throw_on_error)
c.terminate();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
BOOST_CHECK(!c.running());
done.store(true);
thr.join();
}

View File

@@ -8,7 +8,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_TEST_MAIN
#define BOOST_TEST_IGNORE_SIGCHLD
#include <boost/test/included/unit_test.hpp>
#include <boost/process/error.hpp>
#include <boost/process/child.hpp>
@@ -24,6 +24,9 @@
namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( wait_test );
BOOST_AUTO_TEST_CASE(sync_wait, *boost::unit_test::timeout(2))
{
using boost::unit_test::framework::master_test_suite;
@@ -40,7 +43,7 @@ BOOST_AUTO_TEST_CASE(sync_wait, *boost::unit_test::timeout(2))
}
BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(2))
BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(4))
{
using boost::unit_test::framework::master_test_suite;
using namespace boost::asio;
@@ -50,6 +53,10 @@ BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(2))
std::error_code ec;
bool called = false;
boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(3)};
timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
bp::child c(
master_test_suite().argv[1],
bp::args+={"test", "--wait", "1"},
@@ -64,3 +71,5 @@ BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(2))
BOOST_CHECK(called);
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -8,7 +8,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_TEST_MAIN
#define BOOST_TEST_IGNORE_SIGCHLD
//#define BOOST_TEST_IGNORE_SIGCHLD
#include <boost/test/included/unit_test.hpp>
#include <boost/process/error.hpp>
#include <boost/process/child.hpp>
@@ -22,12 +22,15 @@
#endif
namespace bp = boost::process;
BOOST_AUTO_TEST_SUITE( wait_test);
BOOST_AUTO_TEST_CASE(wait_for)
{
using boost::unit_test::framework::master_test_suite;
std::error_code ec;
auto launch_time = std::chrono::system_clock::now();
bp::child c(
master_test_suite().argv[1],
bp::args+={"test", "--wait", "1"},
@@ -35,8 +38,13 @@ BOOST_AUTO_TEST_CASE(wait_for)
);
BOOST_REQUIRE(!ec);
BOOST_CHECK(!c.wait_for(std::chrono::milliseconds(200)));
BOOST_CHECK( c.wait_for(std::chrono::milliseconds(1000)));
auto timeout_t = std::chrono::system_clock::now();
BOOST_CHECK_LE(std::chrono::duration_cast<std::chrono::seconds>(timeout_t - launch_time).count(), 5); //should be less
}
BOOST_AUTO_TEST_CASE(wait_for_ec)
@@ -101,4 +109,6 @@ BOOST_AUTO_TEST_CASE(wait_until_ec)
BOOST_CHECK( c.wait_until(t2, ec));
BOOST_CHECK_MESSAGE(!ec, ec.message());
}
}
BOOST_AUTO_TEST_SUITE_END();

View File

@@ -24,7 +24,7 @@
namespace bp = boost::process;
BOOST_AUTO_TEST_CASE(args, *boost::unit_test::timeout(2))
BOOST_AUTO_TEST_CASE(wargs, *boost::unit_test::timeout(2))
{
using boost::unit_test::framework::master_test_suite;
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(args, *boost::unit_test::timeout(2))
}
BOOST_AUTO_TEST_CASE(cmd, *boost::unit_test::timeout(2))
BOOST_AUTO_TEST_CASE(wcmd, *boost::unit_test::timeout(2))
{
using boost::unit_test::framework::master_test_suite;