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

Compare commits

...

447 Commits

Author SHA1 Message Date
Klemens David Morgenstern
0a554c92b5 Merge branch 'develop' of github.com:boostorg/process into develop 2019-05-18 11:11:20 +07:00
Klemens Morgenstern
fa81cecffc Merge pull request #196 from klemens-morgenstern/limit_fd
Limit fd
2019-05-18 11:07:55 +07:00
Klemens David Morgenstern
977b76f6aa Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2019-05-15 12:31:16 +07:00
Klemens Morgenstern
fc1acb82d9 Merge pull request #199 from klemens-morgenstern/stream_close
added opstream::close, closes klemens-morgenstern/boost-process#198
2019-05-14 22:04:21 +07:00
Klemens David Morgenstern
db7af9f87d doc addition 2019-05-14 13:22:05 +07:00
Klemens Morgenstern
a350cc346b Merge pull request #203 from klemens-morgenstern/win_pipe_unlimited_instances
Closes boostorg/process#84 and boostorg/process#83
2019-05-14 12:41:29 +07:00
Klemens David Morgenstern
9fa86d3d65 removed call to 'close_sink' 2019-05-14 12:15:57 +07:00
Klemens David Morgenstern
e426f2bfac remove ill-formed test & minor fixes 2019-05-14 11:57:20 +07:00
Klemens David Morgenstern
6b173117aa Merge branch 'develop' into stream_close 2019-05-14 10:45:53 +07:00
Klemens David Morgenstern
ecbc93408f Merge branch 'develop' into win_pipe_unlimited_instances 2019-05-14 10:45:16 +07:00
Klemens David Morgenstern
6ba9a48d15 Merge branch 'develop' into new_wait_for_test 2019-05-14 10:44:40 +07:00
Klemens David Morgenstern
519c0a636a Merge branch 'develop' into limit_fd 2019-05-14 10:44:08 +07:00
Klemens David Morgenstern
82195c61af Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop
# Conflicts:
#	include/boost/process/detail/posix/wait_group.hpp
2019-05-14 00:41:41 +07:00
Klemens David Morgenstern
c604e3a20e switched to a wait/sleep version for OSX - should work fine for groups 2019-05-14 00:36:24 +07:00
Klemens Morgenstern
b27d0170ba Typo fix 2019-05-13 23:50:31 +07:00
Klemens David Morgenstern
98fd4eecf0 small reordering of code 2019-05-13 20:43:03 +07:00
Klemens David Morgenstern
3799315ce7 reverted to pipes for OSX 2019-05-13 20:11:17 +07:00
Klemens David Morgenstern
b9431ba492 fixing signal workaround 2019-05-13 10:30:28 +07:00
Klemens David Morgenstern
c0dca35615 added wrongfully removed build script options 2019-05-13 00:28:10 +07:00
Klemens David Morgenstern
790d79db9c Merge branch 'develop' into limit_fd 2019-05-13 00:23:52 +07:00
Klemens David Morgenstern
5de0a795d1 fixed wait_for_exit 2019-05-13 00:22:46 +07:00
Klemens David Morgenstern
cbaa913e3d Merge branch 'develop' into limit_fd
# Conflicts:
#	include/boost/process/detail/posix/pipe_out.hpp
#	test/Jamfile.jam
2019-05-12 17:43:40 +07:00
Klemens David Morgenstern
5786162fb5 Merge branch 'develop' into new_wait_for_test 2019-05-12 17:42:08 +07:00
Klemens David Morgenstern
78c44dd560 Merge branch 'develop' into win_pipe_unlimited_instances 2019-05-12 17:40:54 +07:00
Klemens David Morgenstern
23ff67d83d added space for pipe close test 2019-05-12 17:37:35 +07:00
Klemens David Morgenstern
476c6ccd95 Merge branch 'develop' into stream_close 2019-05-12 17:13:36 +07:00
Klemens David Morgenstern
28126b3432 osx fix 2019-05-12 17:02:25 +07:00
Klemens David Morgenstern
ed8388d091 actual fix 2019-05-12 16:55:45 +07:00
Klemens David Morgenstern
43c402a5da test logic fix 2019-05-12 16:53:54 +07:00
Klemens David Morgenstern
9ff2f6f3ef still trying for circleci 2019-05-10 16:56:11 +07:00
Klemens David Morgenstern
b2a0fadaca Merge branch 'develop' into new_wait_for_test
# Conflicts:
#	.travis.yml
2019-05-10 16:38:23 +07:00
Klemens David Morgenstern
3c4057204e hopefully fixed wait_for for osx 2019-05-10 16:34:51 +07:00
Klemens David Morgenstern
717ac47510 further investigation of circlci error 2019-05-10 12:21:37 +07:00
Klemens David Morgenstern
4f6f4eb391 updated for circle 2019-05-10 12:00:43 +07:00
Klemens David Morgenstern
99e04036c7 removed report-ci from circle-ci 2019-05-10 00:37:00 +07:00
Klemens David Morgenstern
519e339365 added more checks 2019-05-09 23:05:09 +07:00
Klemens David Morgenstern
d2c930470f removed && false 2019-05-09 17:08:58 +07:00
Klemens David Morgenstern
d5709ae747 trying to fix wait_for 2019-05-09 16:35:58 +07:00
Klemens David Morgenstern
d2ab81b1b9 Merge branch 'develop' into new_wait_for_test
# Conflicts:
#	include/boost/process/detail/posix/wait_for_exit.hpp
#	include/boost/process/detail/posix/wait_group.hpp
2019-05-09 12:20:20 +07:00
Klemens David Morgenstern
885557fe01 still trying to make wait_for work 2019-05-09 12:19:26 +07:00
Klemens David Morgenstern
b5b758f89a Merge branch 'develop' into stream_close 2019-05-09 11:29:31 +07:00
Klemens David Morgenstern
2a954eb809 Merge branch 'develop' into win_pipe_unlimited_instances 2019-05-09 11:24:14 +07:00
Klemens David Morgenstern
0edff5449a Merge branch 'develop' into new_wait_for_test
# Conflicts:
#	include/boost/process/detail/posix/wait_for_exit.hpp
2019-05-08 16:53:45 +07:00
Klemens David Morgenstern
417ea77f2f changed SIGTERM to SIGKILL 2019-05-08 16:50:49 +07:00
Klemens David Morgenstern
9e3fdc9669 SIGSEV fix 2019-05-08 16:44:38 +07:00
Klemens David Morgenstern
66c2867371 removed travis token 2019-05-08 16:30:39 +07:00
Klemens David Morgenstern
caa7b2fcc8 two minor fixes 2019-05-08 16:28:54 +07:00
Klemens David Morgenstern
6263e74bcd Merge branch 'develop' into limit_fd 2019-05-07 12:16:53 +07:00
Klemens David Morgenstern
faae08ee64 replaced 1 with ::boost::winapi::HANDLE_FLAG_INHERIT_ 2019-05-07 12:16:32 +07:00
Klemens David Morgenstern
2314e19f12 restructured osx wait
Check if it solves klemens-morgenstern/boost-process#200
2019-05-07 12:01:04 +07:00
Klemens David Morgenstern
cfd0fc055c fixed overflow func 2019-05-07 11:48:16 +07:00
Klemens David Morgenstern
849b5d0f30 Closes boostorg/process#84 and boostorg/process#83 2019-05-07 10:59:50 +07:00
Klemens Morgenstern
d13df2a194 Merge pull request #82 from Parean/develop
should close klemens-morgenstern/boost-process#201
2019-05-03 21:07:53 +07:00
Denis Smirnov
86fc3b0b4d should close klemens-morgenstern/boost-process#201 2019-05-03 19:07:17 +07:00
Klemens David Morgenstern
4733ca719f typo fix 2019-04-25 22:40:13 +07:00
Klemens David Morgenstern
296f12eb64 RAII issues & resetting flags on windwos handles 2019-04-25 22:36:30 +07:00
Klemens David Morgenstern
96d3470e37 added this-> before clear() 2019-04-25 22:06:23 +07:00
Klemens David Morgenstern
2265c98d81 added missing ; 2019-04-25 20:24:42 +07:00
Klemens David Morgenstern
060e5c2526 fixed name lookup 2019-04-25 15:15:29 +07:00
Klemens David Morgenstern
b4894807f1 added opstream::close, closes klemens-morgenstern/boost-process#198 2019-04-24 18:24:44 +07:00
Klemens David Morgenstern
2aa5e1461c Merge branch 'develop' into new_wait_for_test
# Conflicts:
#	test/Jamfile.jam
2019-04-20 16:41:31 +08:00
Klemens Morgenstern
61fa15fa48 Merge pull request #197 from toonetown/fix-wait_for-fork-macOS
Use SIGTERM instead of `-15`.
2019-04-20 15:39:54 +07:00
Nathan Toone
92508e06a1 Use SIGTERM instead of -15. 2019-04-19 23:44:54 -06:00
Klemens David Morgenstern
e85f0d0816 Closes klemens-morgenstern/boost-process#139 2019-04-10 12:18:02 +08:00
Klemens David Morgenstern
5e90c8de9b fixed up tests 2019-04-10 10:09:32 +08:00
Klemens David Morgenstern
a486a25a07 appveyor minor fix, pipe_out naming fix & limit_fd small sanity check because of weird osx bug 2019-04-10 01:33:21 +08:00
Klemens David Morgenstern
f8c0dd4da5 prototype for limit_fd 2019-04-09 23:39:43 +08:00
Klemens David Morgenstern
ee6870bfbc added used_handles & limit_fd for windows 2019-04-09 19:16:55 +08:00
Klemens David Morgenstern
0422b6bfb8 added posix get_handle function 2019-04-09 15:40:26 +08:00
Klemens David Morgenstern
7fc41b2815 added windows handles functionality 2019-04-09 14:31:50 +08:00
Klemens David Morgenstern
a49f1f6e2d Started on limit-fd functionality 2019-04-08 11:11:55 +08:00
Klemens David Morgenstern
af54484bc2 sed typo fix 2019-04-07 21:40:28 +08:00
Klemens David Morgenstern
ebcb30e4bd reduced amount of threads for build 2019-04-07 13:31:46 +08:00
Klemens David Morgenstern
5371c9813b typo fix 2019-04-07 13:07:11 +08:00
Klemens David Morgenstern
9a833c610d trying to fix the exit code 2019-04-07 12:53:02 +08:00
Klemens David Morgenstern
c99ebfee7a flipping typos 2019-04-07 12:34:37 +08:00
Klemens David Morgenstern
34861366e0 added sed for annotations 2019-04-07 12:19:17 +08:00
Klemens David Morgenstern
e6722c452c faulty log name fix (attempt) 2019-04-07 11:47:18 +08:00
Klemens David Morgenstern
b1e38842fb renamed the no-valgrind log 2019-04-07 03:15:38 +08:00
Klemens David Morgenstern
bcc9826e67 still doing the ci thing here 2019-04-07 03:09:17 +08:00
Klemens David Morgenstern
b6c6753b87 added valgrind to circle Ci 2019-04-07 02:57:14 +08:00
Klemens David Morgenstern
0d008a88fc dammit circle 2019-04-07 02:49:14 +08:00
Klemens David Morgenstern
f92ec53968 circle ci example job fix 2019-04-07 02:36:14 +08:00
Klemens David Morgenstern
00a87d0a67 report-ci update for circleci 2019-04-07 02:29:52 +08:00
Klemens David Morgenstern
462334639c typo fix 2019-04-07 02:08:31 +08:00
Klemens David Morgenstern
7129182044 ci fixes - the similtaneous wait doen't work on osx 2019-04-07 02:03:08 +08:00
Klemens David Morgenstern
03fbed44ad typo fix 2019-04-07 01:23:10 +08:00
Klemens David Morgenstern
0277c4fcec CI fixes 2019-04-07 01:19:19 +08:00
Klemens David Morgenstern
4bc1ae6ff8 added async fix & fixed dangling develop workaroudn for async_pipe copy 2019-04-07 00:21:27 +08:00
Klemens David Morgenstern
266c4503aa Merge branch 'develop' into asio_no_deprecated 2019-04-06 23:58:47 +08:00
Klemens David Morgenstern
80479b6b70 removed errornous global variable 2019-04-06 23:58:27 +08:00
Klemens David Morgenstern
823a346a08 added another exit_code test 2019-04-06 23:53:11 +08:00
Klemens David Morgenstern
8f3a7b9c63 Merge branch 'develop' into asio_no_deprecated 2019-04-06 22:35:45 +08:00
Klemens David Morgenstern
2ebcc07892 Merge branch 'circleci' into develop 2019-04-06 22:33:22 +08:00
Klemens Morgenstern
a673cd9643 Update config.yml 2019-04-06 22:25:52 +08:00
Klemens Morgenstern
12971db132 Update config.yml 2019-04-06 22:19:11 +08:00
Klemens Morgenstern
94be279992 Update config.yml 2019-04-06 22:15:38 +08:00
Klemens David Morgenstern
12cded5995 switched test to strand 2019-04-06 22:15:12 +08:00
Klemens David Morgenstern
0c16a0e5b3 set params back to support report.ci 2019-04-06 22:11:04 +08:00
Klemens Morgenstern
e4a6fde7b9 Update config.yml 2019-04-06 18:28:40 +08:00
Klemens David Morgenstern
92d2bebaaf added test and fixed #189 and #157 as well as #93 2019-04-06 18:25:08 +08:00
Klemens David Morgenstern
7e7a8cbc1d fixed #194 2019-04-06 17:29:52 +08:00
Klemens Morgenstern
4f767f4bfe Update config.yml 2019-04-06 17:25:03 +08:00
Klemens Morgenstern
63f714ae2f Update config.yml 2019-04-06 16:54:07 +08:00
Klemens Morgenstern
1b3b9b707c Update config.yml 2019-04-06 16:41:44 +08:00
Klemens Morgenstern
f64bc8a6d4 Update config.yml 2019-04-06 16:34:26 +08:00
Klemens Morgenstern
102834130d Update config.yml 2019-04-06 16:28:48 +08:00
Klemens Morgenstern
fdc6a11cbc Update config.yml 2019-04-06 16:09:16 +08:00
Klemens Morgenstern
19b20f55ce Update config.yml 2019-04-06 16:04:28 +08:00
Klemens David Morgenstern
60d072ce46 Merge branch 'develop' into circleci 2019-04-06 15:29:22 +08:00
Klemens David Morgenstern
34f05b9276 Merge branch 'develop' into asio_no_deprecated 2019-04-06 15:22:10 +08:00
Klemens David Morgenstern
1b476b0430 Closes #65 2019-04-06 15:21:52 +08:00
Klemens David Morgenstern
b294710e60 fixed self-pipe issue 2019-04-06 14:42:08 +08:00
Klemens David Morgenstern
f8cd325d1b trying circleci 2019-04-05 15:13:14 +08:00
Klemens David Morgenstern
2a6c23e173 typo fix 2019-04-04 18:11:33 +08:00
Klemens David Morgenstern
d7768b7221 Merge branch 'develop' into asio_no_deprecated 2019-04-04 17:57:28 +08:00
Klemens David Morgenstern
b8821eac57 should close #78 2019-03-30 23:14:25 +08:00
Klemens David Morgenstern
d20b64cf37 removed unnecessary int to remove warning 2019-03-29 01:39:00 +08:00
Klemens David Morgenstern
f0ddd6ca29 typo & structure fix 2019-03-29 00:57:11 +08:00
Klemens David Morgenstern
574d9e09d6 should close #193 2019-03-29 00:32:12 +08:00
Klemens Morgenstern
7085a50f36 Merge pull request #77 from SimonEbner/develop
Fix leaking pipe
2019-03-23 00:01:27 +08:00
Klemens Morgenstern
0485459da2 Merge pull request #76 from orgads/patch-1
Fix signed/unsigned comparison
2019-03-22 23:56:13 +08:00
Simon Ebner
318439af2e Fix Issue 62
Fixes a leaking pipe. See https://github.com/boostorg/process/issues/62
2019-03-22 15:27:35 +01:00
Orgad Shaneh
4d52ff362f Fix signed/unsigned comparison 2019-03-21 23:39:27 +02:00
Klemens David Morgenstern
8d48d9cbfa dumb workaround -> fix report.ci detection! 2019-03-21 16:21:40 +08:00
Klemens David Morgenstern
f25c31c847 added test by @grives as recommended in #69 2019-03-21 12:51:32 +08:00
Klemens David Morgenstern
3eacae5e38 Merge branch 'develop' 2019-03-04 12:16:07 +08:00
Klemens David Morgenstern
14b294c10c Merge branch 'develop' of github.com:boostorg/process into develop 2019-03-04 12:14:56 +08:00
Klemens Morgenstern
881da4f9e2 Merge pull request #191 from klemens-morgenstern/develop
Update master
2019-02-28 12:44:50 +08:00
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 David Morgenstern
6abce365c5 started on asio_no_deprecated.cpp 2018-03-11 20:57:18 +01:00
Klemens Morgenstern
4fc4784506 Merge pull request #34 from Lastique/update_winapi_cc
Switch WINAPI calling convention macros to the replacements from Boost.WinAPI
2018-03-11 20:56:06 +01:00
Andrey Semashev
900aab5d6d Switched WINAPI calling convention macros to the replacements from Boost.WinAPI
WINAPI macro definition in Boost.WinAPI is deprecated as it may clash with
the macro defined in Windows SDK.
2018-03-11 20:20:49 +03:00
Klemens Morgenstern
f61a61cf59 Merge pull request #144 from klemens-morgenstern/develop
Another master updates
2018-02-26 23:25:28 +01:00
Klemens Morgenstern
8e8d36772e Merge pull request #151 from amerry/is-running-fixes
is_running fixes
2018-02-26 13:53:41 +01:00
Alex Merry
ec04919825 Rename tests to reflect what they do 2018-02-22 14:32:54 +00:00
Alex Merry
6625999765 Check the "still running" status code does not clash with WIFSIGNALED
This makes the static_assert reflect the actual assumptions in the code.
2018-02-22 14:31:22 +00:00
Alex Merry
0d3688aca5 Ignore stopped processes
is_running should only concern itself with terminated processes, not
stopped processes (which might be continued later).
2018-02-22 14:12:46 +00:00
Klemens Morgenstern
40be786c43 Merge pull request #150 from amerry/async-exit-status
Return the same exit status in the async handler as the sync method
2018-02-22 13:43:06 +01:00
Klemens Morgenstern
d4a0444223 Merge pull request #147 from amerry/args
Always set arguments on POSIX
2018-02-22 13:05:33 +01:00
Klemens Morgenstern
f99cfe77f4 Merge pull request #148 from pepsiman/patch-1
Fix grammar in tutorial
2018-02-22 12:59:52 +01:00
Alex Merry
ed32531369 Return the same exit status in the async handler as the sync method
Previously, if the process terminated via a signal on posix, the async
handler would provide an exit status of 0.
2018-02-22 11:53:42 +00:00
Malcolm Parsons
751af041cd Fix grammar in tutorial 2018-02-22 10:29:59 +00:00
Alex Merry
a0ceebd59f Fix copyright headers
Insofar as there are copyrights on these changes, they are owned by my
employer, as I'm doing this on company time.
2018-02-22 09:02:02 +00:00
Klemens Morgenstern
b0b37f2ce6 Merge pull request #146 from amerry/test-for-sigchld-fix
Add unit tests for async exit watching with multiple io_contexts
2018-02-21 17:50:27 +01:00
Alex Merry
cf1f904ae2 Fix compilation on MSVC 2018-02-21 15:53:46 +00:00
Alex Merry
8aaf53d76d Always set arguments on POSIX
Explicitly specifying an executable (either with boost::filesystem::path
or boost::process::exe) and no arguments causes NULL to be passed as the
argument list.

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

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

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

Reassigning async_pipes previously raised exceptions complaining about
EBADF or EEXIST. I think the ::close calls in the destructor and the
move assignment were not closing the pipe correctly.
2017-11-04 17:22:15 -07:00
klemens-morgenstern
6e60928b1f Merge branch 'develop' of github.com:boostorg/process into develop 2017-11-03 00:14:23 +01:00
Klemens Morgenstern
e27baa7628 Merge pull request #24 from ca-l-eb/fix-terminate
Fix move assignment for child_decl
2017-11-02 19:13:17 -04:00
Caleb Dechant
337a6e3e83 Fix move assignment for child
_terminate field is now copied from the move assingment operator on
child. This fixes the issue that a child process could previously only
be terminated() once (even after reassignment).
2017-11-02 16:03:05 -07:00
klemens-morgenstern
bbfc334c93 split up the async_system test 2017-10-28 13:04:01 +02:00
klemens-morgenstern
1a9fa2cc2c Merge branch 'develop' 2017-10-28 12:09:36 +02:00
klemens-morgenstern
1296e02372 Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2017-10-25 18:49:13 +02:00
klemens-morgenstern
585104605e removed variadic arg in test 2017-10-25 18:48:55 +02:00
Klemens Morgenstern
d0c07b7c63 Update windows_specific.cpp 2017-10-25 12:20:00 +02:00
Klemens Morgenstern
7c9ce7f8b9 Update exit_code.cpp 2017-10-25 10:55:40 +02:00
Klemens Morgenstern
c388f24d6e Update windows_specific.cpp 2017-10-25 10:53:46 +02:00
klemens-morgenstern
b1f50e953b some additions attempted fixes for the windows part 2017-10-25 09:07:23 +02:00
klemens-morgenstern
852d8f3d9d renamed windows/io_service_ref.hpp 2017-10-24 23:54:58 +02:00
klemens-morgenstern
2c026e43a8 removed constness for gcc 4.8 2017-10-24 23:17:42 +02:00
klemens-morgenstern
51396227a0 renamed native() to native_handle() 2017-10-24 23:15:53 +02:00
klemens-morgenstern
75d3049199 Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2017-10-24 22:36:48 +02:00
Klemens Morgenstern
3d9a8b2353 Merge pull request #22 from Lastique/update_winapi
Update Boost.WinAPI usage to the new location and namespace
2017-10-24 16:35:40 -04:00
Klemens Morgenstern
8097c2e07a Merge pull request #19 from chriskohlhoff/asio-updates-1
Updates to compile against latest asio.
2017-10-24 16:34:06 -04:00
Andrey Semashev
d9231d466c Updated Boost.WinAPI usage to the new location and namespace. 2017-10-24 23:27:56 +03:00
Christopher Kohlhoff
153e05eac0 Updates to compile against latest asio. 2017-10-23 21:23:44 +11:00
Klemens Morgenstern
883b6ac937 Merge pull request #15 from ganboing/develop
fix uninitialized variable and close(-1) behavior
2017-10-22 15:41:53 -04:00
Klemens Morgenstern
764fff1f65 Merge pull request #17 from gevorgvoskanyan/search_path_unused_var
remove unused variable in boost::process::detail::posix::search_path()
2017-10-22 15:35:58 -04:00
Klemens Morgenstern
16ff42290a Merge pull request #16 from gevorgvoskanyan/doc_typos
Some typo fixes
2017-10-22 15:35:43 -04:00
Gevorg Voskanyan
6adf1bf545 fix param path comment for search_path() 2017-10-22 23:20:02 +04:00
Gevorg Voskanyan
126659f2f9 remove unused variable in boost::process::detail::posix::search_path() 2017-10-22 22:50:45 +04:00
Gevorg Voskanyan
90adf118ac s/a environment/an environment 2017-10-22 22:30:24 +04:00
Gevorg Voskanyan
63952fa2a6 s/seperated/separated 2017-10-22 22:20:27 +04:00
Bo Gan
2f00162817 fix uninitialized variable and close(-1) behavior 2017-09-12 12:37:20 -07:00
Klemens Morgenstern
28b402eed1 Merge pull request #120 from klemens-morgenstern/vfork-check-fix
Updated vfork check
2017-08-29 13:22:32 -04:00
Egor Pugin
3f12d82e00 Rename io service. 2017-08-29 14:38:23 +03:00
Egor Pugin
e01c1e0d37 Rename test. 2017-08-29 14:34:35 +03:00
Egor Pugin
c2602e86e9 Make counter 64 bits. 2017-08-29 14:20:51 +03:00
Egor Pugin
e2a2a57820 Fix multithreaded async pipes creation. 2017-08-29 14:19:21 +03:00
Klemens Morgenstern
547c04fc1f Updated vfork check 2017-08-22 22:02:48 +02:00
Klemens Morgenstern
6ab2ed1723 Merge pull request #119 from klemens-morgenstern/fix_for_118
Strange typo fix
2017-08-22 15:50:58 -04:00
Klemens Morgenstern
79e26878b1 Strange typo fix
Trying to fix #118
2017-08-22 18:24:53 +02:00
Klemens Morgenstern
d15e7be16a Merge pull request #117 from sehe/develop
fix `rdbuf()` implementation on pipe
2017-08-22 15:40:57 +02:00
sehe
3ab038fc0f fix rdbuf() implementation on pipe 2017-08-22 09:56:44 +02:00
Klemens Morgenstern
66989a25f2 Update wait_group.hpp 2017-08-02 22:23:09 +02:00
klemens-morgenstern
c748fff766 Merge branch 'master' of github.com:boostorg/process 2017-08-02 21:59:29 +02:00
Klemens Morgenstern
4772a08f89 Merge pull request #113 from klemens-morgenstern/develop
1.65 bugfixes
2017-08-02 21:58:22 +02:00
klemens-morgenstern
054d7980ab hopefully closes #106 2017-08-02 21:08:33 +02:00
Klemens Morgenstern
4c6b0fff2a Merge pull request #115 from klemens-morgenstern/sigchld_service
Sigchld service
2017-08-02 13:50:09 +02:00
Klemens Morgenstern
449eef0b98 Update async.hpp 2017-08-02 09:37:06 +02:00
Klemens Morgenstern
3992965359 Update extend.qbk 2017-08-02 09:36:53 +02:00
Klemens Morgenstern
264b517b38 Update async.hpp 2017-08-02 09:35:41 +02:00
Klemens Morgenstern
71c2fad8ce Update extend.qbk 2017-08-02 09:33:36 +02:00
Klemens Morgenstern
5b45fad163 Update wait.cpp
removed double wait
2017-08-02 09:27:38 +02:00
Klemens Morgenstern
e899189bf4 Update on_exit3.cpp
typo fix
2017-08-02 09:25:39 +02:00
klemens-morgenstern
241883c9e4 changed to use only one signal 2017-08-02 08:34:53 +02:00
klemens-morgenstern
aeee4e5dbb windows wait_for fix 2017-08-02 08:31:30 +02:00
Klemens David Morgenstern
e08e095fd1 WEXITSTATUS fix 2017-08-02 01:52:58 -04:00
Klemens David Morgenstern
da34b4020d Trying to get the sigchld-service to work 2017-08-01 18:41:55 -04:00
Klemens David Morgenstern
99001ccb50 Fixed wait_for & wait_until, closes #11 2017-08-01 18:00:44 -04:00
klemens-morgenstern
f402f48138 started on sigchld_service.hpp 2017-08-01 20:58:09 +02:00
klemens-morgenstern
1960360099 typo fixes 2017-08-01 20:07:22 +02:00
klemens-morgenstern
83019b5f70 started on the wait for fix for posix 2017-08-01 19:35:55 +02:00
klemens-morgenstern
76418ca191 added wait_for and wait_until tests 2017-08-01 19:17:28 +02:00
klemens-morgenstern
f02e72304f seperated test-suites into valgrind / no-valgrind 2017-08-01 19:05:40 +02:00
klemens-morgenstern
4850ae493f Merge branch 'develop' of github.com:klemens-morgenstern/boost-process into develop 2017-07-31 22:32:29 +02:00
Klemens Morgenstern
77aecb43b8 Merge pull request #14 from jschueller/lowercase-windows-header
lowercase win32 header to fix cross-compilation
2017-07-31 22:31:37 +02:00
Julien Schueller
66e576806f lowercase win32 header to fix cross-compilation 2017-07-31 22:27:39 +02:00
Klemens Morgenstern
15445fd2bf Merge pull request #110 from thomasschaub/develop
Respect WIFSIGNALED in all relevant places
2017-07-25 20:27:13 +02:00
Klemens Morgenstern
6f49261c6e Merge pull request #111 from thomasschaub/feature/avoid-reencoding-on-windows
Avoid string charset conversion
2017-07-25 20:24:15 +02:00
Thomas Schaub
062b26e046 Avoid string charset conversion 2017-07-25 18:12:13 +02:00
Thomas Schaub
bb0fe86292 Respect WIFSIGNALED in all relevant places
Was only respected for one `waitpid` call
2017-07-25 18:01:53 +02:00
Klemens Morgenstern
a3d3a98d5b Merge pull request #13 from egorpugin/develop
Set correct access rights. Fix windows build.
2017-07-24 07:23:23 +02:00
Egor Pugin
950f16fe42 Merge branch 'develop' of github.com-egorpugin:egorpugin/process into develop 2017-07-24 00:48:37 +03:00
Egor Pugin
225b322e56 Fix windows build. 2017-07-24 00:47:48 +03:00
Egor Pugin
3e31d43d61 Fix access rights. 2017-07-24 00:27:17 +03:00
Klemens Morgenstern
085adc07ec Merge pull request #12 from egorpugin/develop
Fix incorrect on_exit() callback called on any child exited.
2017-07-23 23:18:39 +02:00
Klemens Morgenstern
6aaefedf25 Merge pull request #11 from thomasschaub/develop
Respect WIFSIGNALED
2017-07-23 23:18:16 +02:00
Egor Pugin
8df9c467e5 Fix incorrect on_exit() callback called on any child exited. 2017-07-24 00:10:30 +03:00
Thomas Schaub
529d09f43b Respect WIFSIGNALED 2017-07-19 12:00:44 +02:00
klemens-morgenstern
ce2a06f3a6 closes #102 2017-06-03 10:29:45 +02:00
Klemens Morgenstern
93a077e911 Merge pull request #10 from triccardi-systran/typos
Fix some typos.
2017-05-22 11:24:35 +02:00
Thomas Riccardi
9ed2ebef27 Fix some typos. 2017-05-22 11:14:29 +02:00
klemens-morgenstern
7882bad799 updated readme 2017-05-10 15:00:55 +02:00
Klemens Morgenstern
92e1e04ae4 Merge pull request #9 from cdglove/restore_wargs_tests
Restore wargs tests
2017-05-10 14:59:31 +02:00
Chris Glover
cf19c451fa Remove returns that were disabling wargs tests. 2017-05-10 08:51:31 -04:00
klemens-morgenstern
74dd6570e3 small fixes, closes #97 2017-05-07 12:44:38 +02:00
klemens-morgenstern
826177a12e Merge branch 'develop' of github.com:boostorg/process into develop
# Conflicts:
#	include/boost/process/detail/windows/search_path.hpp
2017-05-01 10:56:24 +02:00
Klemens Morgenstern
6712c54827 Merge pull request #8 from tabe/throw_last_error-const_char
Overloading boost::process::detail::throw_last_error() for Xcode's clang++
2017-05-01 10:54:32 +02:00
Takeshi Abe
6a64b9e0bd Allow const char * as throw_last_error()'s argument 2017-05-01 17:29:35 +09:00
klemens-morgenstern
34377ecad0 typo fixes 2017-04-25 21:02:16 +02:00
klemens-morgenstern
ae2b0a9024 removed tabs 2017-04-23 19:16:39 +02:00
klemens-morgenstern
712ebf772b changed search_path to use PATHEXT on windows, closes #91 2017-04-23 19:14:18 +02:00
klemens-morgenstern
7a99be71d3 tab fix 2017-04-23 17:46:18 +02:00
klemens-morgenstern
210efd8dc5 Merge branch 'async-pipe-fix' into develop 2017-04-23 17:43:42 +02:00
klemens-morgenstern
ed15395f6d fixed example error, closes #87 2017-04-23 17:42:02 +02:00
klemens-morgenstern
05443af621 readme fix 2017-04-23 17:30:36 +02:00
klemens-morgenstern
a25665aeff removed merge error 2017-04-23 17:29:12 +02:00
klemens-morgenstern
ee4428c226 Merge branch 'whitespaces' into develop
# Conflicts:
#	include/boost/process/io.hpp
2017-04-23 17:28:35 +02:00
klemens-morgenstern
74814e46c1 closes #90 2017-04-23 15:09:39 +02:00
klemens-morgenstern
f27898cdcd yml branch selection fix 2017-04-23 15:05:41 +02:00
klemens-morgenstern
007dd97486 added pid_t typedef, closes #82 2017-04-23 15:03:50 +02:00
klemens-morgenstern
f0082aa797 closes #89 2017-04-23 14:54:46 +02:00
klemens-morgenstern
ba14d9f870 Normalize all the line endings 2017-04-23 14:48:16 +02:00
klemens-morgenstern
684f9bcf11 added .git attributes, see #88 2017-04-23 14:41:26 +02:00
Klemens Morgenstern
51735a5640 Merge pull request #86 from ForNeVeR/patch-1
README: update markdown
2017-04-06 08:53:09 +02:00
Friedrich von Never
d6b242c54a README: update markdown 2017-04-06 11:46:24 +07:00
Klemens Morgenstern
9daf3b4717 Merge pull request #80 from klemens-morgenstern/env_fix
Updated environment reset on windows
2017-03-19 18:36:51 +01:00
klemens-morgenstern
9cab8d455a Updated environment reset on windows 2017-03-19 18:04:38 +01:00
Klemens Morgenstern
f1bd81d56e Merge pull request #79 from ChrisKitching/moreWarnings
Fix some more warnings...
2017-03-17 19:13:24 +01:00
Chris Kitching
28dc0c8830 Repair more Wunused warnings 2017-03-17 17:39:33 +00:00
Chris Kitching
7e217fe012 Stop using mixed line-endings... 2017-03-17 17:39:05 +00:00
161 changed files with 10434 additions and 7282 deletions

75
.circleci/config.yml Normal file
View File

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

96
.gitattributes vendored Normal file
View File

@@ -0,0 +1,96 @@
* text=auto !eol svneol=native#text/plain
*.gitattributes text svneol=native#text/plain
# Scriptish formats
*.bat text svneol=native#text/plain
*.bsh text svneol=native#text/x-beanshell
*.cgi text svneol=native#text/plain
*.cmd text svneol=native#text/plain
*.js text svneol=native#text/javascript
*.php text svneol=native#text/x-php
*.pl text svneol=native#text/x-perl
*.pm text svneol=native#text/x-perl
*.py text svneol=native#text/x-python
*.sh eol=lf svneol=LF#text/x-sh
configure eol=lf svneol=LF#text/x-sh
# Image formats
*.bmp binary svneol=unset#image/bmp
*.gif binary svneol=unset#image/gif
*.ico binary svneol=unset#image/ico
*.jpeg binary svneol=unset#image/jpeg
*.jpg binary svneol=unset#image/jpeg
*.png binary svneol=unset#image/png
*.tif binary svneol=unset#image/tiff
*.tiff binary svneol=unset#image/tiff
*.svg text svneol=native#image/svg%2Bxml
# Data formats
*.pdf binary svneol=unset#application/pdf
*.avi binary svneol=unset#video/avi
*.doc binary svneol=unset#application/msword
*.dsp text svneol=crlf#text/plain
*.dsw text svneol=crlf#text/plain
*.eps binary svneol=unset#application/postscript
*.gz binary svneol=unset#application/gzip
*.mov binary svneol=unset#video/quicktime
*.mp3 binary svneol=unset#audio/mpeg
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
*.ps binary svneol=unset#application/postscript
*.psd binary svneol=unset#application/photoshop
*.rdf binary svneol=unset#text/rdf
*.rss text svneol=unset#text/xml
*.rtf binary svneol=unset#text/rtf
*.sln text svneol=native#text/plain
*.swf binary svneol=unset#application/x-shockwave-flash
*.tgz binary svneol=unset#application/gzip
*.vcproj text svneol=native#text/xml
*.vcxproj text svneol=native#text/xml
*.vsprops text svneol=native#text/xml
*.wav binary svneol=unset#audio/wav
*.xls binary svneol=unset#application/vnd.ms-excel
*.zip binary svneol=unset#application/zip
# Text formats
.htaccess text svneol=native#text/plain
*.bbk text svneol=native#text/xml
*.cmake text svneol=native#text/plain
*.css text svneol=native#text/css
*.dtd text svneol=native#text/xml
*.htm text svneol=native#text/html
*.html text svneol=native#text/html
*.ini text svneol=native#text/plain
*.log text svneol=native#text/plain
*.mak text svneol=native#text/plain
*.qbk text svneol=native#text/plain
*.rst text svneol=native#text/plain
*.sql text svneol=native#text/x-sql
*.txt text svneol=native#text/plain
*.xhtml text svneol=native#text/xhtml%2Bxml
*.xml text svneol=native#text/xml
*.xsd text svneol=native#text/xml
*.xsl text svneol=native#text/xml
*.xslt text svneol=native#text/xml
*.xul text svneol=native#text/xul
*.yml text svneol=native#text/plain
boost-no-inspect text svneol=native#text/plain
CHANGES text svneol=native#text/plain
COPYING text svneol=native#text/plain
INSTALL text svneol=native#text/plain
Jamfile text svneol=native#text/plain
Jamroot text svneol=native#text/plain
Jamfile.v2 text svneol=native#text/plain
Jamrules text svneol=native#text/plain
Makefile* text svneol=native#text/plain
README text svneol=native#text/plain
TODO text svneol=native#text/plain
# Code formats
*.c text svneol=native#text/plain
*.cpp text svneol=native#text/plain
*.h text svneol=native#text/plain
*.hpp text svneol=native#text/plain
*.ipp text svneol=native#text/plain
*.tpp text svneol=native#text/plain
*.jam text svneol=native#text/plain
*.java text svneol=native#text/plain

View File

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

@@ -1,13 +1,14 @@
#[Boost Process (Boost.Process)](https://github.com/klemens-morgenstern/boost-process)
# [Boost Process (Boost.Process)](https://github.com/klemens-morgenstern/boost-process)
Boost.process is not yet part of the [Boost C++ Libraries](http://github.com/boostorg), but will probably be released in boost 1.64. It is a library for comfortable management of processes.
Boost.process is a library for comfortable management of processes, released with boost 1.64.0.
### Test results
Branches | Build | Tests coverage |
----------------|-------------- | -------------- |
Develop: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=develop)](https://travis-ci.org/klemens-morgenstern/boost-process) [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=develop)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=develop) |
Master: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=master)] (https://travis-ci.org/klemens-morgenstern/boost-process) [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba/branch/master?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=master)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) |
Branches | Linux | 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)
@@ -21,4 +22,4 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org
### Dependency
This library requires boost 1.63. Since this is not released yet you can clone the winapi module from [here](https://github.com/boostorg/winapi) to get it to work on windows.
This library requires boost 1.64 with which it is released.

View File

@@ -16,7 +16,7 @@ In that it is different than other facilities (like sockets) and provides anothe
Pipes are typically used for interprocess communication. The main reason is, that pipes can be directly assigned to the process stdio, i.e. stderr, stdin and stdout.
Additionally, half of the pipe can be inherited to the child process and closed in the father process. This will cause the pipe to be broken when the child process exits.
Though please not, that if the the same thread reads and write to a pipe, it will only talk to itself.
Though please note, that if the the same thread reads and write to a pipe, it will only talk to itself.
[section:anonymous Anonymous Pipes]
@@ -50,7 +50,7 @@ which also have file-like names, but are in a different scope than the actual fi
[section:process Processes]
A process is an independently executable entity, which is different from a thread, in that it has it's own resources.
A process is an independently executable entity, which is different from a thread, in that it has its own resources.
Those include memory and hardware resources.
Every process is identified by a unique number[footnote it is unique as long as the process is active], called the process identification digit, `pid`.

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,25 +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__
@@ -121,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;
};
@@ -134,6 +133,8 @@ struct async_bar : __handler, __async_handler__
[caution `on_exit_handler` does not default and is always required when [classref boost::process::extend::async_handler async_handler] is inherited. ]
[caution `on_exit_handler` uses `boost::asio::signal_set` to listen for SIGCHLD on posix. The application must not also register a signal handler for SIGCHLD using functions such as `signal()` or `sigaction()` (but using `boost::asio::signal_set` is fine). ]
[endsect]
[section:error Error handling]
@@ -208,4 +209,4 @@ way to implement systems-specific code without using the preprocessor.
[endsect]
[endsect]
[endsect]

View File

@@ -1,87 +1,87 @@
[section:faq Frequently Asked Questions]
[section:faq Frequently Asked Questions]
[section:dead_lock Why does this produce a deadlock?]
[section:dead_lock Why does this produce a deadlock?]
Now let's revisit our c++filt example and we will put in an obvious mistake.
This might however be not as obvious for more complex applications.
Now let's revisit our c++filt example and we will put in an obvious mistake.
This might however be not as obvious for more complex applications.
```
vector<string> demangle(vector<string> in)
{
ipstream is;
opstream os;
child c("c++filt", std_out > is, std_in < os);
vector<string> data;
for (auto & elem : data)
{
string line;
getline(is, line);
os << elem;
}
}
```
We switched the read and write operation up, so that's causing a dead-lock.
This locks immediately. This is because `c++filt` expects input, before
outputting any data. The launching process on the other hand wait's for it's output.
```
vector<string> demangle(vector<string> in)
{
ipstream is;
opstream os;
child c("c++filt", std_out > is, std_in < os);
vector<string> data;
for (auto & elem : data)
{
string line;
getline(is, line);
os << elem;
}
}
```
We switched the read and write operation up, so that's causing a dead-lock.
This locks immediately. This is because `c++filt` expects input, before
outputting any data. The launching process on the other hand waits for its output.
[endsect]
[endsect]
[section:closep Why does the pipe not close?]
[section:closep Why does the pipe not close?]
Now for another example, which might look correct, let's consider you want
to use `ls` to read the current directory.
Now for another example, which might look correct, let's consider you want
to use `ls` to read the current directory.
```
ipstream is;
child c("ls", std_out > is);
```
ipstream is;
child c("ls", std_out > is);
std::string file;
while (is >> file)
cout << "File: " << file << endl;
```
std::string file;
while (is >> file)
cout << "File: " << file << endl;
```
This will also deadlock, because the pipe does not close when the subprocess exits.
So the `ipstream` will still look for data even though the process has ended.
This will also deadlock, because the pipe does not close when the subprocess exits.
So the `ipstream` will still look for data even though the process has ended.
[note It is not possible to use automatically pipe-closing in this library, because
a pipe might be a file-handle (as for async pipes on windows).]
[note It is not possible to use automatically pipe-closing in this library, because
a pipe might be a file-handle (as for async pipes on windows).]
But, since pipes are buffered, you might get incomplete data if you do this:
But, since pipes are buffered, you might get incomplete data if you do this:
```
ipstream is;
child c("ls", std_out > is);
```
ipstream is;
child c("ls", std_out > is);
std::string file;
while (c.running())
{
is >> file;
cout << "File: " << file << endl;
}
```
std::string file;
while (c.running())
{
is >> file;
cout << "File: " << file << endl;
}
```
It is therefore highly recommended that you use the asynchronous api if you are
not absolutely sure how the output will look.
It is therefore highly recommended that you use the asynchronous api if you are
not absolutely sure how the output will look.
[endsect]
[endsect]
[section:wchar_t When will the codecvt be used?]
[section:wchar_t When will the codecvt be used?]
Since windows does not use UTF-8 it is sometimes unavoidable to use the `wchar_t` version of the WinApi.
To keep this library consistent it provides `wchar_t` support on posix also.
Since windows does not use UTF-8 it is sometimes unavoidable to use the `wchar_t` version of the WinApi.
To keep this library consistent it provides `wchar_t` support on posix also.
Since the posix api is purely `char` every `wchar_t` based type will be converted into `char`.
Since the posix api is purely `char` every `wchar_t` based type will be converted into `char`.
Windows on the other hand is more selective; the default is to use `char`,
but if any parameter requires `wchar_t`, everything will be converted to `wchar_t`.
This also includes `boost::filesystem::path`. Additionally, if the system does not provide
the `char` api (as is the case with Windows CE) everything will also be converted.
Windows on the other hand is more selective; the default is to use `char`,
but if any parameter requires `wchar_t`, everything will be converted to `wchar_t`.
This also includes `boost::filesystem::path`. Additionally, if the system does not provide
the `char` api (as is the case with Windows CE) everything will also be converted.
[endsect]
[endsect]
[endsect]

View File

@@ -30,7 +30,7 @@
[def asio_async_read [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_read.html boost::asio::async_read]]
[def bp::environment [classref boost::process::basic_environment bp::environment]]
[def bp::native_environment [classref boost::process::basic_native_environment bp::native_environment]]
[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]]
[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process:deadlock :environment]]
[def std::chrono::seconds [@http://en.cppreference.com/w/cpp/chrono/duration std::chrono::seconds]]
[def std::vector [@http://en.cppreference.com/w/cpp/container/vector std::vector]]
@@ -81,7 +81,7 @@ So as a first step, we'll use the `exe-args` style.
int result = bp::system("/usr/bin/g++", "main.cpp");
```
With that sytax we still have "g++" hard-coded, so let's assume we get the string
With that syntax we still have "g++" hard-coded, so let's assume we get the string
from an external source as `boost::filesystem::path`, we can do this too.
```
@@ -104,13 +104,13 @@ This also includes to add a file suffix on windows, such as `.exe` or `.bat`.]
[section:launch_mode Launch functions]
Given that in our example used the [funcref boost::process::system system] function,
our program will wait until the child process is completed. This maybe unwanted,
Given that our example used the [funcref boost::process::system system] function,
our program will wait until the child process is completed. This may be unwanted,
especially since compiling can take a while.
In order to avoid that, boost.process provides several ways to launch a process.
Besides the already mentioned [funcref boost::process::system system] function and it's
asynchronous version [funcref boost::process::async_system async_system],
Besides the already mentioned [funcref boost::process::system system] function and its
asynchronous version [funcref boost::process::async_system async_system],
we can also use the [funcref boost::process::spawn spawn] function or the
[classref boost::process::child child] class.
@@ -151,14 +151,14 @@ This can be avoided by calling __detach__ beforehand]
Until now, we have assumed that everything works out, but it is not impossible,
that "g++" is not present. That will cause the launch of the process to fail.
The default behaviour of all functions is to throw an
The default behaviour of all functions is to throw a
[@http://en.cppreference.com/w/cpp/error/system_error std::system_error] on failure.
As with many other functions in this library, passing an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code]
will change the behaviour, so that instead of throwing an exception, the error will be a assigned to the error code.
will change the behaviour, so that instead of throwing an exception, the error will be assigned to the error code.
```
std::error_code ec;
bp::system c("g++ main.cpp", ec);
bp::system("g++ main.cpp", ec);
```
[endsect]
[section:io Synchronous I/O]
@@ -200,7 +200,7 @@ wrap around the [classref boost::process::pipe pipe] and provide an implementati
std::vector<std::string> read_outline(std::string & file)
{
bp::ipstream is; //reading pipe-stream
bp::child c(bp::search_patk("nm"), file, bp::std_out > is);
bp::child c(bp::search_path("nm"), file, bp::std_out > is);
std::vector<std::string> data;
std::string line;
@@ -217,8 +217,7 @@ std::vector<std::string> read_outline(std::string & file)
What this does is redirect the `stdout` of the process into a pipe and we read this
synchronously.
[warning The pipe will cause a deadlock if you try to read after nm exited]
[note You can do the same thing with [globalref boost::process::std_err std_err]]
[note You can do the same thing with [globalref boost::process::std_err std_err]]
Now we get the name from `nm` and we might want to demangle it, so we use input and output.
`nm` has a demangle option, but for the sake of the example, we'll use
@@ -278,7 +277,7 @@ With [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] this is what
```
io_service ios;
std::vector<char> buf;
std::vector<char> buf(4096);
bp::async_pipe ap(ios);
@@ -288,7 +287,6 @@ asio_async_read(ap, asio_buffer(buf),
[](const boost::system::error_code &ec, std::size_t size){});
ios.run();
c.wait();
int result = c.exit_code();
```
@@ -297,12 +295,11 @@ provided we also pass a reference to an io_service.
```
io_service ios;
std::vector<char> buf;
std::vector<char> buf(4096);
bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > asio_buffer(buf), ios);
ios.run();
c.wait();
int result = c.exit_code();
```
@@ -342,10 +339,10 @@ it will not terminate all the child processes of the child unless you use a grou
The two main reasons to use groups are:
# Being able two terminate child processes of the child process
# Being able to terminate child processes of the child process
# Grouping several processes into one, just so they can be terminated at once
If we have program like `make`, which does launch it's own child processes,
If we have program like `make`, which does launch its own child processes,
a call of child_terminate might not suffice. I.e. if we have a makefile launching `gcc`
and use the following code, the `gcc` process will still run afterwards:
@@ -388,7 +385,7 @@ void f()
```
In the example, it will wait for both processes at the end of the function unless
an exception occures. I.e. if an exception is thrown, the group will be terminated.
an exception occurs. I.e. if an exception is thrown, the group will be terminated.
Please see the [headerref boost/process/group.hpp reference] for more information.
@@ -405,7 +402,7 @@ auto env = boost::this_process::environment();
//add a variable to the current environment
env["VALUE_1"] = "foo";
//copy it into a environment seperate to the one of this process
//copy it into an environment separate to the one of this process
bp::environment env_ = env;
//append two values to a variable in the new env
env_["VALUE_2"] += {"bar1", "bar2"};

View File

@@ -16,7 +16,7 @@ namespace bp = boost::process;
int main()
{
boost::asio::io_service ios;
boost::asio::io_context ios;
boost::asio::streambuf buffer;

View File

@@ -44,14 +44,14 @@ int main()
}
{
boost::asio::io_service io_service;
bp::async_pipe p1(io_service);
bp::async_pipe p2(io_service);
boost::asio::io_context io_context;
bp::async_pipe p1(io_context);
bp::async_pipe p2(io_context);
bp::system(
"test.exe",
bp::std_out > p2,
bp::std_in < p1,
io_service,
io_context,
bp::on_exit([&](int exit, const std::error_code& ec_in)
{
p1.async_close();
@@ -64,7 +64,7 @@ int main()
boost::asio::async_read (p2, boost::asio::buffer(in_buf), []( const boost::system::error_code&, std::size_t){});
}
{
boost::asio::io_service io_service;
boost::asio::io_context io_context;
std::vector<char> in_buf;
std::string value = "my_string";
bp::system(
@@ -75,7 +75,7 @@ int main()
}
{
boost::asio::io_service io_service;
boost::asio::io_context io_context;
std::future<std::vector<char>> in_buf;
std::future<void> write_fut;
std::string value = "my_string";

View File

@@ -21,14 +21,14 @@ int main()
}
{
boost::asio::io_service io_service;
boost::asio::io_context io_context;
bp::child c(
"test.exe",
io_service,
io_context,
bp::on_exit([&](int exit, const std::error_code& ec_in){})
);
io_service.run();
io_context.run();
}
}

14
filter_section_warning.py Normal file
View File

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

View File

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

View File

@@ -7,7 +7,7 @@
The header which provides the basic asynchrounous features.
It provides the on_exit property, which allows callbacks when the process exits.
It also implements the necessary traits for passing an boost::asio::io_service,
It also implements the necessary traits for passing an boost::asio::io_context,
which is needed for asynchronous communication.
It also pulls the [boost::asio::buffer](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html)
@@ -32,20 +32,20 @@ namespace boost {
#include <boost/process/detail/traits.hpp>
#include <boost/process/detail/on_exit.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/buffer.hpp>
#include <type_traits>
#include <boost/fusion/iterator/deref.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/io_service_ref.hpp>
#include <boost/process/detail/posix/io_context_ref.hpp>
#include <boost/process/detail/posix/async_in.hpp>
#include <boost/process/detail/posix/async_out.hpp>
#include <boost/process/detail/posix/on_exit.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/io_service_ref.hpp>
#include <boost/process/detail/windows/io_context_ref.hpp>
#include <boost/process/detail/windows/async_in.hpp>
#include <boost/process/detail/windows/async_out.hpp>
#include <boost/process/detail/windows/on_exit.hpp>
@@ -56,25 +56,25 @@ namespace boost { namespace process { namespace detail {
struct async_tag;
template<typename T>
struct is_io_service : std::false_type {};
struct is_io_context : std::false_type {};
template<>
struct is_io_service<api::io_service_ref> : std::true_type {};
struct is_io_context<api::io_context_ref> : std::true_type {};
template<typename Tuple>
inline asio::io_service& get_io_service(const Tuple & tup)
inline asio::io_context& get_io_context(const Tuple & tup)
{
auto& ref = *boost::fusion::find_if<is_io_service<boost::mpl::_>>(tup);
auto& ref = *boost::fusion::find_if<is_io_context<boost::mpl::_>>(tup);
return ref.get();
}
struct async_builder
{
boost::asio::io_service * ios;
boost::asio::io_context * ios;
void operator()(boost::asio::io_service & ios_) {this->ios = &ios_;};
void operator()(boost::asio::io_context & ios_) {this->ios = &ios_;};
typedef api::io_service_ref result_type;
api::io_service_ref get_initializer() {return api::io_service_ref (*ios);};
typedef api::io_context_ref result_type;
api::io_context_ref get_initializer() {return api::io_context_ref (*ios);};
};
@@ -90,7 +90,7 @@ using ::boost::asio::buffer;
#if defined(BOOST_PROCESS_DOXYGEN)
/** When an io_service is passed, the on_exit property can be used, to be notified
/** When an io_context is passed, the on_exit property can be used, to be notified
when the child process exits.
@@ -107,7 +107,7 @@ with `function` being a callable object with the signature `(int, const std::err
\par Example
\code{.cpp}
io_service ios;
io_context ios;
child c("ls", on_exit=[](int exit, const std::error_code& ec_in){});
@@ -117,8 +117,10 @@ chlid c2("ls", on_exit=exit_code);
\endcode
\note The handler is not invoked when the launch fails.
\warning When used \ref ignore_error it might gte invoked on error.
\warning When used \ref ignore_error it might get invoked on error.
\warning `on_exit` uses `boost::asio::signal_set` to listen for `SIGCHLD` on posix, and so has the
same restrictions as that class (do not register a handler for `SIGCHLD` except by using
`boost::asio::signal_set`).
*/
constexpr static ::boost::process::detail::on_exit_ on_exit{};
#endif

View File

@@ -48,31 +48,31 @@ public:
typedef platform_specific handle_type;
/** Construct a new async_pipe, does automatically open the pipe.
* Initializes source and sink with the same io_service.
* Initializes source and sink with the same io_context.
* @note Windows creates a named pipe here, where the name is automatically generated.
*/
inline async_pipe(boost::asio::io_service & ios);
inline async_pipe(boost::asio::io_context & ios);
/** Construct a new async_pipe, does automatically open the pipe.
* @note Windows creates a named pipe here, where the name is automatically generated.
*/
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink);
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink);
/** Construct a new async_pipe, does automatically open.
* Initializes source and sink with the same io_service.
* Initializes source and sink with the same io_context.
*
* @note Windows restricts possible names.
*/
inline async_pipe(boost::asio::io_service & ios, const std::string & name);
inline async_pipe(boost::asio::io_context & ios, const std::string & name);
/** Construct a new async_pipe, does automatically open.
*
* @note Windows restricts possible names.
*/
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink, const std::string & name);
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink, const std::string & name);
/** Copy-Constructor of the async pipe.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
@@ -89,15 +89,15 @@ public:
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p);
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p);
/** Construct the async-pipe from a pipe, with two different io_service objects.
/** Construct the async-pipe from a pipe, with two different io_context objects.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
explicit async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
const basic_pipe<CharT, Traits> & p);
@@ -189,15 +189,15 @@ public:
///Get the asio handle of the pipe source. Qualified as rvalue
handle_type && source() &&;
/// Move the source out of this class and change the io_service. Qualified as rvalue. \attention Will always move.
handle_type source(::boost::asio::io_service& ios) &&;
/// Move the sink out of this class and change the io_service. Qualified as rvalue. \attention Will always move
handle_type sink (::boost::asio::io_service& ios) &&;
/// Move the source out of this class and change the io_context. Qualified as rvalue. \attention Will always move.
handle_type source(::boost::asio::io_context& ios) &&;
/// Move the sink out of this class and change the io_context. Qualified as rvalue. \attention Will always move
handle_type sink (::boost::asio::io_context& ios) &&;
/// Copy the source out of this class and change the io_service. \attention Will always copy.
handle_type source(::boost::asio::io_service& ios) const &;
/// Copy the sink out of this class and change the io_service. \attention Will always copy
handle_type sink (::boost::asio::io_service& ios) const &;
/// Copy the source out of this class and change the io_context. \attention Will always copy.
handle_type source(::boost::asio::io_context& ios) const &;
/// Copy the sink out of this class and change the io_context. \attention Will always copy
handle_type sink (::boost::asio::io_context& ios) const &;

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>
@@ -40,8 +41,8 @@ namespace detail
template<typename ExitHandler>
struct async_system_handler : ::boost::process::detail::api::async_handler
{
boost::asio::io_service & ios;
boost::asio::detail::async_result_init<
boost::asio::io_context & ios;
boost::asio::async_completion<
ExitHandler, void(boost::system::error_code, int)> init;
#if defined(BOOST_POSIX_API)
@@ -50,8 +51,8 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
template<typename ExitHandler_>
async_system_handler(
boost::asio::io_service & ios,
ExitHandler_ && exit_handler) : ios(ios), init(std::forward<ExitHandler_>(exit_handler))
boost::asio::io_context & ios,
ExitHandler_ && exit_handler) : ios(ios), init(exit_handler)
{
}
@@ -63,12 +64,13 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
#if defined(BOOST_POSIX_API)
errored = true;
#endif
auto & h = init.handler;
ios.post(
[h, ec]() mutable
{
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
});
auto & h = init.completion_handler;
boost::asio::post(
ios.get_executor(),
[h, ec]() mutable
{
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
});
}
BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
@@ -82,9 +84,9 @@ 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.handler;
auto & h = init.completion_handler;
return [h](int exit_code, const std::error_code & ec) mutable
{
h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
@@ -106,7 +108,7 @@ but is similar to the asynchronous functions in [boost.asio](http://www.boost.or
It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine
the return value (from the second parameter, `exit_handler`).
\param ios A reference to an [io_service](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html)
\param ios A reference to an [io_context](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html)
\param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)`
\note This function does not allow custom error handling, since those are done through the `exit_handler`.
@@ -115,12 +117,12 @@ the return value (from the second parameter, `exit_handler`).
#if defined(BOOST_PROCESS_DOXYGEN)
template<typename ExitHandler, typename ...Args>
inline boost::process::detail::dummy
async_system(boost::asio::io_service & ios, ExitHandler && exit_handler, Args && ...args);
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
#endif
template<typename ExitHandler, typename ...Args>
inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
async_system(boost::asio::io_service & ios, ExitHandler && exit_handler, Args && ...args)
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args)
{
detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};

View File

@@ -35,6 +35,9 @@ child::child(Args&&...args)
: child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {}
///Typedef for the type of an pid_t
typedef ::boost::process::detail::api::pid_t pid_t;
#if defined(BOOST_PROCESS_DOXYGEN)
/** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread),
* in that it has a join and detach function.
@@ -89,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

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

View File

@@ -27,37 +27,37 @@ namespace detail {
#if defined(BOOST_POSIX_API)
using ::boost::process::detail::posix::is_async_handler;
using ::boost::process::detail::posix::does_require_io_service;
using ::boost::process::detail::posix::does_require_io_context;
#else
using ::boost::process::detail::windows::is_async_handler;
using ::boost::process::detail::windows::does_require_io_service;
using ::boost::process::detail::windows::does_require_io_context;
#endif
template<typename ...Args>
struct has_io_service;
struct has_io_context;
template<typename T, typename ...Args>
struct has_io_service<T, Args...>
struct has_io_context<T, Args...>
{
typedef typename has_io_service<Args...>::type next;
typedef typename has_io_context<Args...>::type next;
typedef typename std::is_same<
typename std::remove_reference<T>::type,
boost::asio::io_service>::type is_ios;
boost::asio::io_context>::type is_ios;
typedef typename std::conditional<is_ios::value,
std::true_type,
next>::type type;
};
template<typename T>
struct has_io_service<T>
struct has_io_context<T>
{
typedef typename std::is_same<
typename std::remove_reference<T>::type,
boost::asio::io_service>::type type;
boost::asio::io_context>::type type;
};
template<typename ...Args>
using has_io_service_t = typename has_io_service<Args...>::type;
using has_io_context_t = typename has_io_context<Args...>::type;
template<typename ...Args>
struct has_async_handler;
@@ -79,34 +79,34 @@ struct has_async_handler<T>
};
template<typename ...Args>
struct needs_io_service;
struct needs_io_context;
template<typename T, typename ...Args>
struct needs_io_service<T, Args...>
struct needs_io_context<T, Args...>
{
typedef typename needs_io_service<Args...>::type next;
typedef typename does_require_io_service<T>::type is_ios;
typedef typename needs_io_context<Args...>::type next;
typedef typename does_require_io_context<T>::type is_ios;
typedef typename std::conditional<is_ios::value,
std::true_type,
next>::type type;
};
template<typename T>
struct needs_io_service<T>
struct needs_io_context<T>
{
typedef typename does_require_io_service<T>::type type;
typedef typename does_require_io_context<T>::type type;
};
template<typename ...Args>
boost::asio::io_service &get_io_service_var(boost::asio::io_service & f, Args&...)
boost::asio::io_context &get_io_context_var(boost::asio::io_context & f, Args&...)
{
return f;
}
template<typename First, typename ...Args>
boost::asio::io_service &get_io_service_var(First&, Args&...args)
boost::asio::io_context &get_io_context_var(First&, Args&...args)
{
return get_io_service_var(args...);
return get_io_context_var(args...);
}
}

View File

@@ -1,292 +1,292 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#ifndef BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#if defined( BOOST_WINDOWS_API )
#include <boost/process/detail/windows/basic_cmd.hpp>
#include <boost/process/detail/windows/cmd.hpp>
#elif defined( BOOST_POSIX_API )
#include <boost/process/detail/posix/basic_cmd.hpp>
#include <boost/process/detail/posix/cmd.hpp>
#endif
#if defined( BOOST_WINDOWS_API )
#include <boost/process/detail/windows/basic_cmd.hpp>
#include <boost/process/detail/windows/cmd.hpp>
#elif defined( BOOST_POSIX_API )
#include <boost/process/detail/posix/basic_cmd.hpp>
#include <boost/process/detail/posix/cmd.hpp>
#endif
#include <boost/process/shell.hpp>
#include <boost/process/shell.hpp>
#include <iterator>
#include <iterator>
namespace boost { namespace process { namespace detail {
namespace boost { namespace process { namespace detail {
template<typename Char>
struct exe_setter_
{
typedef Char value_type;
typedef std::basic_string<Char> string_type;
template<typename Char>
struct exe_setter_
{
typedef Char value_type;
typedef std::basic_string<Char> string_type;
string_type exe_;
exe_setter_(string_type && str) : exe_(std::move(str)) {}
exe_setter_(const string_type & str) : exe_(str) {}
};
string_type exe_;
exe_setter_(string_type && str) : exe_(std::move(str)) {}
exe_setter_(const string_type & str) : exe_(str) {}
};
template<> struct is_wchar_t<exe_setter_<wchar_t>> : std::true_type {};
template<> struct is_wchar_t<exe_setter_<wchar_t>> : std::true_type {};
template<>
struct char_converter<char, exe_setter_<wchar_t>>
{
static exe_setter_<char> conv(const exe_setter_<wchar_t> & in)
{
return {::boost::process::detail::convert(in.exe_)};
}
};
template<>
struct char_converter<char, exe_setter_<wchar_t>>
{
static exe_setter_<char> conv(const exe_setter_<wchar_t> & in)
{
return {::boost::process::detail::convert(in.exe_)};
}
};
template<>
struct char_converter<wchar_t, exe_setter_<char>>
{
static exe_setter_<wchar_t> conv(const exe_setter_<char> & in)
{
return {::boost::process::detail::convert(in.exe_)};
}
};
template<>
struct char_converter<wchar_t, exe_setter_<char>>
{
static exe_setter_<wchar_t> conv(const exe_setter_<char> & in)
{
return {::boost::process::detail::convert(in.exe_)};
}
};
template <typename Char, bool Append >
struct arg_setter_
{
using value_type = Char;
using string_type = std::basic_string<value_type>;
std::vector<string_type> _args;
template <typename Char, bool Append >
struct arg_setter_
{
using value_type = Char;
using string_type = std::basic_string<value_type>;
std::vector<string_type> _args;
typedef typename std::vector<string_type>::iterator iterator;
typedef typename std::vector<string_type>::const_iterator const_iterator;
typedef typename std::vector<string_type>::iterator iterator;
typedef typename std::vector<string_type>::const_iterator const_iterator;
template<typename Iterator>
arg_setter_(Iterator && begin, Iterator && end) : _args(begin, end) {}
template<typename Iterator>
arg_setter_(Iterator && begin, Iterator && end) : _args(begin, end) {}
template<typename Range>
arg_setter_(Range && str) :
_args(std::begin(str),
std::end(str)) {}
template<typename Range>
arg_setter_(Range && str) :
_args(std::begin(str),
std::end(str)) {}
iterator begin() {return _args.begin();}
iterator end() {return _args.end();}
const_iterator begin() const {return _args.begin();}
const_iterator end() const {return _args.end();}
arg_setter_(string_type & str) : _args{{str}} {}
arg_setter_(string_type && s) : _args({std::move(s)}) {}
arg_setter_(const string_type & s) : _args({s}) {}
arg_setter_(const value_type* s) : _args({std::move(s)}) {}
iterator begin() {return _args.begin();}
iterator end() {return _args.end();}
const_iterator begin() const {return _args.begin();}
const_iterator end() const {return _args.end();}
arg_setter_(string_type & str) : _args{{str}} {}
arg_setter_(string_type && s) : _args({std::move(s)}) {}
arg_setter_(const string_type & s) : _args({s}) {}
arg_setter_(const value_type* s) : _args({std::move(s)}) {}
template<std::size_t Size>
arg_setter_(const value_type (&s) [Size]) : _args({s}) {}
};
template<std::size_t Size>
arg_setter_(const value_type (&s) [Size]) : _args({s}) {}
};
template<> struct is_wchar_t<arg_setter_<wchar_t, true >> : std::true_type {};
template<> struct is_wchar_t<arg_setter_<wchar_t, false>> : std::true_type {};
template<> struct is_wchar_t<arg_setter_<wchar_t, true >> : std::true_type {};
template<> struct is_wchar_t<arg_setter_<wchar_t, false>> : std::true_type {};
template<>
struct char_converter<char, arg_setter_<wchar_t, true>>
{
static arg_setter_<char, true> conv(const arg_setter_<wchar_t, true> & in)
{
std::vector<std::string> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
template<>
struct char_converter<char, arg_setter_<wchar_t, true>>
{
static arg_setter_<char, true> conv(const arg_setter_<wchar_t, true> & in)
{
std::vector<std::string> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
template<>
struct char_converter<wchar_t, arg_setter_<char, true>>
{
static arg_setter_<wchar_t, true> conv(const arg_setter_<char, true> & in)
{
std::vector<std::wstring> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::detail::convert(ws);
});
template<>
struct char_converter<wchar_t, arg_setter_<char, true>>
{
static arg_setter_<wchar_t, true> conv(const arg_setter_<char, true> & in)
{
std::vector<std::wstring> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
return {vec};
}
};
template<>
struct char_converter<char, arg_setter_<wchar_t, false>>
{
static arg_setter_<char, false> conv(const arg_setter_<wchar_t, false> & in)
{
std::vector<std::string> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec}; }
};
template<>
struct char_converter<char, arg_setter_<wchar_t, false>>
{
static arg_setter_<char, false> conv(const arg_setter_<wchar_t, false> & in)
{
std::vector<std::string> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec}; }
};
template<>
struct char_converter<wchar_t, arg_setter_<char, false>>
{
static arg_setter_<wchar_t, false> conv(const arg_setter_<char, false> & in)
{
std::vector<std::wstring> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
template<>
struct char_converter<wchar_t, arg_setter_<char, false>>
{
static arg_setter_<wchar_t, false> conv(const arg_setter_<char, false> & in)
{
std::vector<std::wstring> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
using api::exe_cmd_init;
using api::exe_cmd_init;
template<typename Char>
struct exe_builder
{
//set by path, because that will not be interpreted as a cmd
bool not_cmd = false;
bool shell = false;
using string_type = std::basic_string<Char>;
string_type exe;
std::vector<string_type> args;
template<typename Char>
struct exe_builder
{
//set by path, because that will not be interpreted as a cmd
bool not_cmd = false;
bool shell = false;
using string_type = std::basic_string<Char>;
string_type exe;
std::vector<string_type> args;
void operator()(const boost::filesystem::path & data)
{
not_cmd = true;
if (exe.empty())
exe = data.native();
else
args.push_back(data.native());
}
void operator()(const boost::filesystem::path & data)
{
not_cmd = true;
if (exe.empty())
exe = data.native();
else
args.push_back(data.native());
}
void operator()(const string_type & data)
{
if (exe.empty())
exe = data;
else
args.push_back(data);
}
void operator()(const Char* data)
{
if (exe.empty())
exe = data;
else
args.push_back(data);
}
void operator()(shell_) {shell = true;}
void operator()(std::vector<string_type> && data)
{
if (data.empty())
return;
void operator()(const string_type & data)
{
if (exe.empty())
exe = data;
else
args.push_back(data);
}
void operator()(const Char* data)
{
if (exe.empty())
exe = data;
else
args.push_back(data);
}
void operator()(shell_) {shell = true;}
void operator()(std::vector<string_type> && data)
{
if (data.empty())
return;
auto itr = std::make_move_iterator(data.begin());
auto end = std::make_move_iterator(data.end());
auto itr = std::make_move_iterator(data.begin());
auto end = std::make_move_iterator(data.end());
if (exe.empty())
{
exe = *itr;
itr++;
}
args.insert(args.end(), itr, end);
}
if (exe.empty())
{
exe = *itr;
itr++;
}
args.insert(args.end(), itr, end);
}
void operator()(const std::vector<string_type> & data)
{
if (data.empty())
return;
void operator()(const std::vector<string_type> & data)
{
if (data.empty())
return;
auto itr = data.begin();
auto end = data.end();
auto itr = data.begin();
auto end = data.end();
if (exe.empty())
{
exe = *itr;
itr++;
}
args.insert(args.end(), itr, end);
}
void operator()(exe_setter_<Char> && data)
{
not_cmd = true;
exe = std::move(data.exe_);
}
void operator()(const exe_setter_<Char> & data)
{
not_cmd = true;
exe = data.exe_;
}
void operator()(arg_setter_<Char, false> && data)
{
args.assign(
std::make_move_iterator(data._args.begin()),
std::make_move_iterator(data._args.end()));
}
void operator()(arg_setter_<Char, true> && data)
{
args.insert(args.end(),
std::make_move_iterator(data._args.begin()),
std::make_move_iterator(data._args.end()));
}
void operator()(const arg_setter_<Char, false> & data)
{
args.assign(data._args.begin(), data._args.end());
}
void operator()(const arg_setter_<Char, true> & data)
{
args.insert(args.end(), data._args.begin(), data._args.end());
}
if (exe.empty())
{
exe = *itr;
itr++;
}
args.insert(args.end(), itr, end);
}
void operator()(exe_setter_<Char> && data)
{
not_cmd = true;
exe = std::move(data.exe_);
}
void operator()(const exe_setter_<Char> & data)
{
not_cmd = true;
exe = data.exe_;
}
void operator()(arg_setter_<Char, false> && data)
{
args.assign(
std::make_move_iterator(data._args.begin()),
std::make_move_iterator(data._args.end()));
}
void operator()(arg_setter_<Char, true> && data)
{
args.insert(args.end(),
std::make_move_iterator(data._args.begin()),
std::make_move_iterator(data._args.end()));
}
void operator()(const arg_setter_<Char, false> & data)
{
args.assign(data._args.begin(), data._args.end());
}
void operator()(const arg_setter_<Char, true> & data)
{
args.insert(args.end(), data._args.begin(), data._args.end());
}
api::exe_cmd_init<Char> get_initializer()
{
if (not_cmd || !args.empty())
{
if (shell)
return api::exe_cmd_init<Char>::exe_args_shell(std::move(exe), std::move(args));
else
return api::exe_cmd_init<Char>::exe_args(std::move(exe), std::move(args));
}
else
if (shell)
return api::exe_cmd_init<Char>::cmd_shell(std::move(exe));
else
return api::exe_cmd_init<Char>::cmd(std::move(exe));
api::exe_cmd_init<Char> get_initializer()
{
if (not_cmd || !args.empty())
{
if (shell)
return api::exe_cmd_init<Char>::exe_args_shell(std::move(exe), std::move(args));
else
return api::exe_cmd_init<Char>::exe_args(std::move(exe), std::move(args));
}
else
if (shell)
return api::exe_cmd_init<Char>::cmd_shell(std::move(exe));
else
return api::exe_cmd_init<Char>::cmd(std::move(exe));
}
typedef api::exe_cmd_init<Char> result_type;
};
}
typedef api::exe_cmd_init<Char> result_type;
};
template<>
struct initializer_builder<cmd_or_exe_tag<char>>
{
typedef exe_builder<char> type;
};
template<>
struct initializer_builder<cmd_or_exe_tag<char>>
{
typedef exe_builder<char> type;
};
template<>
struct initializer_builder<cmd_or_exe_tag<wchar_t>>
{
typedef exe_builder<wchar_t> type;
};
template<>
struct initializer_builder<cmd_or_exe_tag<wchar_t>>
{
typedef exe_builder<wchar_t> type;
};
}}}
}}}
#endif /* BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */

View File

@@ -65,7 +65,8 @@ public:
child(child && lhs) noexcept
: _child_handle(std::move(lhs._child_handle)),
_exit_status(std::move(lhs._exit_status)),
_attached (lhs._attached)
_attached (lhs._attached),
_terminated (lhs._terminated)
{
lhs._attached = false;
}
@@ -79,6 +80,7 @@ public:
_child_handle= std::move(lhs._child_handle);
_exit_status = std::move(lhs._exit_status);
_attached = lhs._attached;
_terminated = lhs._terminated;
lhs._attached = false;
return *this;
};
@@ -99,74 +101,57 @@ public:
int exit_code() const {return ::boost::process::detail::api::eval_exit_status(_exit_status->load());}
pid_t id() const {return _child_handle.id(); }
int native_exit_code() const {return _exit_status->load();}
bool running()
{
if (valid() && !_exited())
{
int code;
auto res = boost::process::detail::api::is_running(_child_handle, code);
if (!res && !_exited())
_exit_status->store(code);
return res;
}
return false;
std::error_code ec;
bool b = running(ec);
boost::process::detail::throw_error(ec, "running error");
return b;
}
void terminate()
{
if (valid() && running())
boost::process::detail::api::terminate(_child_handle);
_terminated = true;
std::error_code ec;
terminate(ec);
boost::process::detail::throw_error(ec, "terminate error");
}
void wait()
{
if (!_exited() && valid())
{
int exit_code = 0;
boost::process::detail::api::wait(_child_handle, exit_code);
_exit_status->store(exit_code);
}
std::error_code ec;
wait(ec);
boost::process::detail::throw_error(ec, "wait error");
}
template< class Rep, class Period >
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
{
if (!_exited())
{
int exit_code = 0;
auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time);
if (!b)
return false;
_exit_status->store(exit_code);
}
return true;
std::error_code ec;
bool b = wait_for(rel_time, ec);
boost::process::detail::throw_error(ec, "wait_for error");
return b;
}
template< class Clock, class Duration >
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
{
if (!_exited())
{
int exit_code = 0;
auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time);
if (!b)
return false;
_exit_status->store(exit_code);
}
return true;
std::error_code ec;
bool b = wait_until(timeout_time, ec);
boost::process::detail::throw_error(ec, "wait_until error");
return b;
}
bool running(std::error_code & ec) noexcept
{
if (valid() && !_exited())
ec.clear();
if (valid() && !_exited() && !ec)
{
int code;
auto res = boost::process::detail::api::is_running(_child_handle, code, ec);
if (!res && !_exited())
_exit_status->store(code);
int exit_code = 0;
auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec);
if (!ec && !res && !_exited())
_exit_status->store(exit_code);
return res;
}
@@ -175,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
@@ -187,22 +173,15 @@ 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);
}
}
template< class Rep, class Period >
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
{
if (!_exited())
{
int exit_code = 0;
auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time, ec);
if (!b)
return false;
_exit_status->store(exit_code);
}
return true;
return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
}
template< class Clock, class Duration >
@@ -212,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

@@ -31,7 +31,7 @@
extern char **environ;
#endif
#elif defined(BOOST_WINDOWS_API)
#include <boost/detail/winapi/get_last_error.hpp>
#include <boost/winapi/get_last_error.hpp>
#else
#error "System API not supported by boost.process"
#endif
@@ -53,17 +53,21 @@ inline std::error_code get_last_error() noexcept
}
//copied from linux spec.
#if defined (__USE_XOPEN_EXTENDED) && !defined (__USE_XOPEN2K8) || defined( __USE_BSD)
#if (_XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) && !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
#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;
inline std::error_code get_last_error() noexcept
{
return std::error_code(::boost::detail::winapi::GetLastError(), std::system_category());
return std::error_code(::boost::winapi::GetLastError(), std::system_category());
}
#endif
@@ -72,11 +76,27 @@ inline void throw_last_error(const std::string & msg)
throw process_error(get_last_error(), msg);
}
inline void throw_last_error(const char * msg)
{
throw process_error(get_last_error(), msg);
}
inline void throw_last_error()
{
throw process_error(get_last_error());
}
inline void throw_error(const std::error_code& ec)
{
if (ec)
throw process_error(ec);
}
inline void throw_error(const std::error_code& ec, const char* msg)
{
if (ec)
throw process_error(ec, msg);
}
template<typename Char> constexpr Char null_char();
template<> constexpr char null_char<char> (){return '\0';}

View File

@@ -1,75 +1,75 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_HANDLER_HPP_
#ifndef BOOST_PROCESS_DETAIL_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_HANDLER_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/config.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif
namespace boost { namespace process { namespace detail {
namespace boost { namespace process { namespace detail {
//extended handler base.
typedef api::handler_base_ext handler;
//extended handler base.
typedef api::handler_base_ext handler;
template <class Handler>
struct on_setup_ : handler
{
explicit on_setup_(Handler handler) : handler_(handler) {}
template <class Handler>
struct on_setup_ : handler
{
explicit on_setup_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_setup(Executor &e)
{
handler_(e);
}
private:
Handler handler_;
};
template <class Executor>
void on_setup(Executor &e)
{
handler_(e);
}
private:
Handler handler_;
};
template <class Handler>
struct on_error_ : handler
{
explicit on_error_(Handler handler) : handler_(handler) {}
template <class Handler>
struct on_error_ : handler
{
explicit on_error_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_error(Executor &e, const std::error_code &ec)
{
handler_(e, ec);
}
private:
Handler handler_;
};
template <class Executor>
void on_error(Executor &e, const std::error_code &ec)
{
handler_(e, ec);
}
private:
Handler handler_;
};
template <class Handler>
struct on_success_ : handler
{
explicit on_success_(Handler handler) : handler_(handler) {}
template <class Handler>
struct on_success_ : handler
{
explicit on_success_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_success(Executor &e)
{
handler_(e);
}
private:
Handler handler_;
};
template <class Executor>
void on_success(Executor &e)
{
handler_(e);
}
private:
Handler handler_;
};
}
}
}}
}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

View File

@@ -20,34 +20,39 @@ template<typename Allocator>
class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_service;
class io_context;
class executor;
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class signal_set_service;
template <typename SignalSetService>
class basic_signal_set;
typedef basic_signal_set<signal_set_service> signal_set;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
template <typename Executor>
class basic_signal_set;
typedef basic_signal_set<executor> signal_set;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
template <typename Handler>
class basic_yield_context;
namespace posix {
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class stream_descriptor_service;
template <typename StreamDesscriptorService>
class basic_stream_descriptor;
typedef basic_stream_descriptor<stream_descriptor_service> stream_descriptor;
class object_handle_service;
template <typename ObjectHandleService>
class basic_object_handle;
typedef basic_object_handle<object_handle_service> object_handle;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
template <typename Executor>
class basic_stream_descriptor;
typedef basic_stream_descriptor<executor> stream_descriptor;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
} //posix
} //asio

View File

@@ -1,40 +1,40 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#ifndef BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#include <boost/process/detail/posix/handler.hpp>
#include <type_traits>
#include <boost/process/detail/posix/handler.hpp>
#include <type_traits>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct require_io_service {};
struct require_io_context {};
struct async_handler : handler_base_ext, require_io_service
{
};
struct async_handler : handler_base_ext, require_io_context
{
};
template<typename T>
struct is_async_handler : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct does_require_io_service : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_context : std::is_base_of<require_io_context, T> {};
template<typename T>
struct does_require_io_service<T&> : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_context<T&> : std::is_base_of<require_io_context, T> {};
template<typename T>
struct does_require_io_service<const T&> : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_context<const T&> : std::is_base_of<require_io_context, T> {};
}}}}
}}}}
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */

View File

@@ -1,95 +1,111 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/write.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/write.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
#include <boost/process/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_service
{
Buffer & buf;
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context,
::boost::process::detail::uses_handles
{
Buffer & buf;
std::shared_ptr<std::promise<void>> promise;
async_in_buffer operator>(std::future<void> & fut)
{
promise = std::make_shared<std::promise<void>>();
fut = promise->get_future(); return std::move(*this);
}
std::shared_ptr<boost::process::async_pipe> pipe;
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
if (this->promise)
{
auto promise = this->promise;
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)));
}
else
promise->set_value();
});
}
else
boost::asio::async_write(*pipe, buf,
[pipe](const boost::system::error_code&ec, std::size_t size){});
std::move(*pipe).source().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).source().close();
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
}
template <typename Executor>
void on_exec_setup(Executor &exec)
{
if (::dup2(pipe->native_source(), STDIN_FILENO) == -1)
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_source());
}
};
std::shared_ptr<std::promise<void>> promise;
async_in_buffer operator>(std::future<void> & fut)
{
promise = std::make_shared<std::promise<void>>();
fut = promise->get_future(); return std::move(*this);
}
}}}}
std::shared_ptr<boost::process::async_pipe> pipe;
#endif
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor)
{
auto pipe_ = this->pipe;
if (this->promise)
{
auto promise_ = this->promise;
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)));
}
else
promise_->set_value();
});
}
else
boost::asio::async_write(*pipe_, buf,
[pipe_](const boost::system::error_code&, std::size_t){});
std::move(*pipe_).source().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).source().close();
}
template<typename Executor>
void on_setup(Executor & exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
}
std::array<int, 3> get_used_handles()
{
if (pipe)
return {STDIN_FILENO, pipe->native_source(), pipe->native_sink()};
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
return {STDIN_FILENO, STDIN_FILENO, STDIN_FILENO};
}
template <typename Executor>
void on_exec_setup(Executor &exec)
{
if (::dup2(pipe->native_source(), STDIN_FILENO) == -1)
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (pipe->native_source() != STDIN_FILENO)
::close(pipe->native_source());
::close(pipe->native_sink());
}
};
}}}}
#endif

View File

@@ -1,170 +1,187 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/async_pipe.hpp>
#include <istream>
#include <memory>
#include <exception>
#include <future>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/async_pipe.hpp>
#include <istream>
#include <memory>
#include <exception>
#include <future>
#include <array>
#include <boost/process/detail/used_handles.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
{
return ::dup2(handle, STDOUT_FILENO);
}
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
{
return ::dup2(handle, STDOUT_FILENO);
}
inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
{
return ::dup2(handle, STDERR_FILENO);
}
inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
{
return ::dup2(handle, STDERR_FILENO);
}
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
{
if (::dup2(handle, STDOUT_FILENO) == -1)
return -1;
if (::dup2(handle, STDERR_FILENO) == -1)
return -1;
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
{
if (::dup2(handle, STDOUT_FILENO) == -1)
return -1;
if (::dup2(handle, STDERR_FILENO) == -1)
return -1;
return 0;
}
return 0;
}
template<int p1, int p2, typename Buffer>
struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_service
{
Buffer & buf;
template<int p1, int p2, typename Buffer>
struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context,
::boost::process::detail::uses_handles
{
Buffer & buf;
std::shared_ptr<boost::process::async_pipe> pipe;
std::shared_ptr<boost::process::async_pipe> pipe;
std::array<int, 4> get_used_handles()
{
const auto pp1 = p1 != -1 ? p1 : p2;
const auto pp2 = p2 != -1 ? p2 : p1;
if (pipe)
return {pipe->native_source(), pipe->native_sink(), pp1, pp2};
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
return {pp1, pp2, pp1, pp2};
}
async_out_buffer(Buffer & buf) : buf(buf)
{
}
async_out_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t size){});
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t){});
this->pipe = nullptr;
std::move(*pipe).sink().close();
}
this->pipe = nullptr;
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
}
template <typename Executor>
void on_exec_setup(Executor &exec)
{
int res = apply_out_handles(pipe->native_sink(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
if (res == -1)
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
template <typename Executor>
void on_exec_setup(Executor &exec)
{
int res = apply_out_handles(pipe->native_sink(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
if (res == -1)
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_sink());
}
};
::close(pipe->native_sink());
::close(pipe->native_source());
}
};
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_service
{
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context
{
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
std::shared_ptr<boost::process::async_pipe> pipe;
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_future(std::future<Type> & fut)
{
fut = promise->get_future();
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
async_out_future(std::future<Type> & fut)
{
fut = promise->get_future();
}
template <typename Executor>
inline void on_success(Executor &)
{
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)
{
if (ec && (ec.value() != ENOENT))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
{
std::istream is (buffer.get());
Type arg;
arg.resize(buffer->size());
is.read(&*arg.begin(), buffer->size());
promise->set_value(std::move(arg));
}
});
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)));
}
else
{
std::istream is (buffer_.get());
Type arg;
arg.resize(buffer_->size());
is.read(&*arg.begin(), buffer_->size());
promise_->set_value(std::move(arg));
}
});
std::move(*pipe).sink().close();
this->pipe = nullptr;
}
std::move(*pipe_).sink().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
}
template <typename Executor>
void on_exec_setup(Executor &exec)
{
template <typename Executor>
void on_exec_setup(Executor &exec)
{
int res = apply_out_handles(pipe->native_sink(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
if (res == -1)
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
int res = apply_out_handles(pipe->native_sink(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
if (res == -1)
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_sink());
}
::close(pipe->native_sink());
::close(pipe->native_source());
}
};
};
}}}}
}}}}
#endif
#endif

View File

@@ -9,8 +9,10 @@
#include <boost/process/detail/posix/basic_pipe.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/post.hpp>
#include <system_error>
#include <string>
#include <utility>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -22,10 +24,10 @@ public:
typedef int native_handle_type;
typedef ::boost::asio::posix::stream_descriptor handle_type;
inline async_pipe(boost::asio::io_service & ios) : async_pipe(ios, ios) {}
inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {}
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink) : _source(ios_source), _sink(ios_sink)
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink) : _source(ios_source), _sink(ios_sink)
{
int fds[2];
if (::pipe(fds) == -1)
@@ -34,11 +36,11 @@ public:
_source.assign(fds[0]);
_sink .assign(fds[1]);
};
inline async_pipe(boost::asio::io_service & ios, const std::string & name)
inline async_pipe(boost::asio::io_context & ios, const std::string & name)
: async_pipe(ios, ios, name) {}
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & io_sink, const std::string & name);
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & io_sink, const std::string & name);
inline async_pipe(const async_pipe& lhs);
async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink))
{
@@ -47,15 +49,15 @@ public:
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(::boost::asio::io_service & ios_source,
::boost::asio::io_service & ios_sink,
explicit async_pipe(::boost::asio::io_context & ios_source,
::boost::asio::io_context & ios_sink,
const basic_pipe<CharT, Traits> & p)
: _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
{
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p)
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
: async_pipe(ios, ios, p)
{
}
@@ -68,10 +70,10 @@ public:
~async_pipe()
{
if (_sink .native() != -1)
::close(_sink.native());
if (_source.native() != -1)
::close(_source.native());
if (_sink .native_handle() != -1)
::close(_sink.native_handle());
if (_source.native_handle() != -1)
::close(_source.native_handle());
}
template<class CharT, class Traits = std::char_traits<CharT>>
@@ -108,9 +110,9 @@ public:
void async_close()
{
if (_sink.is_open())
_sink.get_io_service(). post([this]{_sink.close();});
boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
if (_source.is_open())
_source.get_io_service().post([this]{_source.close();});
boost::asio::post(_source.get_executor(), [this]{_source.close();});
}
template<typename MutableBufferSequence>
@@ -124,8 +126,20 @@ public:
return _sink.write_some(buffers);
}
native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native();}
native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native();}
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();}
template<typename MutableBufferSequence,
typename ReadHandler>
@@ -135,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,
@@ -146,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));
}
@@ -156,32 +170,32 @@ public:
handle_type && sink() && { return std::move(_sink); }
handle_type && source()&& { return std::move(_source); }
handle_type source(::boost::asio::io_service& ios) &&
handle_type source(::boost::asio::io_context& ios) &&
{
::boost::asio::posix::stream_descriptor stolen(ios, _source.release());
return stolen;
}
handle_type sink (::boost::asio::io_service& ios) &&
handle_type sink (::boost::asio::io_context& ios) &&
{
::boost::asio::posix::stream_descriptor stolen(ios, _sink.release());
return stolen;
}
handle_type source(::boost::asio::io_service& ios) const &
handle_type source(::boost::asio::io_context& ios) const &
{
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in));
}
handle_type sink (::boost::asio::io_service& ios) const &
handle_type sink (::boost::asio::io_context& ios) const &
{
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in));
}
};
async_pipe::async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
async_pipe::async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
const std::string & name) : _source(ios_source), _sink(ios_sink)
{
auto fifo = mkfifo(name.c_str(), 0666 );
@@ -205,19 +219,19 @@ async_pipe::async_pipe(boost::asio::io_service & ios_source,
}
async_pipe::async_pipe(const async_pipe & p) :
_source(const_cast<async_pipe&>(p)._source.get_io_service()),
_sink( const_cast<async_pipe&>(p)._sink.get_io_service())
_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.
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
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();
if (source_in == -1)
_source.assign(-1);
else
{
_source.assign(::dup(source_in));
if (_source.native()== -1)
if (_source.native_handle()== -1)
::boost::process::detail::throw_last_error("dup()");
}
@@ -226,7 +240,7 @@ async_pipe::async_pipe(const async_pipe & p) :
else
{
_sink.assign(::dup(sink_in));
if (_sink.native() == -1)
if (_sink.native_handle() == -1)
::boost::process::detail::throw_last_error("dup()");
}
}
@@ -237,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();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
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
@@ -264,16 +278,8 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
async_pipe& async_pipe::operator=(async_pipe && lhs)
{
if (_source.native_handle() == -1)
::close(_source.native());
if (_sink.native_handle() == -1)
::close(_sink.native());
_source.assign(lhs._source.native_handle());
_sink .assign(lhs._sink .native_handle());
lhs._source.assign(-1);
lhs._sink .assign(-1);
std::swap(_source, lhs._source);
std::swap(_sink, lhs._sink);
return *this;
}
@@ -284,8 +290,8 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
int sink;
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
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();
if (source_in == -1)

View File

@@ -118,12 +118,8 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
else
exec.exe = &exe.front();
if (!args.empty())
{
cmd_impl = make_cmd();
exec.cmd_line = cmd_impl.data();
}
cmd_impl = make_cmd();
exec.cmd_line = cmd_impl.data();
}
static exe_cmd_init exe_args(std::string && exe, std::vector<std::string> && args) {return exe_cmd_init(std::move(exe), std::move(args));}
static exe_cmd_init cmd (std::string && cmd)
@@ -163,8 +159,10 @@ std::vector<char*> exe_cmd_init<char>::make_cmd()
if (!exe.empty())
vec.push_back(&exe.front());
for (auto & v : args)
vec.push_back(&v.front());
if (!args.empty()) {
for (auto & v : args)
vec.push_back(&v.front());
}
vec.push_back(nullptr);

View File

@@ -29,7 +29,7 @@ class basic_pipe
int _sink = -1;
public:
explicit basic_pipe(int source, int sink) : _source(source), _sink(sink) {}
explicit basic_pipe(int source, int sink, const std::string & name) : _source(source), _sink(sink) {}
explicit basic_pipe(int source, int sink, const std::string&) : _source(source), _sink(sink) {}
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
@@ -97,7 +97,7 @@ public:
return read_len;
}
bool is_open()
bool is_open() const
{
return (_source != -1) ||
(_sink != -1);
@@ -105,8 +105,10 @@ public:
void close()
{
::close(_source);
::close(_sink);
if (_source != -1)
::close(_source);
if (_sink != -1)
::close(_sink);
_source = -1;
_sink = -1;
}

View File

@@ -44,7 +44,7 @@ struct child_handle
return pid;
}
bool in_group() const {return true;}
bool in_group(std::error_code &ec) const noexcept {return true;}
bool in_group(std::error_code&) const noexcept {return true;}
typedef int process_handle_t;
process_handle_t process_handle() const { return pid; }

View File

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

View File

@@ -10,8 +10,9 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <array>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -20,6 +21,8 @@ struct close_out : handler_base_ext
{
template <class Executor>
inline void on_exec_setup(Executor &e) const;
std::array<int, 2> get_used_handles() {return {p1 != -1 ? p1 : p2, p2 != -1 ? p2 : p1};}
};
template<>

View File

@@ -1,322 +1,322 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
#ifndef BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/process/detail/config.hpp>
#include <algorithm>
#include <cstdlib>
#include <boost/process/locale.hpp>
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/process/detail/config.hpp>
#include <algorithm>
#include <cstdlib>
#include <boost/process/locale.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Char>
class native_environment_impl
{
static std::vector<std::basic_string<Char>> _load()
{
std::vector<std::basic_string<Char>> val;
auto p = environ;
while (*p != nullptr)
{
std::string str = *p;
val.push_back(::boost::process::detail::convert(str));
p++;
}
return val;
}
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & vec)
{
std::vector<Char*> val;
val.resize(vec.size() + 1);
std::transform(vec.begin(), vec.end(), val.begin(),
[](std::basic_string<Char> & str)
{
return &str.front();
});
val.back() = nullptr;
return val;
}
std::vector<std::basic_string<Char>> _buffer = _load();
std::vector<Char*> _impl = _load_var(_buffer);
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
template<typename Char>
class native_environment_impl
{
static std::vector<std::basic_string<Char>> _load()
{
std::vector<std::basic_string<Char>> val;
auto p = environ;
while (*p != nullptr)
{
std::string str = *p;
val.push_back(::boost::process::detail::convert(str));
p++;
}
return val;
}
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & vec)
{
std::vector<Char*> val;
val.resize(vec.size() + 1);
std::transform(vec.begin(), vec.end(), val.begin(),
[](std::basic_string<Char> & str)
{
return &str.front();
});
val.back() = nullptr;
return val;
}
std::vector<std::basic_string<Char>> _buffer = _load();
std::vector<Char*> _impl = _load_var(_buffer);
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
void reload()
{
_buffer = _load();
_impl = _load_var(_buffer);
}
void reload()
{
_buffer = _load();
_impl = _load_var(_buffer);
}
string_type get(const pointer_type id) { return get(string_type(id)); }
void set(const pointer_type id, const pointer_type value)
{
set(string_type(id), string_type(value));
}
void reset(const pointer_type id) { reset(string_type(id)); }
string_type get(const pointer_type id) { return get(string_type(id)); }
void set(const pointer_type id, const pointer_type value)
{
set(string_type(id), string_type(value));
}
void reset(const pointer_type id) { reset(string_type(id)); }
string_type get(const string_type & id)
{
std::string id_c = ::boost::process::detail::convert(id);
std::string g = ::getenv(id_c.c_str());
return ::boost::process::detail::convert(g.c_str());
}
void set(const string_type & id, const string_type & value)
{
std::string id_c = ::boost::process::detail::convert(id.c_str());
std::string value_c = ::boost::process::detail::convert(value.c_str());
auto res = ::setenv(id_c.c_str(), value_c.c_str(), true);
if (res != 0)
boost::process::detail::throw_last_error();
}
void reset(const string_type & id)
{
std::string id_c = ::boost::process::detail::convert(id.c_str());
auto res = ::unsetenv(id_c.c_str());
if (res != 0)
::boost::process::detail::throw_last_error();
}
string_type get(const string_type & id)
{
std::string id_c = ::boost::process::detail::convert(id);
std::string g = ::getenv(id_c.c_str());
return ::boost::process::detail::convert(g.c_str());
}
void set(const string_type & id, const string_type & value)
{
std::string id_c = ::boost::process::detail::convert(id.c_str());
std::string value_c = ::boost::process::detail::convert(value.c_str());
auto res = ::setenv(id_c.c_str(), value_c.c_str(), true);
if (res != 0)
boost::process::detail::throw_last_error();
}
void reset(const string_type & id)
{
std::string id_c = ::boost::process::detail::convert(id.c_str());
auto res = ::unsetenv(id_c.c_str());
if (res != 0)
::boost::process::detail::throw_last_error();
}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = _impl.data();
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = _impl.data();
native_handle_type native_handle() const {return environ;}
};
native_handle_type native_handle() const {return environ;}
};
template<>
class native_environment_impl<char>
{
public:
using char_type = char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
template<>
class native_environment_impl<char>
{
public:
using char_type = char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
void reload() {this->_env_impl = ::environ;}
void reload() {this->_env_impl = ::environ;}
string_type get(const pointer_type id) { return getenv(id); }
void set(const pointer_type id, const pointer_type value)
{
auto res = ::setenv(id, value, 1);
if (res != 0)
boost::process::detail::throw_last_error();
reload();
}
void reset(const pointer_type id)
{
auto res = ::unsetenv(id);
if (res != 0)
boost::process::detail::throw_last_error();
reload();
}
string_type get(const pointer_type id) { return getenv(id); }
void set(const pointer_type id, const pointer_type value)
{
auto res = ::setenv(id, value, 1);
if (res != 0)
boost::process::detail::throw_last_error();
reload();
}
void reset(const pointer_type id)
{
auto res = ::unsetenv(id);
if (res != 0)
boost::process::detail::throw_last_error();
reload();
}
string_type get(const string_type & id) {return get(id.c_str());}
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
void reset(const string_type & id) {reset(id.c_str());}
string_type get(const string_type & id) {return get(id.c_str());}
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
void reset(const string_type & id) {reset(id.c_str());}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = environ;
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = environ;
native_handle_type native_handle() const {return ::environ;}
};
native_handle_type native_handle() const {return ::environ;}
};
template<typename Char>
struct basic_environment_impl
{
std::vector<std::basic_string<Char>> _data {};
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & data);
std::vector<Char*> _env_arr{_load_var(_data)};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = Char**;
void reload()
{
_env_arr = _load_var(_data);
_env_impl = _env_arr.data();
}
template<typename Char>
struct basic_environment_impl
{
std::vector<std::basic_string<Char>> _data {};
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & data);
std::vector<Char*> _env_arr{_load_var(_data)};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = Char**;
void reload()
{
_env_arr = _load_var(_data);
_env_impl = _env_arr.data();
}
string_type get(const pointer_type id) {return get(string_type(id));}
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
void reset(const pointer_type id) {reset(string_type(id));}
string_type get(const pointer_type id) {return get(string_type(id));}
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
void reset(const pointer_type id) {reset(string_type(id));}
string_type get(const string_type & id);
void set(const string_type & id, const string_type & value);
void reset(const string_type & id);
string_type get(const string_type & id);
void set(const string_type & id, const string_type & value);
void reset(const string_type & id);
basic_environment_impl(const native_environment_impl<Char> & nei);
basic_environment_impl() = default;
basic_environment_impl(const basic_environment_impl& rhs)
: _data(rhs._data)
{
basic_environment_impl(const native_environment_impl<Char> & nei);
basic_environment_impl() = default;
basic_environment_impl(const basic_environment_impl& rhs)
: _data(rhs._data)
{
}
basic_environment_impl(basic_environment_impl && ) = default;
basic_environment_impl & operator=(const basic_environment_impl& rhs)
{
_data = rhs._data;
_env_arr = _load_var(_data);
_env_impl = &*_env_arr.begin();
return *this;
}
basic_environment_impl & operator=(basic_environment_impl && ) = default;
}
basic_environment_impl(basic_environment_impl && ) = default;
basic_environment_impl & operator=(const basic_environment_impl& rhs)
{
_data = rhs._data;
_env_arr = _load_var(_data);
_env_impl = &*_env_arr.begin();
return *this;
}
basic_environment_impl & operator=(basic_environment_impl && ) = default;
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(rhs._data.size())
{
std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(),
[&](const std::basic_string<CharR> & st)
{
return ::boost::process::detail::convert(st, cv);
}
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(rhs._data.size())
{
std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(),
[&](const std::basic_string<CharR> & st)
{
return ::boost::process::detail::convert(st, cv);
}
);
reload();
}
);
reload();
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
}
Char ** _env_impl = &*_env_arr.data();
Char ** _env_impl = &*_env_arr.data();
native_handle_type native_handle() const {return &_data.front();}
};
native_handle_type native_handle() const {return &_data.front();}
};
template<typename Char>
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
{
auto beg = nei.native_handle();
template<typename Char>
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
{
auto beg = nei.native_handle();
auto end = beg;
while (*end != nullptr)
end++;
this->_data.assign(beg, end);
reload();
}
auto end = beg;
while (*end != nullptr)
end++;
this->_data.assign(beg, end);
reload();
}
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr == _data.end())
{
return "";
}
else return
itr->data() + id.size(); //id=Thingy -> +2 points to T
}
if (itr == _data.end())
{
return "";
}
else return
itr->data() + id.size(); //id=Thingy -> +2 points to T
}
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr != _data.end())
*itr = id + equal_sign<Char>() + value;
else
_data.push_back(id + equal_sign<Char>() + value);
if (itr != _data.end())
*itr = id + equal_sign<Char>() + value;
else
_data.push_back(id + equal_sign<Char>() + value);
reload();
}
reload();
}
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr != _data.end())
{
_data.erase(itr);//and remove it
}
reload();
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr != _data.end())
{
_data.erase(itr);//and remove it
}
reload();
}
}
template<typename Char>
std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basic_string<Char>> & data)
{
std::vector<Char*> ret;
ret.reserve(data.size() +1);
template<typename Char>
std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basic_string<Char>> & data)
{
std::vector<Char*> ret;
ret.reserve(data.size() +1);
for (auto & val : data)
ret.push_back(&val.front());
for (auto & val : data)
ret.push_back(&val.front());
ret.push_back(nullptr);
return ret;
}
ret.push_back(nullptr);
return ret;
}
template<typename T> constexpr T env_seperator();
template<> constexpr char env_seperator() {return ':'; }
template<> constexpr wchar_t env_seperator() {return L':'; }
template<typename T> constexpr T env_seperator();
template<> constexpr char env_seperator() {return ':'; }
template<> constexpr wchar_t env_seperator() {return L':'; }
typedef int native_handle_t;
typedef int native_handle_t;
inline int get_id() {return getpid(); }
inline int native_handle() {return getpid(); }
inline int get_id() {return getpid(); }
inline int native_handle() {return getpid(); }
}
}
}
}
}
}
}
}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */

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);
}
@@ -180,7 +145,7 @@ template<typename Sequence>
class executor
{
template<typename HasHandler, typename UseVFork>
void internal_error_handle(const std::error_code &ec, const char* msg, HasHandler, boost::mpl::true_, UseVFork) {}
void internal_error_handle(const std::error_code&, const char*, HasHandler, boost::mpl::true_, UseVFork) {}
int _pipe_sink = -1;
@@ -233,7 +198,8 @@ class executor
void check_error(boost::mpl::true_) {};
void check_error(boost::mpl::false_)
{
throw process_error(_ec, _msg);
if (_ec)
throw process_error(_ec, _msg);
}
typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler;
@@ -292,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;
@@ -337,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)
@@ -348,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);
@@ -367,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(_pipe_sink);
::close(p.p[1]);
_exit(EXIT_FAILURE);
return child();
}
::close(p.p[1]);
p.p[1] = -1;
_read_error(p.p[0]);
}
if (_ec)
{
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)
{
@@ -484,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)
@@ -499,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

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

View File

@@ -1,76 +1,76 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
#include <fcntl.h>
#include <string>
#include <boost/filesystem/path.hpp>
#include <fcntl.h>
#include <string>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct file_descriptor
{
enum mode_t
{
read = 1,
write = 2,
read_write = 3
};
struct file_descriptor
{
enum mode_t
{
read = 1,
write = 2,
read_write = 3
};
file_descriptor() = default;
explicit file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
file_descriptor() = default;
explicit file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
explicit file_descriptor(const std::string & path , mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
explicit file_descriptor(const std::string & path , mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
explicit file_descriptor(const char* path, mode_t mode = read_write)
: _handle(create_file(path, mode))
{
explicit file_descriptor(const char* path, mode_t mode = read_write)
: _handle(create_file(path, mode))
{
}
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
~file_descriptor()
{
if (_handle != -1)
::close(_handle);
}
~file_descriptor()
{
if (_handle != -1)
::close(_handle);
}
int handle() const { return _handle;}
int handle() const { return _handle;}
private:
static int create_file(const char* name, mode_t mode )
{
switch(mode)
{
case read:
return ::open(name, O_RDONLY);
case write:
return ::open(name, O_WRONLY | O_CREAT, 0660);
case read_write:
return ::open(name, O_RDWR | O_CREAT, 0660);
default:
return -1;
}
}
private:
static int create_file(const char* name, mode_t mode )
{
switch(mode)
{
case read:
return ::open(name, O_RDONLY);
case write:
return ::open(name, O_WRONLY | O_CREAT, 0660);
case read_write:
return ::open(name, O_RDWR | O_CREAT, 0660);
default:
return -1;
}
}
int _handle = -1;
};
int _handle = -1;
};
}}}}
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */

View File

@@ -1,40 +1,46 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <cstdio>
#include <unistd.h>
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <cstdio>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct file_in : handler_base_ext
{
file_descriptor file;
int handle = file.handle();
struct file_in : handler_base_ext, ::boost::process::detail::uses_handles
{
file_descriptor file;
int handle = file.handle();
template<typename T>
file_in(T&& t) : file(std::forward<T>(t)) {}
file_in(FILE * f) : handle(fileno(f)) {}
std::array<int, 2> get_used_handles()
{
return {STDIN_FILENO, handle};
}
template <class WindowsExecutor>
void on_exec_setup(WindowsExecutor &e) const
{
if (::dup2(handle, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
template<typename T>
file_in(T&& t) : file(std::forward<T>(t)) {}
file_in(FILE * f) : handle(fileno(f)) {}
}}}}
template <class WindowsExecutor>
void on_exec_setup(WindowsExecutor &e) const
{
if (::dup2(handle, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
#endif
}}}}
#endif

View File

@@ -1,65 +1,73 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_FILE_OUT_HPP
#define BOOST_PROCESS_POSIX_FILE_OUT_HPP
#ifndef BOOST_PROCESS_POSIX_FILE_OUT_HPP
#define BOOST_PROCESS_POSIX_FILE_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <unistd.h>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct file_out : handler_base_ext
{
file_descriptor file;
int handle = file.handle();
template<int p1, int p2>
struct file_out : handler_base_ext, ::boost::process::detail::uses_handles
{
file_descriptor file;
int handle = file.handle();
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write), handle(file.handle()) {}
file_out(FILE * f) : handle(fileno(f)) {}
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write), handle(file.handle()) {}
file_out(FILE * f) : handle(fileno(f)) {}
std::array<int, 3> get_used_handles()
{
const auto pp1 = p1 != -1 ? p1 : p2;
const auto pp2 = p2 != -1 ? p2 : p1;
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
return {handle, pp1, pp2};
}
template<>
template<typename Executor>
void file_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void file_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void file_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void file_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
template<>
template<typename Executor>
void file_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
template<>
template<typename Executor>
void file_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}}}}
}
#endif
}}}}
#endif

View File

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

View File

@@ -28,7 +28,7 @@ struct group_ref : handler_base_ext
{}
template <class Executor>
void on_exec_setup(Executor& exec) const
void on_exec_setup(Executor&) const
{
if (grp.grp == -1)
::setpgid(0, 0);

View File

@@ -1,74 +1,74 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
#ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
//does not extend anything.
struct handler_base_ext : handler_base
{
template<typename Executor>
void on_fork_error (Executor &, const std::error_code&) const {}
//does not extend anything.
struct handler_base_ext : handler_base
{
template<typename Executor>
void on_fork_error (Executor &, const std::error_code&) const {}
template<typename Executor>
void on_exec_setup (Executor &) const {}
template<typename Executor>
void on_exec_setup (Executor &) const {}
template<typename Executor>
void on_exec_error (Executor &, const std::error_code&) const {}
};
template<typename Executor>
void on_exec_error (Executor &, const std::error_code&) const {}
};
template <class Handler>
struct on_fork_error_ : handler_base_ext
{
explicit on_fork_error_(Handler handler) : handler_(handler) {}
template <class Handler>
struct on_fork_error_ : handler_base_ext
{
explicit on_fork_error_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_fork_error(Executor &e, const std::error_code &ec) const
{
handler_(e, ec);
}
private:
Handler handler_;
};
template <class Executor>
void on_fork_error(Executor &e, const std::error_code &ec) const
{
handler_(e, ec);
}
private:
Handler handler_;
};
template <class Handler>
struct on_exec_setup_ : handler_base_ext
{
explicit on_exec_setup_(Handler handler) : handler_(handler) {}
template <class Handler>
struct on_exec_setup_ : handler_base_ext
{
explicit on_exec_setup_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_exec_setup(Executor &e) const
{
handler_(e);
}
private:
Handler handler_;
};
template <class Executor>
void on_exec_setup(Executor &e) const
{
handler_(e);
}
private:
Handler handler_;
};
template <class Handler>
struct on_exec_error_ : handler_base_ext
{
explicit on_exec_error_(Handler handler) : handler_(handler) {}
template <class Handler>
struct on_exec_error_ : handler_base_ext
{
explicit on_exec_error_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_exec_error(Executor &e, const std::error_code &ec) const
{
handler_(e, ec);
}
private:
Handler handler_;
};
template <class Executor>
void on_exec_error(Executor &e, const std::error_code &ec) const
{
handler_(e, ec);
}
private:
Handler handler_;
};
}}}}
}}}}
#endif /* BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_ */

View File

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

View File

@@ -1,155 +1,125 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_IO_SERVICE_REF_HPP_
#define BOOST_PROCESS_POSIX_IO_SERVICE_REF_HPP_
#ifndef BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_
#define BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <functional>
#include <type_traits>
#include <memory>
#include <vector>
#include <sys/wait.h>
#include <boost/process/detail/posix/sigchld_service.hpp>
#include <boost/process/detail/posix/is_running.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
#include <functional>
#include <type_traits>
#include <memory>
#include <vector>
#include <sys/wait.h>
template<typename Executor>
struct on_exit_handler_transformer
{
Executor & exec;
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
template<typename Sig>
struct result;
namespace boost { namespace process { namespace detail { namespace posix {
template<typename T>
struct result<on_exit_handler_transformer<Executor>(T&)>
{
typedef typename T::on_exit_handler_t type;
};
template<typename Executor>
struct on_exit_handler_transformer
{
Executor & exec;
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
template<typename Sig>
struct result;
template<typename T>
auto operator()(T& t) const -> typename T::on_exit_handler_t
{
return t.on_exit_handler(exec);
}
};
template<typename T>
struct result<on_exit_handler_transformer<Executor>(T&)>
{
typedef typename T::on_exit_handler_t type;
};
template<typename Executor>
struct async_handler_collector
{
Executor & exec;
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
template<typename T>
auto operator()(T& t) const -> typename T::on_exit_handler_t
{
return t.on_exit_handler(exec);
}
};
template<typename Executor>
struct async_handler_collector
{
Executor & exec;
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
async_handler_collector(Executor & exec,
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
: exec(exec), handlers(handlers) {}
async_handler_collector(Executor & exec,
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
: exec(exec), handlers(handlers) {}
template<typename T>
void operator()(T & t) const
{
handlers.push_back(t.on_exit_handler(exec));
};
};
template<typename T>
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.
struct io_service_ref : handler_base_ext
{
io_service_ref(boost::asio::io_service & ios) : ios(ios)
{
//Also set's up waiting for the exit, so it can close async stuff.
struct io_context_ref : handler_base_ext
{
io_context_ref(boost::asio::io_context & ios) : ios(ios)
{
}
boost::asio::io_service &get() {return ios;};
}
boost::asio::io_context &get() {return ios;};
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<
typename std::remove_reference< boost::mpl::_ > ::type
>>(exec.seq);
boost::asio::signal_set *signal_p = nullptr;
//ok, check if there are actually any.
if (boost::fusion::empty(asyncs))
return;
template <class Executor>
void on_setup(Executor& exec)
{
//must be on the heap so I can move it into the lambda.
auto asyncs = boost::fusion::filter_if<
is_async_handler<
typename std::remove_reference< boost::mpl::_ > ::type
>>(exec.seq);
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
funcs.reserve(boost::fusion::size(asyncs));
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
//ok, check if there are actually any.
if (boost::fusion::empty(asyncs))
return;
auto & es = exec.exit_status;
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
funcs.reserve(boost::fusion::size(asyncs));
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
auto wh = [funcs, es](int val, const std::error_code & ec)
{
es->store(val);
for (auto & func : funcs)
func(::boost::process::detail::posix::eval_exit_status(val), ec);
};
wait_handler wh(std::move(funcs), ios, exec.exit_status);
sigchld_service.async_wait(exec.pid, std::move(wh));
}
signal_p = wh.signal_.get();
signal_p->async_wait(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 & exec, const std::error_code & ec) const
{
if (signal_p != nullptr)
{
boost::system::error_code ec;
signal_p->cancel(ec);
}
}
template <class Executor>
void on_error(Executor&, const std::error_code &) const {/*ios.notify_fork(boost::asio::io_context::fork_parent);*/}
struct wait_handler
{
std::shared_ptr<boost::asio::signal_set> signal_;
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
std::shared_ptr<std::atomic<int>> exit_status;
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);
};
wait_handler(const wait_handler & ) = default;
wait_handler(wait_handler && ) = default;
wait_handler(
std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
boost::asio::io_service & ios,
const std::shared_ptr<std::atomic<int>> &exit_status)
: signal_(new boost::asio::signal_set(ios, SIGCHLD)),
funcs(std::move(funcs)),
exit_status(exit_status)
{
}}}}
}
void operator()(const boost::system::error_code & ec_in, int /*signal*/)
{
if (ec_in.value() == boost::asio::error::operation_aborted)
return;
int status;
::wait(&status);
std::error_code ec(ec_in.value(), std::system_category());
int val = WEXITSTATUS(status);
exit_status->store(status);
for (auto & func : funcs)
func(val, ec);
}
};
private:
boost::asio::io_service &ios;
};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
#endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */

View File

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

View File

@@ -1,35 +1,43 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#ifndef BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
#include <boost/process/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct null_in : handler_base_ext
{
file_descriptor source{"/dev/null", file_descriptor::read};
struct null_in : handler_base_ext, ::boost::process::detail::uses_handles
{
file_descriptor source{"/dev/null", file_descriptor::read};
public:
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source.handle(), STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
std::array<int, 2> get_used_handles()
{
return {STDIN_FILENO, source.handle()};
}
}}}}
#endif
public:
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source.handle(), STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
}}}}
#endif

View File

@@ -1,58 +1,68 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#ifndef BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <unistd.h>
#include <array>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct null_out : handler_base_ext
{
file_descriptor sink{"/dev/null", file_descriptor::write};
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<int p1, int p2>
struct null_out : handler_base_ext, ::boost::process::detail::uses_handles
{
file_descriptor sink{"/dev/null", file_descriptor::write};
template <typename Executor>
void on_exec_setup(Executor &e) const;
template<>
template<typename Executor>
void null_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
std::array<int, 3> get_used_handles()
{
const auto pp1 = p1 != -1 ? p1 : p2;
const auto pp2 = p2 != -1 ? p2 : p1;
template<>
template<typename Executor>
void null_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
return {sink.handle(), pp1, pp2};
}
};
template<>
template<typename Executor>
void null_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
template<>
template<typename Executor>
void null_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void null_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
}}}}
template<>
template<typename Executor>
void null_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
#endif
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
}}}}
#endif

View File

@@ -1,35 +1,35 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <system_error>
#include <functional>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <system_error>
#include <functional>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
struct on_exit_ : boost::process::detail::posix::async_handler
{
std::function<void(int, const std::error_code&)> handler;
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
{
struct on_exit_ : boost::process::detail::posix::async_handler
{
std::function<void(int, const std::error_code&)> handler;
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
{
}
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
{
return handler;
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
{
return handler;
};
};
}
};
}}}}
#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */
}}}}
#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */

View File

@@ -1,90 +1,98 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_PIPE_IN_HPP
#define BOOST_PROCESS_POSIX_PIPE_IN_HPP
#ifndef BOOST_PROCESS_POSIX_PIPE_IN_HPP
#define BOOST_PROCESS_POSIX_PIPE_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
#include <boost/process/detail/used_handles.hpp>
#include <array>
namespace boost { namespace process { namespace detail { namespace posix {
struct pipe_in : handler_base_ext, ::boost::process::detail::uses_handles
{
int source;
int sink; //opposite end
pipe_in(int sink, int source) : source(source), sink(sink) {}
std::array<int, 3> get_used_handles()
{
return {STDIN_FILENO, source, sink};
}
namespace boost { namespace process { namespace detail { namespace posix {
template<typename T>
pipe_in(T & p) : source(p.native_source()), sink(p.native_sink())
{
p.assign_source(-1);
}
struct pipe_in : handler_base_ext
{
int source;
int sink; //opposite end
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(source);
}
pipe_in(int sink, int source) : source(source), sink(sink) {}
template<typename Executor>
void on_success(Executor &) const
{
::close(source);
}
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (source != STDIN_FILENO)
::close(source);
template<typename T>
pipe_in(T & p) : source(p.native_source()), sink(p.native_sink())
{
p.assign_source(-1);
}
::close(sink);
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(source);
}
};
template<typename Executor>
void on_success(Executor &) const
{
::close(source);
}
class async_pipe;
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(source);
::close(sink);
}
struct async_pipe_in : public pipe_in
{
async_pipe &pipe;
};
template<typename AsyncPipe>
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_sink(), p.native_source()), pipe(p)
{
}
class async_pipe;
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).source().close(ec);
}
struct async_pipe_in : public pipe_in
{
async_pipe &pipe;
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename AsyncPipe>
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_sink(), p.native_source()), pipe(p)
{
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).source().close(ec);
}
}}}}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
}}}}
#endif
#endif

View File

@@ -1,116 +1,120 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#ifndef BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct pipe_out : handler_base_ext
{
int sink;
int source; //opposite end
template<int p1, int p2>
struct pipe_out : handler_base_ext
{
int sink;
int source; //opposite end
pipe_out(int sink, int source) : sink(sink), source(source) {}
pipe_out(int sink, int source) : sink(sink), source(source) {}
template<typename T>
pipe_out(T & p) : sink(p.native_sink()), source(p.native_source())
{
p.assign_sink(-1);
}
template<typename T>
pipe_out(T & p) : sink(p.native_sink()), source(p.native_source())
{
p.assign_sink(-1);
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(sink);
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(sink);
}
template<typename Executor>
void on_success(Executor &) const
{
::close(sink);
}
template<typename Executor>
void on_success(Executor &) const
{
::close(sink);
}
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void pipe_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup3() failed");
::close(sink);
::close(source);
}
template<>
template<typename Executor>
void pipe_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
template<>
template<typename Executor>
void pipe_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
}
if (sink != STDOUT_FILENO)
::close(sink);
::close(source);
}
template<>
template<typename Executor>
void pipe_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
}
template<>
template<typename Executor>
void pipe_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
class async_pipe;
if (sink != STDOUT_FILENO)
::close(sink);
::close(source);
}
template<int p1, int p2>
struct async_pipe_out : public pipe_out<p1, p2>
{
async_pipe &pipe;
template<typename AsyncPipe>
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink(), p.native_source()), pipe(p)
{
}
template<>
template<typename Executor>
void pipe_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if ((sink != STDOUT_FILENO) && (sink != STDERR_FILENO))
::close(sink);
}
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).sink().close(ec);
}
class async_pipe;
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<int p1, int p2>
struct async_pipe_out : public pipe_out<p1, p2>
{
async_pipe &pipe;
template<typename AsyncPipe>
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink(), p.native_source()), pipe(p)
{
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).sink().close(ec);
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
}}}}
}}}}
#endif
#endif

View File

@@ -24,11 +24,12 @@ inline boost::filesystem::path search_path(
const boost::filesystem::path &filename,
const std::vector<boost::filesystem::path> &path)
{
std::string result;
for (const boost::filesystem::path & pp : path)
{
auto p = pp / filename;
if (!::access(p.c_str(), X_OK))
boost::system::error_code ec;
bool file = boost::filesystem::is_regular_file(p, ec);
if (!ec && file && ::access(p.c_str(), X_OK) == 0)
return p;
}
return "";

View File

@@ -0,0 +1,135 @@
// Copyright (c) 2017 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/asio/strand.hpp>
#include <boost/optional.hpp>
#include <signal.h>
#include <functional>
#include <sys/wait.h>
namespace boost { namespace process { namespace detail { namespace posix {
class sigchld_service : public boost::asio::detail::service_base<sigchld_service>
{
boost::asio::io_context::strand _strand{get_io_context()};
boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
inline void _handle_signal(const boost::system::error_code & ec);
public:
sigchld_service(boost::asio::io_context & io_context)
: boost::asio::detail::service_base<sigchld_service>(io_context)
{
}
template <typename SignalHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(SignalHandler,
void (int, std::error_code))
async_wait(::pid_t pid, SignalHandler && handler)
{
boost::asio::async_completion<
SignalHandler, void(boost::system::error_code)> init{handler};
auto & h = init.completion_handler;
boost::asio::dispatch(
_strand,
[this, pid, h]
{
//check if the child actually is running first
int status;
auto pid_res = ::waitpid(pid, &status, WNOHANG);
if (pid_res < 0)
h(-1, get_last_error());
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
h(status, {}); //successfully exited already
else //still running
{
if (_receivers.empty())
_signal_set.async_wait(
[this](const boost::system::error_code &ec, int)
{
boost::asio::dispatch(_strand, [this, ec]{this->_handle_signal(ec);});
});
_receivers.emplace_back(pid, h);
}
});
return init.result.get();
}
void shutdown() override
{
_receivers.clear();
}
void cancel()
{
_signal_set.cancel();
}
void cancel(boost::system::error_code & ec)
{
_signal_set.cancel(ec);
}
};
void sigchld_service::_handle_signal(const boost::system::error_code & ec)
{
std::error_code ec_{ec.value(), std::system_category()};
if (ec_)
{
for (auto & r : _receivers)
r.second(-1, ec_);
return;
}
for (auto & r : _receivers) {
int status;
int pid = ::waitpid(r.first, &status, WNOHANG);
if (pid < 0) {
// error (eg: the process no longer exists)
r.second(-1, get_last_error());
r.first = 0; // mark for deletion
} else if (pid == r.first) {
r.second(status, ec_);
r.first = 0; // mark for deletion
}
// otherwise the process is still around
}
_receivers.erase(std::remove_if(_receivers.begin(), _receivers.end(),
[](const std::pair<::pid_t, std::function<void(int, std::error_code)>> & p)
{
return p.first == 0;
}),
_receivers.end());
if (!_receivers.empty())
{
_signal_set.async_wait(
[this](const boost::system::error_code & ec, int)
{
boost::asio::post(_strand, [this, ec]{this->_handle_signal(ec);});
});
}
}
}
}
}
}
#endif

View File

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

View File

@@ -15,23 +15,10 @@
#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 child_handle &p, int & exit_code)
{
pid_t ret;
int status;
do
{
ret = ::waitpid(p.pid, &status, 0);
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
exit_code = status;
}
inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
pid_t ret;
@@ -41,8 +28,9 @@ 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)));
while (((ret == -1) && (errno == EINTR)) ||
(ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
@@ -50,45 +38,181 @@ inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) no
ec.clear();
exit_code = status;
}
}
template< class Rep, class Period >
inline bool wait_for(
inline void wait(const child_handle &p, int & exit_code) noexcept
{
std::error_code ec;
wait(p, exit_code, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait");
}
template< class Clock, class Duration >
inline bool wait_until(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time)
const std::chrono::time_point<Clock, Duration>& time_out,
std::error_code & ec) noexcept
{
::sigset_t sigset;
pid_t ret;
int status;
//I need to set the signal, because it might be ignore / default, in which case sigwait might not work.
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
using _signal_t = void(*)(int);
static thread_local _signal_t sigchld_handler = SIG_DFL;
bool time_out_occured = false;
struct signal_interceptor_t
{
static void handler_func(int val)
{
if ((sigchld_handler != SIG_DFL) && (sigchld_handler != SIG_IGN))
sigchld_handler(val);
}
signal_interceptor_t() { sigchld_handler = ::signal(SIGCHLD, &handler_func); }
~signal_interceptor_t() { ::signal(SIGCHLD, sigchld_handler); sigchld_handler = SIG_DFL;}
} signal_interceptor{};
if (sigemptyset(&sigset) != 0)
{
ec = get_last_error();
return false;
}
if (sigaddset(&sigset, SIGCHLD) != 0)
{
ec = get_last_error();
return false;
}
auto get_timespec =
[](const Duration & dur)
{
::timespec ts;
ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(dur).count() % 1000000000;
return ts;
};
int ret;
int status{0};
struct ::sigaction old_sig;
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
{
ec = get_last_error();
return false;
}
bool timed_out;
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
do
{
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
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;
if (timed_out)
return false;
}
}
while ((ret == 0) ||
(((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
#else
//if we do not have sigtimedwait, we fork off a child process to get the signal in time
pid_t timeout_pid = ::fork();
if (timeout_pid == -1)
{
ec = boost::process::detail::get_last_error();
return true;
}
else if (timeout_pid == 0)
{
auto ts = get_timespec(time_out - Clock::now());
::timespec rem;
while (ts.tv_sec > 0 || ts.tv_nsec > 0)
{
if (::nanosleep(&ts, &rem) != 0)
{
auto err = errno;
if ((err == EINVAL) || (err == EFAULT))
break;
}
ts = get_timespec(time_out - Clock::now());
}
::exit(0);
}
struct child_cleaner_t
{
pid_t pid;
~child_cleaner_t()
{
int res;
::kill(pid, SIGKILL);
::waitpid(pid, &res, WNOHANG);
}
};
child_cleaner_t child_cleaner{timeout_pid};
do
{
int sig_{0};
if ((::waitpid(timeout_pid, &status, WNOHANG) != 0)
&& (WIFEXITED(status) || WIFSIGNALED(status)))
return false;
ret = ::sigwait(&sigset, &sig_);
errno = 0;
if ((sig_ == SIGCHLD) &&
(old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
old_sig.sa_handler(ret);
ret = ::waitpid(p.pid, &status, WNOHANG);
if (ret == 0) // == > is running
{
timed_out = Clock::now() >= time_out;
if (timed_out)
return false;
}
}
while ((ret == 0) ||
(((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
#endif
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
exit_code = status;
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
exit_code = status;
}
return !time_out_occured;
return true;
}
template< class Clock, class Duration >
inline bool wait_until(
const child_handle &p,
int & exit_code,
const std::chrono::time_point<Clock, Duration>& time_out)
{
std::error_code ec;
bool b = wait_until(p, exit_code, time_out, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_until");
return b;
}
template< class Rep, class Period >
inline bool wait_for(
@@ -97,107 +221,19 @@ inline bool wait_for(
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
exit_code = status;
}
return !time_out_occured;
return wait_until(p, exit_code, std::chrono::steady_clock::now() + rel_time, ec);
}
template< class Rep, class Period >
inline bool wait_until(
inline bool wait_for(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& time_out)
const std::chrono::duration<Rep, Period>& rel_time)
{
pid_t ret;
int status;
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
exit_code = status;
return !time_out_occured;
}
template< class Rep, class Period >
inline bool wait_until(
const child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& time_out,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
exit_code = status;
}
return !time_out_occured;
std::error_code ec;
bool b = wait_for(p, exit_code, rel_time, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_for");
return b;
}
}}}}

View File

@@ -12,75 +12,163 @@
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/posix/group_handle.hpp>
#include <chrono>
#include <system_error>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
inline void wait(const group_handle &p)
{
pid_t ret;
int status;
do
{
ret = ::waitpid(-p.grp, &status, 0);
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
}
inline void wait(const group_handle &p, std::error_code &ec) noexcept
{
pid_t ret;
int status;
siginfo_t status;
do
{
ret = ::waitpid(-p.grp, &status, 0);
ret = ::waitpid(-p.grp, &status.si_status, 0);
if (ret == -1)
{
ec = get_last_error();
return;
}
//ECHILD --> no child processes left.
ret = ::waitid(P_PGID, p.grp, &status, WEXITED | WNOHANG);
}
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
while ((ret != -1) || (errno != ECHILD));
if (errno != ECHILD)
ec = boost::process::detail::get_last_error();
else
ec.clear();
}
template< class Rep, class Period >
inline bool wait_for(
inline void wait(const group_handle &p) noexcept
{
std::error_code ec;
wait(p, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait");
}
template< class Clock, class Duration >
inline bool wait_until(
const group_handle &p,
const std::chrono::duration<Rep, Period>& rel_time)
const std::chrono::time_point<Clock, Duration>& time_out,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
::siginfo_t siginfo;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool timed_out = false;
int ret;
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
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;
};
::sigset_t sigset;
if (sigemptyset(&sigset) != 0)
{
ec = get_last_error();
return false;
}
if (sigaddset(&sigset, SIGCHLD) != 0)
{
ec = get_last_error();
return false;
}
struct ::sigaction old_sig;
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
{
ec = get_last_error();
return false;
}
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
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)
{
time_out_occured = true;
break;
if ((errno == ECHILD) || (errno == ESRCH))
{
ec.clear();
return true;
}
else
{
ec = get_last_error();
return false;
}
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
//check if we're done ->
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG);
}
while (((ret != -1) || ((errno != ECHILD) && (errno != ESRCH))) && !(timed_out = (Clock::now() > time_out)));
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
}
#else
::timespec sleep_interval;
sleep_interval.tv_sec = 0;
sleep_interval.tv_nsec = 1000000;
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
return !time_out_occured;
while (!(timed_out = (Clock::now() > time_out)))
{
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WSTOPPED | WNOHANG);
if (ret == -1)
{
if ((errno == ECHILD) || (errno == ESRCH))
{
ec.clear();
return true;
}
ec = boost::process::detail::get_last_error();
return false;
}
//we can wait, because unlike in the wait_for_exit, we have no race condition regarding eh exit code.
::nanosleep(&sleep_interval, nullptr);
}
return !timed_out;
#endif
}
template< class Clock, class Duration >
inline bool wait_until(
const group_handle &p,
const std::chrono::time_point<Clock, Duration>& time_out) noexcept
{
std::error_code ec;
bool b = wait_until(p, time_out, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_until");
return b;
}
template< class Rep, class Period >
inline bool wait_for(
@@ -88,102 +176,18 @@ inline bool wait_for(
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
ec.clear();
return !time_out_occured;
return wait_until(p, std::chrono::steady_clock::now() + rel_time, ec);
}
template< class Rep, class Period >
inline bool wait_until(
inline bool wait_for(
const group_handle &p,
const std::chrono::duration<Rep, Period>& time_out)
const std::chrono::duration<Rep, Period>& rel_time) noexcept
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
return !time_out_occured;
}
template< class Rep, class Period >
inline bool wait_until(
const group_handle &p,
const std::chrono::duration<Rep, Period>& time_out,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
bool time_out_occured = false;
do
{
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
time_out_occured = true;
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
ec.clear();
return !time_out_occured;
std::error_code ec;
bool b = wait_for(p, rel_time, ec);
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_for");
return b;
}
}}}}

View File

@@ -1,17 +1,17 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_TRAITS_HPP_
#define BOOST_PROCESS_TRAITS_HPP_
#ifndef BOOST_PROCESS_TRAITS_HPP_
#define BOOST_PROCESS_TRAITS_HPP_
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/traits/async.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/env.hpp>
#include <boost/process/detail/traits/error.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/traits/async.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/env.hpp>
#include <boost/process/detail/traits/error.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#endif /* BOOST_PROCESS_TRAITS_HPP_ */
#endif /* BOOST_PROCESS_TRAITS_HPP_ */

View File

@@ -1,34 +1,34 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace asio {
namespace boost { namespace asio {
class io_service;
}}
class io_context;
}}
namespace boost { namespace process { namespace detail {
namespace boost { namespace process { namespace detail {
struct async_tag {};
struct async_tag {};
template<>
struct initializer_builder<async_tag>;
template<>
struct initializer_builder<async_tag>;
template<> struct initializer_tag<::boost::asio::io_service> { typedef async_tag type;};
template<> struct initializer_tag<::boost::asio::io_context> { typedef async_tag type;};
}}}
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

View File

@@ -1,85 +1,85 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
#ifndef BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
#include <string>
#include <vector>
#include <type_traits>
#include <initializer_list>
#include <boost/filesystem/path.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
#include <string>
#include <vector>
#include <type_traits>
#include <initializer_list>
#include <boost/filesystem/path.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
template<typename Char>
struct cmd_or_exe_tag {};
template<typename Char>
struct cmd_or_exe_tag {};
struct shell_;
struct shell_;
template<> struct initializer_tag<const char* > { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<const wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<const char* > { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<const wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<char* > { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<char* > { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
template<std::size_t Size> struct initializer_tag<const char [Size]> { typedef cmd_or_exe_tag<char> type;};
template<std::size_t Size> struct initializer_tag<const wchar_t [Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
template<std::size_t Size> struct initializer_tag<const char [Size]> { typedef cmd_or_exe_tag<char> type;};
template<std::size_t Size> struct initializer_tag<const wchar_t [Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
template<std::size_t Size> struct initializer_tag<const char (&)[Size]> { typedef cmd_or_exe_tag<char> type;};
template<std::size_t Size> struct initializer_tag<const wchar_t (&)[Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
template<std::size_t Size> struct initializer_tag<const char (&)[Size]> { typedef cmd_or_exe_tag<char> type;};
template<std::size_t Size> struct initializer_tag<const wchar_t (&)[Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::basic_string<char >> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::basic_string<wchar_t >> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::basic_string<char >> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::basic_string<wchar_t >> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::vector<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::vector<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::vector<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::vector<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::vector<char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::vector<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::vector<char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::vector<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<const char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<const wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<const char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<const wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<shell_>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
};
template<> struct initializer_tag<shell_>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
};
template<> struct initializer_tag<boost::filesystem::path>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
};
template<> struct initializer_tag<boost::filesystem::path>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
};
template <typename Char>
struct exe_setter_;
template <typename Char, bool Append = false>
struct arg_setter_;
template <typename Char>
struct exe_setter_;
template <typename Char, bool Append = false>
struct arg_setter_;
template <typename Char, bool Append>
struct initializer_tag<arg_setter_<Char, Append>> { typedef cmd_or_exe_tag<Char> type;};
template <typename Char, bool Append>
struct initializer_tag<arg_setter_<Char, Append>> { typedef cmd_or_exe_tag<Char> type;};
template<typename Char> struct initializer_tag<exe_setter_<Char>> { typedef cmd_or_exe_tag<Char> type;};
template<typename Char> struct initializer_tag<exe_setter_<Char>> { typedef cmd_or_exe_tag<Char> type;};
template<>
struct initializer_builder<cmd_or_exe_tag<char>>;
template<>
struct initializer_builder<cmd_or_exe_tag<char>>;
template<>
struct initializer_builder<cmd_or_exe_tag<wchar_t>>;
template<>
struct initializer_builder<cmd_or_exe_tag<wchar_t>>;
}}}
}}}
#endif /* BOOST_PROCESS_DETAIL_STRING_TRAITS_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_STRING_TRAITS_HPP_ */

View File

@@ -1,76 +1,76 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/none.hpp>
#include <type_traits>
#include <boost/process/detail/config.hpp>
#include <boost/none.hpp>
#include <type_traits>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif
namespace boost { namespace process { namespace detail {
namespace boost { namespace process { namespace detail {
template<typename T>
struct is_initializer : std::is_base_of<handler_base, T> {};
template<typename T>
struct is_initializer : std::is_base_of<handler_base, T> {};
template<typename T>
struct is_initializer<T&> : std::is_base_of<handler_base, T> {};
template<typename T>
struct is_initializer<T&> : std::is_base_of<handler_base, T> {};
template<typename T>
struct initializer_tag;// { typedef void type; };
template<typename T>
struct initializer_tag;// { typedef void type; };
//remove const
template<typename T>
struct initializer_tag<const T> { typedef typename initializer_tag<T>::type type; };
//remove const
template<typename T>
struct initializer_tag<const T> { typedef typename initializer_tag<T>::type type; };
//remove &
template<typename T>
struct initializer_tag<T&> { typedef typename initializer_tag<T>::type type; };
//remove &
template<typename T>
struct initializer_tag<T&> { typedef typename initializer_tag<T>::type type; };
//remove const &
template<typename T>
struct initializer_tag<const T&> { typedef typename initializer_tag<T>::type type; };
//remove const &
template<typename T>
struct initializer_tag<const T&> { typedef typename initializer_tag<T>::type type; };
template<typename T>
struct initializer_builder;
template<typename T>
struct initializer_builder;
template<typename First, typename ...Args>
struct valid_argument_list;
template<typename First, typename ...Args>
struct valid_argument_list;
template<typename First>
struct valid_argument_list<First>
{
constexpr static bool value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
typedef std::integral_constant<bool, value> type;
};
template<typename First>
struct valid_argument_list<First>
{
constexpr static bool value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
typedef std::integral_constant<bool, value> type;
};
template<typename First, typename ...Args>
struct valid_argument_list
{
constexpr static bool my_value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
constexpr static bool value = valid_argument_list<Args...>::value && my_value;
typedef std::integral_constant<bool, value> type;
};
template<typename First, typename ...Args>
struct valid_argument_list
{
constexpr static bool my_value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
constexpr static bool value = valid_argument_list<Args...>::value && my_value;
typedef std::integral_constant<bool, value> type;
};
}}}
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

View File

@@ -1,53 +1,53 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process {
namespace boost { namespace process {
template<typename Char>
class basic_environment;
template<typename Char>
class basic_environment;
template<typename Char>
class basic_native_environment;
template<typename Char>
class basic_native_environment;
namespace detail {
namespace detail {
template<typename Char>
struct env_tag {};
template<typename Char>
struct env_tag {};
template<typename Char> struct env_set;
template<typename Char> struct env_append;
template<typename Char> struct env_set;
template<typename Char> struct env_append;
template<typename Char> struct env_reset;
template<typename Char> struct env_init;
template<typename Char> struct env_reset;
template<typename Char> struct env_init;
template<typename Char> struct initializer_tag<env_set<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<env_append<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<env_set<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<env_append<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<env_reset<Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<env_init <Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<env_reset<Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<env_init <Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<::boost::process::basic_environment<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<::boost::process::basic_native_environment<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<::boost::process::basic_environment<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<::boost::process::basic_native_environment<Char>> { typedef env_tag<Char> type; };
template<> struct initializer_builder<env_tag<char>>;
template<> struct initializer_builder<env_tag<wchar_t>>;
template<> struct initializer_builder<env_tag<char>>;
template<> struct initializer_builder<env_tag<wchar_t>>;
}
}
}}
}}
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */

View File

@@ -1,27 +1,27 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
namespace boost { namespace process { namespace detail {
struct error_tag;
struct error_tag;
template<>
struct initializer_tag<std::error_code>;
template<>
struct initializer_tag<std::error_code>;
}}}
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

View File

@@ -0,0 +1,81 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_
#define BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_
#include <type_traits>
#include <boost/fusion/include/filter_if.hpp>
#include <boost/fusion/include/for_each.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handles.hpp>
#include <boost/process/detail/posix/asio_fwd.hpp>
#else
#include <boost/process/detail/windows/handles.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#endif
namespace boost { namespace process { namespace detail {
struct uses_handles
{
//If you get an error here, you must add a `get_handles` function that returns a range or a single handle value
void get_used_handles() const;
};
template<typename T>
struct does_use_handle: std::is_base_of<uses_handles, T> {};
template<typename T>
struct does_use_handle<T&> : std::is_base_of<uses_handles, T> {};
template<typename T>
struct does_use_handle<const T&> : std::is_base_of<uses_handles, T> {};
template<typename Char, typename Sequence>
class executor;
template<typename Func>
struct foreach_handle_invocator
{
Func & func;
foreach_handle_invocator(Func & func) : func(func) {}
template<typename Range>
void invoke(const Range & range) const
{
for (auto handle_ : range)
func(handle_);
}
void invoke(::boost::process::detail::api::native_handle_type handle) const {func(handle);};
template<typename T>
void operator()(T & val) const {invoke(val.get_used_handles());}
};
template<typename Executor, typename Function>
void foreach_used_handle(Executor &exec, Function &&func)
{
boost::fusion::for_each(boost::fusion::filter_if<does_use_handle<boost::mpl::_>>(exec.seq),
foreach_handle_invocator<Function>(func));
}
template<typename Executor>
std::vector<::boost::process::detail::api::native_handle_type>
get_used_handles(Executor &exec)
{
std::vector<::boost::process::detail::api::native_handle_type> res;
foreach_used_handle(exec, [&](::boost::process::detail::api::native_handle_type handle){res.push_back(handle);});
return res;
}
}}}
#endif /* BOOST_PROCESS_DETAIL_USED_HANDLES_HPP_ */

View File

@@ -19,27 +19,43 @@ template<typename Allocator>
class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_service;
class io_context;
class executor;
template <typename Handler>
class basic_yield_context;
namespace windows {
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class stream_handle_service;
template <typename StreamHandleService>
class basic_stream_handle;
typedef basic_stream_handle<stream_handle_service> stream_handle;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
template <typename Executor>
class basic_stream_handle;
typedef basic_stream_handle<executor> stream_handle;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class object_handle_service;
template <typename ObjectHandleService>
class basic_object_handle;
typedef basic_object_handle<object_handle_service> object_handle;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
template <typename Executor>
class basic_object_handle;
typedef basic_object_handle<executor> object_handle;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
} //windows
} //asio

View File

@@ -1,40 +1,40 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
#ifndef BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
#include <boost/process/detail/windows/handler.hpp>
#include <type_traits>
#include <boost/process/detail/windows/handler.hpp>
#include <type_traits>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
struct require_io_service {};
struct require_io_context {};
struct async_handler : handler_base_ext, require_io_service
{
};
struct async_handler : handler_base_ext, require_io_context
{
};
template<typename T>
struct is_async_handler : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct does_require_io_service : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_context : std::is_base_of<require_io_context, T> {};
template<typename T>
struct does_require_io_service<T&> : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_context<T&> : std::is_base_of<require_io_context, T> {};
template<typename T>
struct does_require_io_service<const T&> : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_context<const T&> : std::is_base_of<require_io_context, T> {};
}}}}
}}}}
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */

View File

@@ -1,105 +1,111 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
#include <boost/winapi/error_codes.hpp>
#include <boost/asio/write.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
#include <boost/asio/write.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_context,
::boost::process::detail::uses_handles
{
Buffer & buf;
std::shared_ptr<std::promise<void>> promise;
async_in_buffer operator>(std::future<void> & fut)
{
promise = std::make_shared<std::promise<void>>();
fut = promise->get_future(); return std::move(*this);
}
std::shared_ptr<boost::process::async_pipe> pipe;
::boost::winapi::HANDLE_ get_used_handles() const
{
return std::move(*pipe).source().native_handle();
}
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe_ = this->pipe;
if (this->promise)
{
auto promise_ = this->promise;
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_value();
});
}
else
boost::asio::async_write(*pipe_, buf,
[pipe_](const boost::system::error_code&, std::size_t){});
std::move(*pipe_).source().close();
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_service
{
Buffer & buf;
this->pipe = nullptr;
}
std::shared_ptr<std::promise<void>> promise;
async_in_buffer operator>(std::future<void> & fut)
{
promise = std::make_shared<std::promise<void>>();
fut = promise->get_future(); return std::move(*this);
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::boost::winapi::CloseHandle(pipe->native_source());
}
std::shared_ptr<boost::process::async_pipe> pipe;
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe = this->pipe;
::boost::winapi::HANDLE_ source_handle = std::move(*pipe).source().native_handle();
if (this->promise)
{
auto promise = this->promise;
boost::winapi::SetHandleInformation(source_handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
boost::asio::async_write(*pipe, buf,
[promise](const boost::system::error_code & ec, std::size_t)
{
if (ec && (ec.value() != ::boost::detail::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_value();
});
}
else
boost::asio::async_write(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t){});
std::move(*pipe).source().close();
exec.startup_info.hStdInput = source_handle;
exec.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
exec.inherit_handles = true;
}
};
this->pipe = nullptr;
}
}}}}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::boost::detail::winapi::CloseHandle(pipe->native_source());
}
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
::boost::detail::winapi::HANDLE_ source_handle = std::move(*pipe).source().native_handle();
boost::detail::winapi::SetHandleInformation(source_handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
exec.startup_info.hStdInput = source_handle;
exec.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
exec.inherit_handles = true;
}
};
}}}}
#endif
#endif

View File

@@ -1,176 +1,186 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
#include <boost/winapi/error_codes.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <istream>
#include <memory>
#include <exception>
#include <future>
#include <istream>
#include <memory>
#include <exception>
#include <future>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<int p1, int p2, typename Buffer>
struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_service
{
Buffer & buf;
template<int p1, int p2, typename Buffer>
struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_context
{
Buffer & buf;
std::shared_ptr<boost::process::async_pipe> pipe;
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_buffer(Buffer & buf) : buf(buf)
{
}
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();
this->pipe = nullptr;
async_out_buffer(Buffer & buf) : buf(buf)
{
}
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();
this->pipe = nullptr;
}
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
}
};
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
}
};
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_service
{
std::shared_ptr<boost::process::async_pipe> pipe;
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_context,
::boost::process::detail::uses_handles
{
std::shared_ptr<boost::process::async_pipe> pipe;
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
::boost::winapi::HANDLE_ get_used_handles() const
{
return std::move(*pipe).sink().native_handle();
}
async_out_future(std::future<Type> & fut)
{
fut = promise->get_future();
}
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)
{
if (ec && (ec.value() != ::boost::detail::winapi::ERROR_BROKEN_PIPE_))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
{
std::istream is (buffer.get());
Type arg;
arg.resize(buffer->size());
is.read(&*arg.begin(), buffer->size());
async_out_future(std::future<Type> & fut)
{
fut = promise->get_future();
}
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)
{
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)));
}
else
{
std::istream is (buffer_.get());
Type arg;
if (buffer_->size() > 0)
{
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->buffer = nullptr;
this->promise = nullptr;
}
});
this->pipe = nullptr;
this->buffer = nullptr;
this->promise = nullptr;
}
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
}
};
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
}
};
}}}}
}}}}
#endif
#endif

View File

@@ -6,15 +6,17 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/pipes.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/detail/winapi/get_last_error.hpp>
#include <boost/detail/winapi/access_rights.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/pipes.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/winapi/get_last_error.hpp>
#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>
#include <string>
@@ -24,9 +26,9 @@ inline std::string make_pipe_name()
{
std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_";
auto pid = ::boost::detail::winapi::GetCurrentProcessId();
auto pid = ::boost::winapi::GetCurrentProcessId();
static unsigned long long cnt = 0;
static std::atomic_size_t cnt{0};
name += std::to_string(pid);
name += "_";
name += std::to_string(cnt++);
@@ -38,34 +40,41 @@ class async_pipe
{
::boost::asio::windows::stream_handle _source;
::boost::asio::windows::stream_handle _sink ;
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
const std::string & name, bool private_);
public:
typedef ::boost::detail::winapi::HANDLE_ native_handle_type;
typedef ::boost::winapi::HANDLE_ native_handle_type;
typedef ::boost::asio::windows::stream_handle handle_type;
inline async_pipe(boost::asio::io_service & ios,
const std::string & name = make_pipe_name())
: async_pipe(ios, ios, name) {}
async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios, make_pipe_name(), true) {}
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink)
: async_pipe(ios_source, ios_sink, make_pipe_name(), true) {}
async_pipe(boost::asio::io_context & ios, const std::string & name)
: async_pipe(ios, ios, name, false) {}
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name)
: async_pipe(ios_source, ios_sink, name, false) {}
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
const std::string & name = make_pipe_name());
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::detail::winapi::INVALID_HANDLE_VALUE_);
rhs._sink .assign (::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(::boost::asio::io_service & ios_source,
::boost::asio::io_service & ios_sink,
explicit async_pipe(::boost::asio::io_context & ios_source,
::boost::asio::io_context & ios_sink,
const basic_pipe<CharT, Traits> & p)
: _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
{
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p)
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
: async_pipe(ios, ios, p)
{
}
@@ -78,10 +87,8 @@ public:
~async_pipe()
{
if (_sink .native() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink.native());
if (_source.native() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source.native());
boost::system::error_code ec;
close(ec);
}
template<class CharT, class Traits = std::char_traits<CharT>>
@@ -100,12 +107,12 @@ public:
if (_sink.is_open())
{
_sink.close();
_sink = handle_type(_sink.get_io_service());
_sink = handle_type(_sink.get_executor());
}
if (_source.is_open())
{
_source.close();
_source = handle_type(_source.get_io_service());
_source = handle_type(_source.get_executor());
}
}
void close(boost::system::error_code & ec)
@@ -113,12 +120,12 @@ public:
if (_sink.is_open())
{
_sink.close(ec);
_sink = handle_type(_sink.get_io_service());
_sink = handle_type(_sink.get_executor());
}
if (_source.is_open())
{
_source.close(ec);
_source = handle_type(_source.get_io_service());
_source = handle_type(_source.get_executor());
}
}
@@ -129,9 +136,9 @@ public:
void async_close()
{
if (_sink.is_open())
_sink.get_io_service(). post([this]{_sink.close();});
boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
if (_source.is_open())
_source.get_io_service().post([this]{_source.close();});
boost::asio::post(_source.get_executor(), [this]{_source.close();});
}
template<typename MutableBufferSequence>
@@ -145,8 +152,20 @@ public:
return _sink.write_some(buffers);
}
native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();}
native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();}
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();}
template<typename MutableBufferSequence,
typename ReadHandler>
@@ -156,7 +175,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,
@@ -167,7 +186,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;}
@@ -176,195 +195,245 @@ public:
handle_type && source() && { return std::move(_source); }
handle_type && sink() && { return std::move(_sink); }
handle_type source(::boost::asio::io_service& ios) &&
handle_type source(::boost::asio::io_context& ios) &&
{
::boost::asio::windows::stream_handle stolen(ios, _source.native_handle());
_source.assign(::boost::detail::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_service& ios) &&
handle_type sink (::boost::asio::io_context& ios) &&
{
::boost::asio::windows::stream_handle stolen(ios, _sink.native_handle());
_sink.assign(::boost::detail::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;
}
handle_type source(::boost::asio::io_service& ios) const &
handle_type source(::boost::asio::io_context& ios) const &
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
auto proc = ::boost::winapi::GetCurrentProcess();
::boost::detail::winapi::HANDLE_ source;
auto source_in = const_cast<handle_type&>(_source).native();
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
::boost::winapi::HANDLE_ source;
auto source_in = const_cast<handle_type&>(_source).native_handle();
if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, source_in, proc, &source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::winapi::BOOL_>(true),
::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_service& ios) const &
handle_type sink (::boost::asio::io_context& ios) const &
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
auto proc = ::boost::winapi::GetCurrentProcess();
::boost::detail::winapi::HANDLE_ sink;
auto sink_in = const_cast<handle_type&>(_sink).native();
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
::boost::winapi::HANDLE_ sink;
auto sink_in = const_cast<handle_type&>(_sink).native_handle();
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, sink_in, proc, &sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::winapi::BOOL_>(true),
::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_service()),
_sink (const_cast<handle_type&>(p._sink).get_io_service())
_source(const_cast<handle_type&>(p._source).get_executor()),
_sink (const_cast<handle_type&>(p._sink).get_executor())
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::detail::winapi::HANDLE_ source;
::boost::detail::winapi::HANDLE_ sink;
auto proc = ::boost::winapi::GetCurrentProcess();
::boost::winapi::HANDLE_ source;
::boost::winapi::HANDLE_ sink;
//cannot get the handle from a const object.
auto source_in = const_cast<handle_type&>(p._source).native();
auto sink_in = const_cast<handle_type&>(p._sink).native();
auto source_in = const_cast<handle_type&>(p._source).native_handle();
auto sink_in = const_cast<handle_type&>(p._sink).native_handle();
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, source_in, proc, &source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, sink_in, proc, &sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
_source.assign(source);
_sink. assign(sink);
if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
_source.assign(source);
if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
_sink. assign(sink);
}
async_pipe::async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
const std::string & name) : _source(ios_source), _sink(ios_sink)
async_pipe::async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
const std::string & name, bool private_) : _source(ios_source), _sink(ios_sink)
{
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
::boost::detail::winapi::HANDLE_ source = ::boost::detail::winapi::create_named_pipe(
::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe(
#if defined(BOOST_NO_ANSI_APIS)
::boost::process::detail::convert(name).c_str(),
#else
name.c_str(),
::boost::detail::winapi::PIPE_ACCESS_INBOUND_
#endif
::boost::winapi::PIPE_ACCESS_INBOUND_
| FILE_FLAG_OVERLAPPED_, //write flag
0, 1, 8192, 8192, 0, nullptr);
0, private_ ? 1 : ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
if (source == boost::detail::winapi::INVALID_HANDLE_VALUE_)
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_named_pipe(" + name + ") failed");
_source.assign(source);
::boost::detail::winapi::HANDLE_ sink = boost::detail::winapi::create_file(
::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
#if defined(BOOST_NO_ANSI_APIS)
::boost::process::detail::convert(name).c_str(),
#else
name.c_str(),
::boost::detail::winapi::GENERIC_WRITE_, 0, nullptr,
::boost::detail::winapi::OPEN_EXISTING_,
#endif
::boost::winapi::GENERIC_WRITE_, 0, nullptr,
::boost::winapi::OPEN_EXISTING_,
FILE_FLAG_OVERLAPPED_, //to allow read
nullptr);
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_file() failed");
_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::detail::winapi::GetCurrentProcess();
auto proc = ::boost::winapi::GetCurrentProcess();
::boost::detail::winapi::HANDLE_ source;
::boost::detail::winapi::HANDLE_ sink;
::boost::winapi::HANDLE_ source;
::boost::winapi::HANDLE_ sink;
//cannot get the handle from a const object.
auto &source_in = const_cast<::boost::asio::windows::stream_handle &>(p._source);
auto &sink_in = const_cast<::boost::asio::windows::stream_handle &>(p._sink);
if (source_in.native() == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, source_in.native(), proc, &source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
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(
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.native() == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, sink_in.native(), proc, &sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
if (sink_in.native_handle() == ::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_service
_source = ::boost::asio::windows::stream_handle(source_in.get_io_service(), source);
_sink = ::boost::asio::windows::stream_handle(source_in.get_io_service(), sink);
//so we also assign the io_context
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::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source.native());
if (_sink.native_handle() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink.native());
_source.assign(rhs._source.native_handle());
_sink .assign(rhs._sink .native_handle());
rhs._source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
rhs._sink .assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
_source = std::move(rhs._source);
_sink = std::move(rhs._sink);
return *this;
}
template<class CharT, class Traits>
async_pipe::operator basic_pipe<CharT, Traits>() const
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
auto proc = ::boost::winapi::GetCurrentProcess();
::boost::detail::winapi::HANDLE_ source;
::boost::detail::winapi::HANDLE_ sink;
::boost::winapi::HANDLE_ source;
::boost::winapi::HANDLE_ sink;
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native();
auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native();
auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native_handle();
auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native_handle();
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, source_in, proc, &source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, sink_in, proc, &sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return basic_pipe<CharT, Traits>{source, sink};

View File

@@ -1,164 +1,178 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/process/shell.hpp>
#include <boost/process/detail/windows/handler.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/process/shell.hpp>
#include <boost/process/detail/windows/handler.hpp>
#include <vector>
#include <string>
#include <iterator>
#include <vector>
#include <string>
#include <iterator>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
inline std::string build_args(const std::string & exe, std::vector<std::string> && data)
{
std::string st = exe;
inline std::string build_args(const std::string & exe, std::vector<std::string> && data)
{
std::string st = exe;
//put in quotes if it has spaces
{
boost::replace_all(st, "\"", "\\\"");
//put in quotes if it has spaces
{
boost::replace_all(st, "\"", "\\\"");
auto it = std::find(st.begin(), st.end(), ' ');
auto it = std::find(st.begin(), st.end(), ' ');
if (it != st.end())//contains spaces.
{
st.insert(st.begin(), '"');
st += '"';
}
}
if (it != st.end())//contains spaces.
{
st.insert(st.begin(), '"');
st += '"';
}
}
for (auto & arg : data)
{
boost::replace_all(arg, "\"", "\\\"");
for (auto & arg : data)
{
boost::replace_all(arg, "\"", "\\\"");
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), '"');
arg += '"'; //thats the post one.
}
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), '"');
arg += '"'; //thats the post one.
}
if (!st.empty())//first one does not need a preceeding space
st += ' ';
if (!st.empty())//first one does not need a preceeding space
st += ' ';
st += arg;
}
return st;
}
st += arg;
}
return st;
}
inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstring> && data)
{
std::wstring st = exe;
for (auto & arg : data)
{
boost::replace_all(arg, L"\"", L"\\\"");
inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstring> && data)
{
std::wstring st = exe;
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), L'"');
arg += L'"'; //thats the post one.
}
//put in quotes if it has spaces
{
boost::replace_all(st, L"\"", L"\\\"");
if (!st.empty())//first one does not need a preceeding space
st += L' ';
auto it = std::find(st.begin(), st.end(), L' ');
st += arg;
}
return st;
}
if (it != st.end())//contains spaces.
{
st.insert(st.begin(), L'"');
st += L'"';
}
}
template<typename Char>
struct exe_cmd_init : handler_base_ext
{
using value_type = Char;
using string_type = std::basic_string<value_type>;
for (auto & arg : data)
{
boost::replace_all(arg, L"\"", L"\\\"");
static const char* c_arg(char) { return "/c";}
static const wchar_t* c_arg(wchar_t) { return L"/c";}
auto it = std::find(arg.begin(), arg.end(), L' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), L'"');
arg += L'"'; //thats the post one.
}
exe_cmd_init(const string_type & exe, bool cmd_only = false)
: exe(exe), args({}), cmd_only(cmd_only) {};
exe_cmd_init(string_type && exe, bool cmd_only = false)
: exe(std::move(exe)), args({}), cmd_only(cmd_only) {};
if (!st.empty())//first one does not need a preceeding space
st += L' ';
exe_cmd_init(string_type && exe, std::vector<string_type> && args)
: exe(std::move(exe)), args(build_args(this->exe, std::move(args))), cmd_only(false) {};
template <class Executor>
void on_setup(Executor& exec) const
{
st += arg;
}
return st;
}
if (cmd_only && args.empty())
exec.cmd_line = exe.c_str();
else
{
exec.exe = exe.c_str();
exec.cmd_line = args.c_str();
}
}
static exe_cmd_init<Char> exe_args(string_type && exe, std::vector<string_type> && args)
{
return exe_cmd_init<Char>(std::move(exe), std::move(args));
}
static exe_cmd_init<Char> cmd(string_type&& cmd)
{
return exe_cmd_init<Char>(std::move(cmd), true);
}
static exe_cmd_init<Char> exe_args_shell(string_type && exe, std::vector<string_type> && args)
{
std::vector<string_type> args_ = {c_arg(Char()), std::move(exe)};
args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end()));
string_type sh = get_shell(Char());
template<typename Char>
struct exe_cmd_init : handler_base_ext
{
using value_type = Char;
using string_type = std::basic_string<value_type>;
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
}
static const char* c_arg(char) { return "/c";}
static const wchar_t* c_arg(wchar_t) { return L"/c";}
static std:: string get_shell(char) {return shell(). string(codecvt()); }
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
exe_cmd_init(const string_type & exe, bool cmd_only = false)
: exe(exe), args({}), cmd_only(cmd_only) {};
exe_cmd_init(string_type && exe, bool cmd_only = false)
: exe(std::move(exe)), args({}), cmd_only(cmd_only) {};
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
{
std::vector<string_type> args = {c_arg(Char()), std::move(cmd)};
string_type sh = get_shell(Char());
exe_cmd_init(string_type && exe, std::vector<string_type> && args)
: exe(std::move(exe)), args(build_args(this->exe, std::move(args))), cmd_only(false) {};
template <class Executor>
void on_setup(Executor& exec) const
{
return exe_cmd_init<Char>(
std::move(sh),
std::move(args));
}
private:
string_type exe;
string_type args;
bool cmd_only;
};
if (cmd_only && args.empty())
exec.cmd_line = exe.c_str();
else
{
exec.exe = exe.c_str();
exec.cmd_line = args.c_str();
}
}
static exe_cmd_init<Char> exe_args(string_type && exe, std::vector<string_type> && args)
{
return exe_cmd_init<Char>(std::move(exe), std::move(args));
}
static exe_cmd_init<Char> cmd(string_type&& cmd)
{
return exe_cmd_init<Char>(std::move(cmd), true);
}
static exe_cmd_init<Char> exe_args_shell(string_type && exe, std::vector<string_type> && args)
{
std::vector<string_type> args_ = {c_arg(Char()), std::move(exe)};
args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end()));
string_type sh = get_shell(Char());
}
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
}
static std:: string get_shell(char) {return shell(). string(codecvt()); }
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
{
std::vector<string_type> args = {c_arg(Char()), std::move(cmd)};
string_type sh = get_shell(Char());
return exe_cmd_init<Char>(
std::move(sh),
std::move(args));
}
private:
string_type exe;
string_type args;
bool cmd_only;
};
}
}
}
}
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */

View File

@@ -6,14 +6,14 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_PIPE_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_PIPE_HPP
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/detail/winapi/pipes.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/detail/winapi/get_last_error.hpp>
#include <boost/detail/winapi/access_rights.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/error_codes.hpp>
#include <boost/winapi/pipes.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/winapi/get_last_error.hpp>
#include <boost/winapi/access_rights.hpp>
#include <boost/winapi/process.hpp>
#include <boost/process/detail/windows/compare_handles.hpp>
#include <system_error>
#include <string>
@@ -24,33 +24,33 @@ namespace boost { namespace process { namespace detail { namespace windows {
template<class CharT, class Traits = std::char_traits<CharT>>
class basic_pipe
{
::boost::detail::winapi::HANDLE_ _source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
::boost::detail::winapi::HANDLE_ _sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
::boost::winapi::HANDLE_ _source = ::boost::winapi::INVALID_HANDLE_VALUE_;
::boost::winapi::HANDLE_ _sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
public:
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
typedef typename Traits::pos_type pos_type ;
typedef typename Traits::off_type off_type ;
typedef ::boost::detail::winapi::HANDLE_ native_handle_type;
typedef ::boost::winapi::HANDLE_ native_handle_type;
explicit basic_pipe(::boost::detail::winapi::HANDLE_ source, ::boost::detail::winapi::HANDLE_ sink)
explicit basic_pipe(::boost::winapi::HANDLE_ source, ::boost::winapi::HANDLE_ sink)
: _source(source), _sink(sink) {}
inline explicit basic_pipe(const std::string & name);
inline basic_pipe(const basic_pipe& p);
basic_pipe(basic_pipe&& lhs) : _source(lhs._source), _sink(lhs._sink)
{
lhs._source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
lhs._sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
lhs._source = ::boost::winapi::INVALID_HANDLE_VALUE_;
lhs._sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
}
inline basic_pipe& operator=(const basic_pipe& p);
inline basic_pipe& operator=(basic_pipe&& lhs);
~basic_pipe()
{
if (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink);
if (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source);
if (_sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_sink);
if (_source != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_source);
}
native_handle_type native_source() const {return _source;}
native_handle_type native_sink () const {return _sink;}
@@ -60,21 +60,21 @@ public:
basic_pipe()
{
if (!::boost::detail::winapi::CreatePipe(&_source, &_sink, nullptr, 0))
if (!::boost::winapi::CreatePipe(&_source, &_sink, nullptr, 0))
throw_last_error("CreatePipe() failed");
}
int_type write(const char_type * data, int_type count)
{
::boost::detail::winapi::DWORD_ write_len;
if (!::boost::detail::winapi::WriteFile(
::boost::winapi::DWORD_ write_len;
if (!::boost::winapi::WriteFile(
_sink, data, count * sizeof(char_type), &write_len, nullptr
))
{
auto ec = ::boost::process::detail::get_last_error();
if ((ec.value() == ::boost::detail::winapi::ERROR_BROKEN_PIPE_) ||
(ec.value() == ::boost::detail::winapi::ERROR_NO_DATA_))
if ((ec.value() == ::boost::winapi::ERROR_BROKEN_PIPE_) ||
(ec.value() == ::boost::winapi::ERROR_NO_DATA_))
return 0;
else
throw process_error(ec, "WriteFile failed");
@@ -83,14 +83,14 @@ public:
}
int_type read(char_type * data, int_type count)
{
::boost::detail::winapi::DWORD_ read_len;
if (!::boost::detail::winapi::ReadFile(
::boost::winapi::DWORD_ read_len;
if (!::boost::winapi::ReadFile(
_source, data, count * sizeof(char_type), &read_len, nullptr
))
{
auto ec = ::boost::process::detail::get_last_error();
if ((ec.value() == ::boost::detail::winapi::ERROR_BROKEN_PIPE_) ||
(ec.value() == ::boost::detail::winapi::ERROR_NO_DATA_))
if ((ec.value() == ::boost::winapi::ERROR_BROKEN_PIPE_) ||
(ec.value() == ::boost::winapi::ERROR_NO_DATA_))
return 0;
else
throw process_error(ec, "ReadFile failed");
@@ -98,40 +98,40 @@ public:
return static_cast<int_type>(read_len);
}
bool is_open()
bool is_open() const
{
return (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) ||
(_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_);
return (_source != ::boost::winapi::INVALID_HANDLE_VALUE_) ||
(_sink != ::boost::winapi::INVALID_HANDLE_VALUE_);
}
void close()
{
::boost::detail::winapi::CloseHandle(_source);
::boost::detail::winapi::CloseHandle(_sink);
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
::boost::winapi::CloseHandle(_source);
::boost::winapi::CloseHandle(_sink);
_source = ::boost::winapi::INVALID_HANDLE_VALUE_;
_sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
}
};
template<class Char, class Traits>
basic_pipe<Char, Traits>::basic_pipe(const basic_pipe & p)
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
auto proc = ::boost::winapi::GetCurrentProcess();
if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
if (p._source == ::boost::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, p._source, proc, &_source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
if (p._sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, p._sink, proc, &_sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
}
@@ -143,23 +143,28 @@ 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
::boost::detail::winapi::HANDLE_ source = ::boost::detail::winapi::create_named_pipe(
name.c_str(),
::boost::detail::winapi::PIPE_ACCESS_INBOUND_
#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(),
::boost::winapi::PIPE_ACCESS_INBOUND_
| FILE_FLAG_OVERLAPPED_, //write flag
0, 1, 8192, 8192, 0, nullptr);
0, ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
if (source == boost::detail::winapi::INVALID_HANDLE_VALUE_)
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_named_pipe() failed");
::boost::detail::winapi::HANDLE_ sink = boost::detail::winapi::create_file(
::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
name.c_str(),
::boost::detail::winapi::GENERIC_WRITE_, 0, nullptr,
::boost::winapi::GENERIC_WRITE_, 0, nullptr,
OPEN_EXISTING_,
FILE_FLAG_OVERLAPPED_, //to allow read
nullptr);
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_file() failed");
_source = source;
@@ -169,22 +174,22 @@ basic_pipe<Char, Traits>::basic_pipe(const std::string & name)
template<class Char, class Traits>
basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(const basic_pipe & p)
{
auto proc = ::boost::detail::winapi::GetCurrentProcess();
auto proc = ::boost::winapi::GetCurrentProcess();
if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
if (p._source == ::boost::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, p._source, proc, &_source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
if (p._sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, p._sink, proc, &_sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return *this;
@@ -193,16 +198,16 @@ basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(const basic_pipe &
template<class Char, class Traits>
basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(basic_pipe && lhs)
{
if (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source);
if (_source != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_source);
if (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink);
if (_sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_sink);
_source = lhs._source;
_sink = lhs._sink;
lhs._source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
lhs._sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
lhs._source = ::boost::winapi::INVALID_HANDLE_VALUE_;
lhs._sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
return *this;
}

View File

@@ -11,9 +11,9 @@
#define BOOST_PROCESS_WINDOWS_CHILD_HPP
#include <boost/move/move.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/jobs.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/jobs.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
@@ -21,18 +21,18 @@ typedef int pid_t;
struct child_handle
{
::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
::boost::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
explicit child_handle(const ::boost::detail::winapi::PROCESS_INFORMATION_ &pi) :
explicit child_handle(const ::boost::winapi::PROCESS_INFORMATION_ &pi) :
proc_info(pi)
{}
explicit child_handle(pid_t pid) :
proc_info{nullptr, nullptr, 0,0}
{
auto h = ::boost::detail::winapi::OpenProcess(
::boost::detail::winapi::PROCESS_ALL_ACCESS_,
static_cast<::boost::detail::winapi::BOOL_>(0),
auto h = ::boost::winapi::OpenProcess(
::boost::winapi::PROCESS_ALL_ACCESS_,
static_cast<::boost::winapi::BOOL_>(0),
pid);
if (h == nullptr)
@@ -44,23 +44,23 @@ struct child_handle
child_handle() = default;
~child_handle()
{
::boost::detail::winapi::CloseHandle(proc_info.hProcess);
::boost::detail::winapi::CloseHandle(proc_info.hThread);
::boost::winapi::CloseHandle(proc_info.hProcess);
::boost::winapi::CloseHandle(proc_info.hThread);
}
child_handle(const child_handle & c) = delete;
child_handle(child_handle && c) : proc_info(c.proc_info)
{
c.proc_info.hProcess = ::boost::detail::winapi::invalid_handle_value;
c.proc_info.hThread = ::boost::detail::winapi::invalid_handle_value;
c.proc_info.hProcess = ::boost::winapi::invalid_handle_value;
c.proc_info.hThread = ::boost::winapi::invalid_handle_value;
}
child_handle &operator=(const child_handle & c) = delete;
child_handle &operator=(child_handle && c)
{
::boost::detail::winapi::CloseHandle(proc_info.hProcess);
::boost::detail::winapi::CloseHandle(proc_info.hThread);
::boost::winapi::CloseHandle(proc_info.hProcess);
::boost::winapi::CloseHandle(proc_info.hThread);
proc_info = c.proc_info;
c.proc_info.hProcess = ::boost::detail::winapi::invalid_handle_value;
c.proc_info.hThread = ::boost::detail::winapi::invalid_handle_value;
c.proc_info.hProcess = ::boost::winapi::invalid_handle_value;
c.proc_info.hThread = ::boost::winapi::invalid_handle_value;
return *this;
}
@@ -69,25 +69,25 @@ struct child_handle
return static_cast<int>(proc_info.dwProcessId);
}
typedef ::boost::detail::winapi::HANDLE_ process_handle_t;
typedef ::boost::winapi::HANDLE_ process_handle_t;
process_handle_t process_handle() const { return proc_info.hProcess; }
bool valid() const
{
return (proc_info.hProcess != nullptr) &&
(proc_info.hProcess != ::boost::detail::winapi::INVALID_HANDLE_VALUE_);
(proc_info.hProcess != ::boost::winapi::INVALID_HANDLE_VALUE_);
}
bool in_group() const
{
::boost::detail::winapi::BOOL_ value;
if (!::boost::detail::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
::boost::winapi::BOOL_ value;
if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
throw_last_error("IsProcessinJob Failed");
return value!=0;
}
bool in_group(std::error_code &ec) const noexcept
{
::boost::detail::winapi::BOOL_ value;
if (!::boost::detail::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
::boost::winapi::BOOL_ value;
if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
ec = get_last_error();
return value!=0;
}

View File

@@ -10,8 +10,8 @@
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
@@ -21,8 +21,8 @@ struct close_in : public ::boost::process::detail::handler_base
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdInput = boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
e.startup_info.hStdInput = boost::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
}
};

View File

@@ -10,8 +10,8 @@
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
@@ -27,25 +27,25 @@ template<>
template<typename WindowsExecutor>
void close_out<1,-1>::on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdOutput = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.startup_info.hStdOutput = ::boost::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
}
template<>
template<typename WindowsExecutor>
void close_out<2,-1>::on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdError = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.startup_info.hStdError = ::boost::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
}
template<>
template<typename WindowsExecutor>
void close_out<1,2>::on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdOutput = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.hStdError = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.startup_info.hStdOutput = ::boost::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.hStdError = ::boost::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
}
}}}}

View File

@@ -1,49 +1,49 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_CMD_HPP_
#define BOOST_PROCESS_WINDOWS_CMD_HPP_
#ifndef BOOST_PROCESS_WINDOWS_CMD_HPP_
#define BOOST_PROCESS_WINDOWS_CMD_HPP_
#include <string>
#include <string>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
template<typename CharType>
struct cmd_setter_ : ::boost::process::detail::handler_base
{
typedef CharType value_type;
typedef std::basic_string<value_type> string_type;
template<typename CharType>
struct cmd_setter_ : ::boost::process::detail::handler_base
{
typedef CharType value_type;
typedef std::basic_string<value_type> string_type;
cmd_setter_(string_type && cmd_line) : _cmd_line(std::move(cmd_line)) {}
cmd_setter_(const string_type & cmd_line) : _cmd_line(cmd_line) {}
template <class Executor>
void on_setup(Executor& exec)
{
exec.cmd_line = _cmd_line.c_str();
}
const string_type & str() const {return _cmd_line;}
cmd_setter_(string_type && cmd_line) : _cmd_line(std::move(cmd_line)) {}
cmd_setter_(const string_type & cmd_line) : _cmd_line(cmd_line) {}
template <class Executor>
void on_setup(Executor& exec)
{
exec.cmd_line = _cmd_line.c_str();
}
const string_type & str() const {return _cmd_line;}
private:
string_type _cmd_line;
};
private:
string_type _cmd_line;
};
}
}
}
}
}
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */

View File

@@ -6,28 +6,28 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/process/detail/config.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
inline bool compare_handles(boost::detail::winapi::HANDLE_ lhs, boost::detail::winapi::HANDLE_ rhs)
inline bool compare_handles(boost::winapi::HANDLE_ lhs, boost::winapi::HANDLE_ rhs)
{
if ( (lhs == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|| (rhs == ::boost::detail::winapi::INVALID_HANDLE_VALUE_))
if ( (lhs == ::boost::winapi::INVALID_HANDLE_VALUE_)
|| (rhs == ::boost::winapi::INVALID_HANDLE_VALUE_))
return false;
if (lhs == rhs)
return true;
::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ lhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ rhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
::boost::winapi::BY_HANDLE_FILE_INFORMATION_ lhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
::boost::winapi::BY_HANDLE_FILE_INFORMATION_ rhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
if (!::boost::detail::winapi::GetFileInformationByHandle(lhs, &lhs_info))
if (!::boost::winapi::GetFileInformationByHandle(lhs, &lhs_info))
::boost::process::detail::throw_last_error("GetFileInformationByHandle");
if (!::boost::detail::winapi::GetFileInformationByHandle(rhs, &rhs_info))
if (!::boost::winapi::GetFileInformationByHandle(rhs, &rhs_info))
::boost::process::detail::throw_last_error("GetFileInformationByHandle");
return (lhs_info.nFileIndexHigh == rhs_info.nFileIndexHigh)

View File

@@ -7,8 +7,8 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/winapi/error_codes.hpp>
#include <boost/winapi/process.hpp>
#include <boost/process/detail/config.hpp>
@@ -25,10 +25,10 @@ struct env_init : public ::boost::process::detail::handler_base
env_init(boost::process::basic_environment<Char> && env) : env(std::move(env)) {};
env_init(const boost::process::basic_environment<Char> & env) : env(env) {};
constexpr static ::boost::detail::winapi::DWORD_ creation_flag(char) {return 0u;}
constexpr static ::boost::detail::winapi::DWORD_ creation_flag(wchar_t)
constexpr static ::boost::winapi::DWORD_ creation_flag(char) {return 0u;}
constexpr static ::boost::winapi::DWORD_ creation_flag(wchar_t)
{
return ::boost::detail::winapi::CREATE_UNICODE_ENVIRONMENT_;
return ::boost::winapi::CREATE_UNICODE_ENVIRONMENT_;
}
template <class WindowsExecutor>
@@ -37,7 +37,7 @@ struct env_init : public ::boost::process::detail::handler_base
auto e = env.native_handle();
if (*e == null_char<char>())
{
exec.set_error(std::error_code(::boost::detail::winapi::ERROR_BAD_ENVIRONMENT_, std::system_category()),
exec.set_error(std::error_code(::boost::winapi::ERROR_BAD_ENVIRONMENT_, std::system_category()),
"Empty Environment");
}

View File

@@ -1,356 +1,354 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/detail/winapi/environment.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/detail/winapi/get_current_process.hpp>
#include <boost/detail/winapi/get_current_process_id.hpp>
#include <algorithm>
#include <boost/process/locale.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Char>
class native_environment_impl
{
static void _deleter(Char* p) {boost::detail::winapi::free_environment_strings(p);};
std::unique_ptr<Char[], void(*)(Char*)> _buf{boost::detail::winapi::get_environment_strings<Char>(), &native_environment_impl::_deleter};
static inline std::vector<Char*> _load_var(Char* p);
std::vector<Char*> _env_arr{_load_var(_buf.get())};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = pointer_type;
void reload()
{
_buf.reset(boost::detail::winapi::get_environment_strings<Char>());
_env_arr = _load_var(_buf.get());
_env_impl = &*_env_arr.begin();
}
string_type get(const pointer_type id);
void set(const pointer_type id, const pointer_type value);
void reset(const pointer_type id);
string_type get(const string_type & id) {return get(id.c_str());}
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
void reset(const string_type & id) {reset(id.c_str());}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
Char ** _env_impl = &*_env_arr.begin();
native_handle_type native_handle() const {return _buf.get();}
};
template<typename Char>
inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_type
{
Char buf[4096];
auto size = boost::detail::winapi::get_environment_variable(id, buf, sizeof(buf));
if (size == 0) //failed
{
auto err = ::boost::detail::winapi::GetLastError();
if (err == ::boost::detail::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
return "";
else
throw process_error(std::error_code(err, std::system_category()),
"GetEnvironmentVariable() failed");
}
if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
{
/*limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
* but I used 32768 so it is a multiple of 4096.
*/
constexpr static std::size_t max_size = 32768;
//Handle variables longer then buf.
std::size_t buf_size = sizeof(buf);
while (buf_size <= max_size)
{
std::vector<Char> buf(buf_size);
auto size = boost::detail::winapi::get_environment_variable(id, buf.data(), buf.size());
if (size == buf_size) //buffer to small
buf_size *= 2;
else if (size == 0)
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
else
return std::basic_string<Char>(
buf.data(), buf.data()+ size + 1);
}
}
return std::basic_string<Char>(buf, buf+size+1);
}
template<typename Char>
inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value)
{
boost::detail::winapi::set_environment_variable(id, value);
}
template<typename Char>
inline void native_environment_impl<Char>::reset(const pointer_type id)
{
boost::detail::winapi::set_environment_variable(id, nullptr);
}
template<typename Char>
std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p)
{
std::vector<Char*> ret;
if (*p != null_char<Char>())
{
ret.push_back(p);
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
{
if (*p==null_char<Char>())
{
p++;
ret.push_back(p);
}
else
p++;
}
}
p++;
ret.push_back(nullptr);
return ret;
}
template<typename Char>
struct basic_environment_impl
{
std::vector<Char> _data = {null_char<Char>()};
static std::vector<Char*> _load_var(Char* p);
std::vector<Char*> _env_arr{_load_var(_data.data())};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = pointer_type;
std::size_t size() const { return _data.size();}
void reload()
{
_env_arr = _load_var(_data.data());
_env_impl = _env_arr.data();
}
string_type get(const pointer_type id) {return get(string_type(id));}
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
void reset(const pointer_type id) {reset(string_type(id));}
string_type get(const string_type & id);
void set(const string_type & id, const string_type & value);
void reset(const string_type & id);
inline basic_environment_impl(const native_environment_impl<Char> & nei);
basic_environment_impl() = default;
basic_environment_impl(const basic_environment_impl& rhs)
: _data(rhs._data)
{
}
basic_environment_impl(basic_environment_impl && rhs)
: _data(std::move(rhs._data)),
_env_arr(std::move(rhs._env_arr)),
_env_impl(_env_arr.data())
{
}
basic_environment_impl &operator=(basic_environment_impl && rhs)
{
_data = std::move(rhs._data);
//reload();
_env_arr = std::move(rhs._env_arr);
_env_impl = _env_arr.data();
return *this;
}
basic_environment_impl & operator=(const basic_environment_impl& rhs)
{
_data = rhs._data;
reload();
return *this;
}
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(::boost::process::detail::convert(rhs._data, cv))
{
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
}
Char ** _env_impl = &*_env_arr.begin();
native_handle_type native_handle() const {return &*_data.begin();}
};
template<typename Char>
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
{
auto beg = nei.native_handle();
auto p = beg;
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
p++;
p++; //pointing to the second nullchar
p++; //to get the pointer behing the second nullchar, so it's end.
this->_data.assign(beg, p);
this->reload();
}
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
return string_type(_data.data()); //null-char is handled by the string.
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
seq.insert(seq.end(), id.begin(), id.end());
seq.push_back('=');
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
if (itr == _data.end()) //not found
return "";
itr += seq.size(); //advance to the value behind the '='; the std::string will take care of finding the null-char.
return string_type(&*itr);
}
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
reset(id);
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/winapi/error_codes.hpp>
#include <boost/winapi/environment.hpp>
#include <boost/winapi/get_current_process.hpp>
#include <boost/winapi/get_current_process_id.hpp>
#include <boost/process/detail/config.hpp>
#include <algorithm>
#include <boost/process/locale.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Char>
class native_environment_impl
{
static void _deleter(Char* p) {boost::winapi::free_environment_strings(p);};
std::unique_ptr<Char[], void(*)(Char*)> _buf{boost::winapi::get_environment_strings<Char>(), &native_environment_impl::_deleter};
static inline std::vector<Char*> _load_var(Char* p);
std::vector<Char*> _env_arr{_load_var(_buf.get())};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = pointer_type;
void reload()
{
_buf.reset(boost::winapi::get_environment_strings<Char>());
_env_arr = _load_var(_buf.get());
_env_impl = &*_env_arr.begin();
}
string_type get(const pointer_type id);
void set(const pointer_type id, const pointer_type value);
void reset(const pointer_type id);
string_type get(const string_type & id) {return get(id.c_str());}
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
void reset(const string_type & id) {reset(id.c_str());}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
Char ** _env_impl = &*_env_arr.begin();
native_handle_type native_handle() const {return _buf.get();}
};
template<typename Char>
inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_type
{
Char buf[4096];
auto size = boost::winapi::get_environment_variable(id, buf, sizeof(buf));
if (size == 0) //failed
{
auto err = ::boost::winapi::GetLastError();
if (err == ::boost::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
return "";
else
throw process_error(std::error_code(err, std::system_category()),
"GetEnvironmentVariable() failed");
}
if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
{
/*limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
* but I used 32768 so it is a multiple of 4096.
*/
constexpr static std::size_t max_size = 32768;
//Handle variables longer then buf.
std::size_t buf_size = sizeof(buf);
while (buf_size <= max_size)
{
std::vector<Char> buf(buf_size);
auto size = boost::winapi::get_environment_variable(id, buf.data(), buf.size());
if (size == buf_size) //buffer to small
buf_size *= 2;
else if (size == 0)
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
else
return std::basic_string<Char>(
buf.data(), buf.data()+ size + 1);
}
}
return std::basic_string<Char>(buf, buf+size+1);
}
template<typename Char>
inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value)
{
boost::winapi::set_environment_variable(id, value);
}
template<typename Char>
inline void native_environment_impl<Char>::reset(const pointer_type id)
{
boost::winapi::set_environment_variable(id, nullptr);
}
template<typename Char>
std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p)
{
std::vector<Char*> ret;
if (*p != null_char<Char>())
{
ret.push_back(p);
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
{
if (*p==null_char<Char>())
{
p++;
ret.push_back(p);
}
else
p++;
}
}
p++;
ret.push_back(nullptr);
return ret;
}
template<typename Char>
struct basic_environment_impl
{
std::vector<Char> _data = {null_char<Char>()};
static std::vector<Char*> _load_var(Char* p);
std::vector<Char*> _env_arr{_load_var(_data.data())};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = pointer_type;
std::size_t size() const { return _data.size();}
void reload()
{
_env_arr = _load_var(_data.data());
_env_impl = _env_arr.data();
}
string_type get(const pointer_type id) {return get(string_type(id));}
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
void reset(const pointer_type id) {reset(string_type(id));}
string_type get(const string_type & id);
void set(const string_type & id, const string_type & value);
void reset(const string_type & id);
inline basic_environment_impl(const native_environment_impl<Char> & nei);
basic_environment_impl() = default;
basic_environment_impl(const basic_environment_impl& rhs)
: _data(rhs._data)
{
}
basic_environment_impl(basic_environment_impl && rhs)
: _data(std::move(rhs._data)),
_env_arr(std::move(rhs._env_arr)),
_env_impl(_env_arr.data())
{
}
basic_environment_impl &operator=(basic_environment_impl && rhs)
{
_data = std::move(rhs._data);
//reload();
_env_arr = std::move(rhs._env_arr);
_env_impl = _env_arr.data();
return *this;
}
basic_environment_impl & operator=(const basic_environment_impl& rhs)
{
_data = rhs._data;
reload();
return *this;
}
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(::boost::process::detail::convert(rhs._data, cv))
{
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
}
Char ** _env_impl = &*_env_arr.begin();
native_handle_type native_handle() const {return &*_data.begin();}
};
template<typename Char>
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
{
auto beg = nei.native_handle();
auto p = beg;
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
p++;
p++; //pointing to the second nullchar
p++; //to get the pointer behing the second nullchar, so it's end.
this->_data.assign(beg, p);
this->reload();
}
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
return string_type(_data.data()); //null-char is handled by the string.
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
seq.insert(seq.end(), id.begin(), id.end());
seq.push_back('=');
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
if (itr == _data.end()) //not found
return "";
itr += seq.size(); //advance to the value behind the '='; the std::string will take care of finding the null-char.
return string_type(&*itr);
}
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
reset(id);
std::vector<Char> insertion;
std::vector<Char> insertion;
insertion.insert(insertion.end(), id.begin(), id.end());
insertion.push_back('=');
insertion.insert(insertion.end(), value.begin(), value.end());
insertion.push_back('\0');
insertion.insert(insertion.end(), id.begin(), id.end());
insertion.push_back('=');
insertion.insert(insertion.end(), value.begin(), value.end());
insertion.push_back('\0');
_data.insert(_data.end() -1, insertion.begin(), insertion.end());
_data.insert(_data.end() -1, insertion.begin(), insertion.end());
reload();
}
reload();
}
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
//ok, we need to check the size of data first
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
return;
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
//ok, we need to check the size of data first
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
return;
//check if it's the first one, spares us the search.
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
{
auto beg = _data.begin();
auto end = beg;
//check if it's the first one, spares us the search.
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
{
auto beg = _data.begin();
auto end = beg;
while (*end != '\0')
end++;
while (*end != '\0')
end++;
end++; //to point behind the last null-char
end++; //to point behind the last null-char
_data.erase(beg, end); //and remove the thingy
_data.erase(beg, end); //and remove the thingy
}
}
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
seq.insert(seq.end(), id.begin(), id.end());
seq.push_back('=');
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
seq.insert(seq.end(), id.begin(), id.end());
seq.push_back('=');
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
if (itr == _data.end())
return;//nothing to return if it's empty anyway...
if (itr == _data.end())
return;//nothing to return if it's empty anyway...
auto end = itr;
auto end = itr;
while (*end != '\0')
end++;
while (*++end != '\0');
end ++; //to point behind the last null-char
_data.erase(itr, end);//and remove it
reload();
_data.erase(itr, end);//and remove it
reload();
}
}
template<typename Char>
std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p)
{
std::vector<Char*> ret;
if (*p != null_char<Char>())
{
ret.push_back(p);
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
{
if (*p==null_char<Char>())
{
p++;
ret.push_back(p);
}
else
p++;
}
}
p++;
ret.push_back(nullptr);
return ret;
}
template<typename Char>
std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p)
{
std::vector<Char*> ret;
if (*p != null_char<Char>())
{
ret.push_back(p);
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
{
if (*p==null_char<Char>())
{
p++;
ret.push_back(p);
}
else
p++;
}
}
p++;
ret.push_back(nullptr);
return ret;
}
template<typename T> constexpr T env_seperator();
template<> constexpr char env_seperator() {return ';'; }
template<> constexpr wchar_t env_seperator() {return L';'; }
template<typename T> constexpr T env_seperator();
template<> constexpr char env_seperator() {return ';'; }
template<> constexpr wchar_t env_seperator() {return L';'; }
inline int get_id() {return boost::detail::winapi::GetCurrentProcessId();}
inline void* native_handle() {return boost::detail::winapi::GetCurrentProcess(); }
inline int get_id() {return boost::winapi::GetCurrentProcessId();}
inline void* native_handle() {return boost::winapi::GetCurrentProcess(); }
typedef void* native_handle_t;
typedef void* native_handle_t;
}
}
}
}
}
}
}
}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */

View File

@@ -16,8 +16,8 @@
#include <boost/process/detail/traits.hpp>
#include <boost/process/error.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/process.hpp>
#include <boost/none.hpp>
#include <system_error>
#include <memory>
@@ -33,13 +33,13 @@ template<typename CharType> struct startup_info;
template<> struct startup_info<char>
{
typedef ::boost::detail::winapi::STARTUPINFOA_ type;
typedef ::boost::winapi::STARTUPINFOA_ type;
};
#endif
template<> struct startup_info<wchar_t>
{
typedef ::boost::detail::winapi::STARTUPINFOW_ type;
typedef ::boost::winapi::STARTUPINFOW_ type;
};
#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
@@ -49,13 +49,13 @@ template<typename CharType> struct startup_info_ex;
#if !defined( BOOST_NO_ANSI_APIS )
template<> struct startup_info_ex<char>
{
typedef ::boost::detail::winapi::STARTUPINFOEXA_ type;
typedef ::boost::winapi::STARTUPINFOEXA_ type;
};
#endif
template<> struct startup_info_ex<wchar_t>
{
typedef ::boost::detail::winapi::STARTUPINFOEXW_ type;
typedef ::boost::winapi::STARTUPINFOEXW_ type;
};
@@ -66,7 +66,7 @@ template<> struct startup_info_ex<wchar_t>
template<typename CharT>
struct startup_info_impl
{
::boost::detail::winapi::DWORD_ creation_flags = 0;
::boost::winapi::DWORD_ creation_flags = 0;
typedef typename startup_info_ex<CharT>::type startup_info_ex_t;
typedef typename startup_info<CharT>::type startup_info_t;
@@ -74,9 +74,9 @@ struct startup_info_impl
startup_info_ex_t startup_info_ex
{startup_info_t {sizeof(startup_info_t), nullptr, nullptr, nullptr,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr,
::boost::detail::winapi::invalid_handle_value,
::boost::detail::winapi::invalid_handle_value,
::boost::detail::winapi::invalid_handle_value},
::boost::winapi::invalid_handle_value,
::boost::winapi::invalid_handle_value,
::boost::winapi::invalid_handle_value},
nullptr
};
startup_info_t & startup_info = startup_info_ex.StartupInfo;
@@ -84,7 +84,7 @@ struct startup_info_impl
void set_startup_info_ex()
{
startup_info.cb = sizeof(startup_info_ex_t);
creation_flags = ::boost::detail::winapi::EXTENDED_STARTUPINFO_PRESENT_;
creation_flags |= ::boost::winapi::EXTENDED_STARTUPINFO_PRESENT_;
}
};
@@ -96,13 +96,13 @@ struct startup_info_impl
{
typedef typename startup_info<CharT>::type startup_info_t;
::boost::detail::winapi::DWORD_ creation_flags = 0;
::boost::winapi::DWORD_ creation_flags = 0;
startup_info_t startup_info
{sizeof(startup_info_t), nullptr, nullptr, nullptr,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr,
::boost::detail::winapi::invalid_handle_value,
::boost::detail::winapi::invalid_handle_value,
::boost::detail::winapi::invalid_handle_value};
::boost::winapi::invalid_handle_value,
::boost::winapi::invalid_handle_value,
::boost::winapi::invalid_handle_value};
};
#endif
@@ -186,7 +186,7 @@ public:
}
//NOTE: The non-cast cmd-line string can only be modified by the wchar_t variant which is currently disabled.
int err_code = ::boost::detail::winapi::create_process(
int err_code = ::boost::winapi::create_process(
exe, // LPCSTR_ lpApplicationName,
const_cast<Char*>(cmd_line), // LPSTR_ lpCommandLine,
proc_attrs, // LPSECURITY_ATTRIBUTES_ lpProcessAttributes,
@@ -232,9 +232,9 @@ public:
const std::error_code& error() const {return _ec;}
::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr;
::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr;
::boost::detail::winapi::BOOL_ inherit_handles = false;
::boost::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr;
::boost::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr;
::boost::winapi::BOOL_ inherit_handles = false;
const Char * work_dir = nullptr;
const Char * cmd_line = nullptr;
const Char * exe = nullptr;
@@ -242,7 +242,7 @@ public:
Sequence & seq;
::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
::boost::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
};

View File

@@ -1,104 +1,112 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <string>
#include <boost/filesystem/path.hpp>
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/file_management.hpp>
#include <string>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
struct file_descriptor
{
enum mode_t
{
read = 1,
write = 2,
read_write = 3
};
static ::boost::detail::winapi::DWORD_ desired_access(mode_t mode)
{
switch(mode)
{
case read:
return ::boost::detail::winapi::GENERIC_READ_;
case write:
return ::boost::detail::winapi::GENERIC_WRITE_;
case read_write:
return ::boost::detail::winapi::GENERIC_READ_
| ::boost::detail::winapi::GENERIC_WRITE_;
default:
return 0u;
}
}
struct file_descriptor
{
enum mode_t
{
read = 1,
write = 2,
read_write = 3
};
static ::boost::winapi::DWORD_ desired_access(mode_t mode)
{
switch(mode)
{
case read:
return ::boost::winapi::GENERIC_READ_;
case write:
return ::boost::winapi::GENERIC_WRITE_;
case read_write:
return ::boost::winapi::GENERIC_READ_
| ::boost::winapi::GENERIC_WRITE_;
default:
return 0u;
}
}
file_descriptor() = default;
file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
file_descriptor() = default;
file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
file_descriptor(const std::string & path , mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
file_descriptor(const std::wstring & path, mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
file_descriptor(const std::string & path , mode_t mode = read_write)
#if defined(BOOST_NO_ANSI_APIS)
: file_descriptor(::boost::process::detail::convert(path), mode)
#else
: file_descriptor(path.c_str(), mode)
#endif
{}
file_descriptor(const std::wstring & path, mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
file_descriptor(const char* path, mode_t mode = read_write)
: _handle(
::boost::detail::winapi::create_file(
path,
desired_access(mode),
::boost::detail::winapi::FILE_SHARE_READ_ |
::boost::detail::winapi::FILE_SHARE_WRITE_,
nullptr,
::boost::detail::winapi::OPEN_ALWAYS_,
file_descriptor(const char* path, mode_t mode = read_write)
#if defined(BOOST_NO_ANSI_APIS)
: file_descriptor(std::string(path), mode)
#else
: _handle(
::boost::winapi::create_file(
path,
desired_access(mode),
::boost::winapi::FILE_SHARE_READ_ |
::boost::winapi::FILE_SHARE_WRITE_,
nullptr,
::boost::winapi::OPEN_ALWAYS_,
::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr
))
{
::boost::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr
))
#endif
{
}
file_descriptor(const wchar_t * path, mode_t mode = read_write)
: _handle(
::boost::winapi::create_file(
path,
desired_access(mode),
::boost::winapi::FILE_SHARE_READ_ |
::boost::winapi::FILE_SHARE_WRITE_,
nullptr,
::boost::winapi::OPEN_ALWAYS_,
}
file_descriptor(const wchar_t * path, mode_t mode = read_write)
: _handle(
::boost::detail::winapi::create_file(
path,
desired_access(mode),
::boost::detail::winapi::FILE_SHARE_READ_ |
::boost::detail::winapi::FILE_SHARE_WRITE_,
nullptr,
::boost::detail::winapi::OPEN_ALWAYS_,
::boost::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr
))
{
::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr
))
{
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
~file_descriptor()
{
if (_handle != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_handle);
}
~file_descriptor()
{
if (_handle != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_handle);
}
::boost::winapi::HANDLE_ handle() const { return _handle;}
::boost::detail::winapi::HANDLE_ handle() const { return _handle;}
private:
::boost::winapi::HANDLE_ _handle = ::boost::winapi::INVALID_HANDLE_VALUE_;
};
private:
::boost::detail::winapi::HANDLE_ _handle = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
};
}}}}
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */

View File

@@ -1,44 +1,48 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
#include <io.h>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
#include <io.h>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
struct file_in : public ::boost::process::detail::handler_base
{
file_descriptor file;
::boost::detail::winapi::HANDLE_ handle = file.handle();
struct file_in : public ::boost::process::detail::handler_base,
::boost::process::detail::uses_handles
{
file_descriptor file;
::boost::winapi::HANDLE_ handle = file.handle();
template<typename T>
file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {}
file_in(FILE * f) : handle(reinterpret_cast<::boost::detail::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdInput = handle;
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
};
template<typename T>
file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {}
file_in(FILE * f) : handle(reinterpret_cast<::boost::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}
}}}}
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdInput = handle;
e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
};
#endif
}}}}
#endif

View File

@@ -1,77 +1,82 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct file_out : public ::boost::process::detail::handler_base
{
file_descriptor file;
::boost::detail::winapi::HANDLE_ handle = file.handle();
template<int p1, int p2>
struct file_out : public ::boost::process::detail::handler_base,
::boost::process::detail::uses_handles
{
file_descriptor file;
::boost::winapi::HANDLE_ handle = file.handle();
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write) {}
file_out(FILE * f) : handle(reinterpret_cast<void*>(_get_osfhandle(_fileno(f)))) {}
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
template <typename WindowsExecutor>
inline void on_setup(WindowsExecutor &e) const;
};
template<>
template<typename WindowsExecutor>
void file_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write) {}
file_out(FILE * f) : handle(reinterpret_cast<void*>(_get_osfhandle(_fileno(f)))) {}
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template <typename WindowsExecutor>
inline void on_setup(WindowsExecutor &e) const;
};
template<>
template<typename WindowsExecutor>
void file_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
template<>
template<typename WindowsExecutor>
void file_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void file_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
template<>
template<typename WindowsExecutor>
void file_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
}}}}
template<>
template<typename WindowsExecutor>
void file_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
#endif
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
}}}}
#endif

View File

@@ -7,14 +7,14 @@
#define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_
#include <boost/process/detail/windows/handler.hpp>
#include <boost/detail/winapi/jobs.hpp>
#include <boost/winapi/jobs.hpp>
#include <boost/process/detail/windows/child_handle.hpp>
#include <boost/process/detail/windows/job_workaround.hpp>
#include <system_error>
namespace boost { namespace process { namespace detail { namespace windows {
inline bool break_away_enabled(::boost::detail::winapi::HANDLE_ h)
inline bool break_away_enabled(::boost::winapi::HANDLE_ h)
{
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
@@ -29,7 +29,7 @@ inline bool break_away_enabled(::boost::detail::winapi::HANDLE_ h)
return (info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0;
}
inline void enable_break_away(::boost::detail::winapi::HANDLE_ h)
inline void enable_break_away(::boost::winapi::HANDLE_ h)
{
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
@@ -54,7 +54,7 @@ inline void enable_break_away(::boost::detail::winapi::HANDLE_ h)
throw_last_error("SetInformationJobObject() failed");
}
inline void enable_break_away(::boost::detail::winapi::HANDLE_ h, std::error_code & ec)
inline void enable_break_away(::boost::winapi::HANDLE_ h, std::error_code & ec)
{
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
@@ -84,71 +84,92 @@ inline void enable_break_away(::boost::detail::winapi::HANDLE_ h, std::error_cod
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::detail::winapi::HANDLE_ _job_object;
::boost::winapi::HANDLE_ _job_object;
::boost::winapi::HANDLE_ _io_port;
typedef ::boost::detail::winapi::HANDLE_ handle_t;
typedef ::boost::winapi::HANDLE_ handle_t;
handle_t handle() const { return _job_object; }
explicit group_handle(handle_t h) :
_job_object(h)
_job_object(h),
_io_port(::CreateIoCompletionPort(::boost::winapi::INVALID_HANDLE_VALUE_, nullptr, 0, 1))
{
enable_break_away(_job_object);
associate_completion_port(_job_object, _io_port);
}
group_handle() : group_handle(::boost::detail::winapi::CreateJobObjectA(nullptr, nullptr))
group_handle() : group_handle(::boost::winapi::CreateJobObjectW(nullptr, nullptr))
{
}
~group_handle()
{
::boost::detail::winapi::CloseHandle(_job_object);
::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::detail::winapi::invalid_handle_value;
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::detail::winapi::CloseHandle(_job_object);
::boost::winapi::CloseHandle(_job_object);
_job_object = c._job_object;
c._job_object = ::boost::detail::winapi::invalid_handle_value;
c._job_object = ::boost::winapi::invalid_handle_value;
return *this;
}
void add(handle_t proc)
{
if (!::boost::detail::winapi::AssignProcessToJobObject(_job_object, proc))
if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc))
throw_last_error();
}
void add(handle_t proc, std::error_code & ec) noexcept
{
if (!::boost::detail::winapi::AssignProcessToJobObject(_job_object, proc))
if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc))
ec = get_last_error();
}
bool has(handle_t proc)
{
::boost::detail::winapi::BOOL_ is;
if (!::boost::detail::winapi::IsProcessInJob(proc, _job_object, &is))
::boost::winapi::BOOL_ is;
if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is))
throw_last_error();
return is!=0;
}
bool has(handle_t proc, std::error_code & ec) noexcept
{
::boost::detail::winapi::BOOL_ is;
if (!::boost::detail::winapi::IsProcessInJob(proc, _job_object, &is))
::boost::winapi::BOOL_ is;
if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is))
ec = get_last_error();
return is!=0;
}
@@ -162,13 +183,13 @@ struct group_handle
inline void terminate(const group_handle &p)
{
if (!::boost::detail::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
boost::process::detail::throw_last_error("TerminateJobObject() failed");
}
inline void terminate(const group_handle &p, std::error_code &ec) noexcept
{
if (!::boost::detail::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
ec = boost::process::detail::get_last_error();
else
ec.clear();
@@ -176,8 +197,8 @@ inline void terminate(const group_handle &p, std::error_code &ec) noexcept
inline bool in_group()
{
::boost::detail::winapi::BOOL_ res;
if (!::boost::detail::winapi::IsProcessInJob(boost::detail::winapi::GetCurrentProcess(), nullptr, &res))
::boost::winapi::BOOL_ res;
if (!::boost::winapi::IsProcessInJob(boost::winapi::GetCurrentProcess(), nullptr, &res))
throw_last_error("IsProcessInJob failed");
return res!=0;

View File

@@ -6,9 +6,10 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_REF_HPP_
#include <boost/winapi/process.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/windows/group_handle.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/handler.hpp>
namespace boost { namespace process {
@@ -17,9 +18,11 @@ namespace detail { namespace windows {
struct group_ref : handler_base_ext
struct group_ref : handler_base_ext, ::boost::process::detail::uses_handles
{
::boost::detail::winapi::HANDLE_ handle;
::boost::winapi::HANDLE_ handle;
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
explicit group_ref(group_handle &g) :
handle(g.handle())
@@ -30,14 +33,14 @@ struct group_ref : handler_base_ext
{
//I can only enable this if the current process supports breakaways.
if (in_group() && break_away_enabled(nullptr))
exec.creation_flags |= boost::detail::winapi::CREATE_BREAKAWAY_FROM_JOB_;
exec.creation_flags |= boost::winapi::CREATE_BREAKAWAY_FROM_JOB_;
}
template <class Executor>
void on_success(Executor& exec) const
{
if (!::boost::detail::winapi::AssignProcessToJobObject(handle, exec.proc_info.hProcess))
if (!::boost::winapi::AssignProcessToJobObject(handle, exec.proc_info.hProcess))
exec.set_error(::boost::process::detail::get_last_error(),
"AssignProcessToJobObject() failed.");

View File

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

View File

@@ -1,20 +1,20 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
//does not extend anything.
struct handler_base_ext : handler_base {};
//does not extend anything.
struct handler_base_ext : handler_base {};
}}}}
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_ */
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_ */

View File

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

View File

@@ -1,160 +1,160 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
#define BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
#ifndef BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_
#define BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/windows/object_handle.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/windows/object_handle.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <functional>
#include <type_traits>
#include <memory>
#include <atomic>
#include <vector>
#include <functional>
#include <type_traits>
#include <memory>
#include <atomic>
#include <vector>
#include <boost/type_index.hpp>
#include <boost/type_index.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Executor>
struct on_exit_handler_transformer
{
Executor & exec;
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
template<typename Sig>
struct result;
template<typename Executor>
struct on_exit_handler_transformer
{
Executor & exec;
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
template<typename Sig>
struct result;
template<typename T>
struct result<on_exit_handler_transformer<Executor>(T&)>
{
typedef typename T::on_exit_handler_t type;
};
template<typename T>
struct result<on_exit_handler_transformer<Executor>(T&)>
{
typedef typename T::on_exit_handler_t type;
};
template<typename T>
auto operator()(T& t) const -> typename T::on_exit_handler_t
{
return t.on_exit_handler(exec);
}
};
template<typename T>
auto operator()(T& t) const -> typename T::on_exit_handler_t
{
return t.on_exit_handler(exec);
}
};
template<typename Executor>
struct async_handler_collector
{
Executor & exec;
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
template<typename Executor>
struct async_handler_collector
{
Executor & exec;
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
async_handler_collector(Executor & exec,
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
: exec(exec), handlers(handlers) {}
async_handler_collector(Executor & exec,
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
: exec(exec), handlers(handlers) {}
template<typename T>
void operator()(T & t) const
{
handlers.push_back(t.on_exit_handler(exec));
}
};
template<typename T>
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.
struct io_service_ref : boost::process::detail::handler_base
{
//Also set's up waiting for the exit, so it can close async stuff.
struct io_context_ref : boost::process::detail::handler_base
{
io_service_ref(boost::asio::io_service & ios)
: ios(ios)
{
}
boost::asio::io_service &get() {return ios;};
io_context_ref(boost::asio::io_context & ios)
: ios(ios)
{
}
boost::asio::io_context &get() {return ios;};
template <class Executor>
void on_success(Executor& exec) const
{
auto asyncs = boost::fusion::filter_if<
is_async_handler<
typename std::remove_reference< boost::mpl::_ > ::type
>>(exec.seq);
template <class Executor>
void on_success(Executor& exec) const
{
auto asyncs = boost::fusion::filter_if<
is_async_handler<
typename std::remove_reference< boost::mpl::_ > ::type
>>(exec.seq);
//ok, check if there are actually any.
if (boost::fusion::empty(asyncs))
{
return;
}
//ok, check if there are actually any.
if (boost::fusion::empty(asyncs))
{
return;
}
::boost::detail::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info;
auto this_proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info;
auto this_proc = ::boost::winapi::GetCurrentProcess();
auto proc_in = proc.hProcess;;
::boost::detail::winapi::HANDLE_ process_handle;
auto proc_in = proc.hProcess;;
::boost::winapi::HANDLE_ process_handle;
if (!::boost::detail::winapi::DuplicateHandle(
this_proc, proc_in, this_proc, &process_handle, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
if (!::boost::winapi::DuplicateHandle(
this_proc, proc_in, this_proc, &process_handle, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
exec.set_error(::boost::process::detail::get_last_error(),
"Duplicate Pipe Failed");
exec.set_error(::boost::process::detail::get_last_error(),
"Duplicate Pipe Failed");
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
funcs.reserve(boost::fusion::size(asyncs));
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
funcs.reserve(boost::fusion::size(asyncs));
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status);
wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status);
auto handle_p = wh.handle.get();
handle_p->async_wait(std::move(wh));
}
auto handle_p = wh.handle.get();
handle_p->async_wait(std::move(wh));
}
struct wait_handler
{
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
std::unique_ptr<boost::asio::windows::object_handle> handle;
std::shared_ptr<std::atomic<int>> exit_status;
wait_handler(const wait_handler & ) = delete;
wait_handler(wait_handler && ) = default;
wait_handler(std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
boost::asio::io_service & 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)),
exit_status(exit_status)
{
struct wait_handler
{
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
std::unique_ptr<boost::asio::windows::object_handle> handle;
std::shared_ptr<std::atomic<int>> exit_status;
wait_handler(const wait_handler & ) = delete;
wait_handler(wait_handler && ) = default;
wait_handler(std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
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.get_executor(), handle)),
exit_status(exit_status)
{
}
void operator()(const boost::system::error_code & ec_in)
{
std::error_code ec;
if (ec_in)
ec = std::error_code(ec_in.value(), std::system_category());
}
void operator()(const boost::system::error_code & ec_in)
{
std::error_code ec;
if (ec_in)
ec = std::error_code(ec_in.value(), std::system_category());
::boost::detail::winapi::DWORD_ code;
::boost::detail::winapi::GetExitCodeProcess(handle->native(), &code);
exit_status->store(code);
::boost::winapi::DWORD_ code;
::boost::winapi::GetExitCodeProcess(handle->native_handle(), &code);
exit_status->store(code);
for (auto & func : funcs)
func(code, ec);
}
for (auto & func : funcs)
func(code, ec);
}
};
};
private:
boost::asio::io_service &ios;
};
private:
boost::asio::io_context &ios;
};
}}}}
}}}}
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
#endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */

View File

@@ -9,36 +9,20 @@
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <cstdlib>
#include <boost/detail/winapi/process.hpp>
#include <boost/winapi/process.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
constexpr static ::boost::detail::winapi::DWORD_ still_active = 259;
constexpr static ::boost::winapi::DWORD_ still_active = 259;
struct child_handle;
inline bool is_running(const child_handle &p, int & exit_code)
{
::boost::detail::winapi::DWORD_ code;
//single value, not needed in the winapi.
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &code))
::boost::process::detail::throw_last_error("GetExitCodeProcess() failed");
if (code == still_active)
return true;
else
{
exit_code = code;
return false;
}
}
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
::boost::detail::winapi::DWORD_ code;
::boost::winapi::DWORD_ code;
//single value, not needed in the winapi.
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &code))
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &code))
ec = ::boost::process::detail::get_last_error();
else
ec.clear();
@@ -49,7 +33,15 @@ inline bool is_running(const child_handle &p, int & exit_code, std::error_code &
{
exit_code = code;
return false;
}
}
}
inline bool is_running(const child_handle &p, int & exit_code)
{
std::error_code ec;
bool b = is_running(p, exit_code, ec);
boost::process::detail::throw_error(ec, "GetExitCodeProcess() failed in is_running");
return b;
}
inline bool is_running(int code)

View File

@@ -6,71 +6,187 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_
#include <boost/detail/winapi/config.hpp>
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/dll.hpp>
#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::detail::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit;
::boost::detail::winapi::LARGE_INTEGER_ PerJobUserTimeLimit;
::boost::detail::winapi::DWORD_ LimitFlags;
::boost::detail::winapi::SIZE_T_ MinimumWorkingSetSize;
::boost::detail::winapi::SIZE_T_ MaximumWorkingSetSize;
::boost::detail::winapi::DWORD_ ActiveProcessLimit;
::boost::detail::winapi::ULONG_PTR_ Affinity;
::boost::detail::winapi::DWORD_ PriorityClass;
::boost::detail::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::detail::winapi::ULONGLONG_ ReadOperationCount;
::boost::detail::winapi::ULONGLONG_ WriteOperationCount;
::boost::detail::winapi::ULONGLONG_ OtherOperationCount;
::boost::detail::winapi::ULONGLONG_ ReadTransferCount;
::boost::detail::winapi::ULONGLONG_ WriteTransferCount;
::boost::detail::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::detail::winapi::SIZE_T_ ProcessMemoryLimit;
::boost::detail::winapi::SIZE_T_ JobMemoryLimit;
::boost::detail::winapi::SIZE_T_ PeakProcessMemoryUsed;
::boost::detail::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,25 +198,28 @@ typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ {
_Out_opt_ LPDWORD lpReturnLength
);
*/
typedef ::boost::detail::winapi::BOOL_ ( WINAPI *query_information_job_object_p)(
::boost::detail::winapi::HANDLE_,
typedef ::boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *query_information_job_object_p)(
::boost::winapi::HANDLE_,
JOBOBJECTINFOCLASS_,
void *,
::boost::detail::winapi::DWORD_,
::boost::detail::winapi::DWORD_ *);
::boost::winapi::DWORD_,
::boost::winapi::DWORD_ *);
inline ::boost::detail::winapi::BOOL_ WINAPI query_information_job_object(
::boost::detail::winapi::HANDLE_ hJob,
inline ::boost::winapi::BOOL_ query_information_job_object(
::boost::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
void * lpJobObjectInfo,
::boost::detail::winapi::DWORD_ cbJobObjectInfoLength,
::boost::detail::winapi::DWORD_ *lpReturnLength)
void *lpJobObjectInfo,
::boost::winapi::DWORD_ cbJobObjectInfoLength,
::boost::winapi::DWORD_ *lpReturnLength)
{
static ::boost::detail::winapi::HMODULE_ h = ::boost::detail::winapi::get_module_handle("Kernel32.dll");
static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::detail::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,30 +229,33 @@ inline ::boost::detail::winapi::BOOL_ WINAPI query_information_job_object(
_In_ DWORD cbJobObjectInfoLength
);*/
typedef ::boost::detail::winapi::BOOL_ ( WINAPI *set_information_job_object_p)(
::boost::detail::winapi::HANDLE_,
typedef ::boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *set_information_job_object_p)(
::boost::winapi::HANDLE_,
JOBOBJECTINFOCLASS_,
void *,
::boost::detail::winapi::DWORD_);
::boost::winapi::DWORD_);
}
inline ::boost::detail::winapi::BOOL_ WINAPI set_information_job_object(
::boost::detail::winapi::HANDLE_ hJob,
inline ::boost::winapi::BOOL_ set_information_job_object(
::boost::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
void * lpJobObjectInfo,
::boost::detail::winapi::DWORD_ cbJobObjectInfoLength)
void *lpJobObjectInfo,
::boost::winapi::DWORD_ cbJobObjectInfoLength)
{
static ::boost::detail::winapi::HMODULE_ h = ::boost::detail::winapi::get_module_handle("Kernel32.dll");
static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::detail::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);
}
constexpr static ::boost::detail::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800;
#endif
constexpr static ::boost::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800;
}}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_ */

View File

@@ -1,103 +1,111 @@
// Copyright (c) 2016 Klemens D. Morgenstern
// Copyright (c) 2008 Beman Dawes
//
// 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)
// Copyright (c) 2016 Klemens D. Morgenstern
// Copyright (c) 2008 Beman Dawes
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_LOCALE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_LOCALE_HPP_
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_LOCALE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_LOCALE_HPP_
#include <locale>
#include <boost/core/ignore_unused.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/detail/winapi/character_code_conversion.hpp>
#include <locale>
#include <boost/core/ignore_unused.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/winapi/character_code_conversion.hpp>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
//copied from boost.filesystem
class windows_file_codecvt
: public std::codecvt< wchar_t, char, std::mbstate_t >
{
public:
explicit windows_file_codecvt(std::size_t refs = 0)
: std::codecvt<wchar_t, char, std::mbstate_t>(refs) {}
protected:
//copied from boost.filesystem
class windows_file_codecvt
: public std::codecvt< wchar_t, char, std::mbstate_t >
{
public:
explicit windows_file_codecvt(std::size_t refs = 0)
: std::codecvt<wchar_t, char, std::mbstate_t>(refs) {}
protected:
bool do_always_noconv() const noexcept override { return false; }
bool do_always_noconv() const noexcept override { return false; }
// seems safest to assume variable number of characters since we don't
// actually know what codepage is active
int do_encoding() const noexcept override { return 0; }
// seems safest to assume variable number of characters since we don't
// actually know what codepage is active
int do_encoding() const noexcept override { return 0; }
std::codecvt_base::result do_in(std::mbstate_t& state,
const char* from, const char* from_end, const char*& from_next,
wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const override
{
boost::ignore_unused(state);
::boost::detail::winapi::UINT_ codepage = AreFileApisANSI() ?
::boost::detail::winapi::CP_ACP_ :
::boost::detail::winapi::CP_OEMCP_;
std::codecvt_base::result do_in(std::mbstate_t& state,
const char* from, const char* from_end, const char*& from_next,
wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const override
{
boost::ignore_unused(state);
int count;
if ((count = ::boost::detail::winapi::MultiByteToWideChar(codepage,
::boost::detail::winapi::MB_PRECOMPOSED_, from,
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to))) == 0)
{
return error; // conversion failed
}
auto codepage =
#if !defined(BOOST_NO_ANSI_APIS)
::boost::winapi::AreFileApisANSI() ?
::boost::winapi::CP_ACP_ :
#endif
::boost::winapi::CP_OEMCP_;
from_next = from_end;
to_next = to + count;
*to_next = L'\0';
return ok;
}
int count = 0;
if ((count = ::boost::winapi::MultiByteToWideChar(codepage,
::boost::winapi::MB_PRECOMPOSED_, from,
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to))) == 0)
{
return error; // conversion failed
}
std::codecvt_base::result do_out(std::mbstate_t & state,
const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next,
char* to, char* to_end, char*& to_next) const override
{
boost::ignore_unused(state);
auto codepage = ::boost::detail::winapi::AreFileApisANSI() ?
::boost::detail::winapi::CP_ACP_ :
::boost::detail::winapi::CP_OEMCP_;
from_next = from_end;
to_next = to + count;
*to_next = L'\0';
return ok;
}
int count;
if ((count = ::boost::detail::winapi::WideCharToMultiByte(codepage,
::boost::detail::winapi::WC_NO_BEST_FIT_CHARS_, from,
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to), 0, 0)) == 0)
{
return error; // conversion failed
}
std::codecvt_base::result do_out(std::mbstate_t & state,
const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next,
char* to, char* to_end, char*& to_next) const override
{
boost::ignore_unused(state);
auto codepage =
#if !defined(BOOST_NO_ANSI_APIS)
::boost::winapi::AreFileApisANSI() ?
::boost::winapi::CP_ACP_ :
#endif
::boost::winapi::CP_OEMCP_;
int count = 0;
from_next = from_end;
to_next = to + count;
*to_next = '\0';
return ok;
}
std::codecvt_base::result do_unshift(std::mbstate_t&,
char* /*from*/, char* /*to*/, char* & /*next*/) const override { return ok; }
if ((count = ::boost::winapi::WideCharToMultiByte(codepage,
::boost::winapi::WC_NO_BEST_FIT_CHARS_, from,
static_cast<int>(from_end - from), to, static_cast<int>(to_end - to), 0, 0)) == 0)
{
return error; // conversion failed
}
int do_length(std::mbstate_t&,
const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const override { return 0; }
from_next = from_end;
to_next = to + count;
*to_next = '\0';
return ok;
}
int do_max_length() const noexcept override { return 0; }
};
std::codecvt_base::result do_unshift(std::mbstate_t&,
char* /*from*/, char* /*to*/, char* & /*next*/) const override { return ok; }
int do_length(std::mbstate_t&,
const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const override { return 0; }
int do_max_length() const noexcept override { return 0; }
};
}
}
}
}
}
}
}
}
#endif /* BOOST_PROCESS_LOCALE_HPP_ */
#endif /* BOOST_PROCESS_LOCALE_HPP_ */

View File

@@ -1,41 +1,45 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
struct null_in : public ::boost::process::detail::handler_base
{
file_descriptor source{"NUL", file_descriptor::read};
struct null_in : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
{
file_descriptor source{"NUL", file_descriptor::read};
public:
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(source.handle(),
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
::boost::winapi::HANDLE_ get_used_handles() const { return source.handle(); }
e.startup_info.hStdInput = source.handle();
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
};
}}}}
public:
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(source.handle(),
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
#endif
e.startup_info.hStdInput = source.handle();
e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
};
}}}}
#endif

View File

@@ -1,75 +1,78 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_OUT_HPP
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct null_out : public ::boost::process::detail::handler_base
{
file_descriptor sink {"NUL", file_descriptor::write}; //works because it gets destroyed AFTER launch.
template<int p1, int p2>
struct null_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
{
file_descriptor sink {"NUL", file_descriptor::write}; //works because it gets destroyed AFTER launch.
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &e) const;
};
::boost::winapi::HANDLE_ get_used_handles() const { return sink.handle(); }
template<>
template<typename WindowsExecutor>
void null_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(sink.handle(),
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &e) const;
};
e.startup_info.hStdOutput = sink.handle();
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
template<>
template<typename WindowsExecutor>
void null_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(sink.handle(),
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
}
e.startup_info.hStdOutput = sink.handle();
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
template<>
template<typename WindowsExecutor>
void null_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(sink.handle(),
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
}
e.startup_info.hStdError = sink.handle();
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
template<>
template<typename WindowsExecutor>
void null_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(sink.handle(),
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
}
e.startup_info.hStdError = sink.handle();
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
template<>
template<typename WindowsExecutor>
void null_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(sink.handle(),
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
}
e.startup_info.hStdOutput = sink.handle();
e.startup_info.hStdError = sink.handle();
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
template<>
template<typename WindowsExecutor>
void null_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(sink.handle(),
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
}
e.startup_info.hStdOutput = sink.handle();
e.startup_info.hStdError = sink.handle();
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}}}}
}
#endif
}}}}
#endif

View File

@@ -1,40 +1,39 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
#define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
#ifndef BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
#define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/detail/winapi/process.hpp>
#include <system_error>
#include <functional>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <system_error>
#include <functional>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
struct on_exit_ : boost::process::detail::windows::async_handler
{
std::function<void(int, const std::error_code&)> handler;
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
{
struct on_exit_ : boost::process::detail::windows::async_handler
{
std::function<void(int, const std::error_code&)> handler;
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
{
}
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
{
auto handler = this->handler;
return [handler](int exit_code, const std::error_code & ec)
{
handler(static_cast<int>(exit_code), ec);
};
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)
{
handler_(static_cast<int>(exit_code), ec);
};
}
};
}
};
}}}}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */
}}}}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */

View File

@@ -1,89 +1,92 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
struct pipe_in : public ::boost::process::detail::handler_base
{
::boost::detail::winapi::HANDLE_ handle;
struct pipe_in : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
{
::boost::winapi::HANDLE_ handle;
pipe_in(::boost::detail::winapi::HANDLE_ handle) : handle(handle) {}
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
template<typename T> //async_pipe
pipe_in(T & p) : handle(p.native_source())
{
p.assign_source(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
pipe_in(::boost::winapi::HANDLE_ handle) : handle(handle) {}
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
template<typename T> //async_pipe
pipe_in(T & p) : handle(p.native_source())
{
p.assign_source(::boost::winapi::INVALID_HANDLE_VALUE_);
}
e.startup_info.hStdInput = handle;
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<typename WindowsExecutor>
void on_error(WindowsExecutor &, const std::error_code &) const
{
::boost::detail::winapi::CloseHandle(handle);
}
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
template<typename WindowsExecutor>
void on_success(WindowsExecutor &) const
{
::boost::detail::winapi::CloseHandle(handle);
}
};
e.startup_info.hStdInput = handle;
e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<typename WindowsExecutor>
void on_error(WindowsExecutor &, const std::error_code &) const
{
::boost::winapi::CloseHandle(handle);
}
class async_pipe;
template<typename WindowsExecutor>
void on_success(WindowsExecutor &) const
{
::boost::winapi::CloseHandle(handle);
}
};
struct async_pipe_in : public pipe_in
{
async_pipe &pipe;
class async_pipe;
template<typename AsyncPipe>
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_source()), pipe(p)
{
}
struct async_pipe_in : public pipe_in
{
async_pipe &pipe;
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).source().close(ec);
}
template<typename AsyncPipe>
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_source()), pipe(p)
{
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).source().close(ec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
}}}}
}}}}
#endif
#endif

View File

@@ -1,122 +1,125 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
#define BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
#ifndef BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
#define BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct pipe_out : public ::boost::process::detail::handler_base
{
::boost::detail::winapi::HANDLE_ handle;
template<int p1, int p2>
struct pipe_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
{
::boost::winapi::HANDLE_ handle;
pipe_out(::boost::detail::winapi::HANDLE_ handle) : handle(handle) {}
template<typename T>
pipe_out(T & p) : handle(p.native_sink())
{
p.assign_sink(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
::boost::winapi::HANDLE_ get_used_handles() const { return handle; }
template<typename WindowsExecutor>
void on_setup(WindowsExecutor &e) const;
pipe_out(::boost::winapi::HANDLE_ handle) : handle(handle) {}
template<typename T>
pipe_out(T & p) : handle(p.native_sink())
{
p.assign_sink(::boost::winapi::INVALID_HANDLE_VALUE_);
}
template<typename WindowsExecutor>
void on_error(WindowsExecutor &, const std::error_code &) const
{
::boost::detail::winapi::CloseHandle(handle);
}
template<typename WindowsExecutor>
void on_setup(WindowsExecutor &e) const;
template<typename WindowsExecutor>
void on_success(WindowsExecutor &) const
{
::boost::detail::winapi::CloseHandle(handle);
}
};
template<typename WindowsExecutor>
void on_error(WindowsExecutor &, const std::error_code &) const
{
::boost::winapi::CloseHandle(handle);
}
template<>
template<typename WindowsExecutor>
void pipe_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
template<typename WindowsExecutor>
void on_success(WindowsExecutor &) const
{
::boost::winapi::CloseHandle(handle);
}
};
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void pipe_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
template<>
template<typename WindowsExecutor>
void pipe_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void pipe_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void pipe_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
template<>
template<typename WindowsExecutor>
void pipe_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<int p1, int p2>
struct async_pipe_out : public pipe_out<p1, p2>
{
async_pipe &pipe;
template<typename AsyncPipe>
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink()), pipe(p)
{
}
template<int p1, int p2>
struct async_pipe_out : public pipe_out<p1, p2>
{
async_pipe &pipe;
template<typename AsyncPipe>
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink()), pipe(p)
{
}
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).sink().close(ec);
}
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).sink().close(ec);
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
}}}}
}}}}
#endif
#endif

View File

@@ -19,9 +19,8 @@
#include <array>
#include <atomic>
#include <cstdlib>
#include <boost/detail/winapi/shell.hpp>
#include <boost/winapi/shell.hpp>
#include <boost/process/environment.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
@@ -29,20 +28,46 @@ inline boost::filesystem::path search_path(
const boost::filesystem::path &filename,
const std::vector<boost::filesystem::path> &path)
{
for (const boost::filesystem::path & pp : path)
const ::boost::process::wnative_environment ne{};
typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
const auto id = L"PATHEXT";
auto itr = std::find_if(ne.cbegin(), ne.cend(),
[&](const value_type & e)
{return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
auto extensions_in = itr->to_vector();
std::vector<std::wstring> extensions((extensions_in.size() * 2) + 1);
auto it_ex = extensions.begin();
it_ex++;
it_ex = std::transform(extensions_in.begin(), extensions_in.end(), it_ex,
[](const std::wstring & ws){return boost::to_lower_copy(ws, ::boost::process::detail::process_locale());});
std::transform(extensions_in.begin(), extensions_in.end(), it_ex,
[](const std::wstring & ws){return boost::to_upper_copy(ws, ::boost::process::detail::process_locale());});
std::copy(std::make_move_iterator(extensions_in.begin()), std::make_move_iterator(extensions_in.end()), extensions.begin() + 1);
for (auto & ext : extensions)
boost::to_lower(ext);
for (const boost::filesystem::path & pp_ : path)
{
auto full = pp / filename;
std::array<std::string, 4> extensions {{ "", ".exe", ".com", ".bat" }};
auto p = pp_ / filename;
for (boost::filesystem::path ext : extensions)
{
auto p = full;
p += ext;
boost::filesystem::path pp = p;
pp += ext;
boost::system::error_code ec;
bool file = boost::filesystem::is_regular_file(p, ec);
bool file = boost::filesystem::is_regular_file(pp, ec);
if (!ec && file &&
::boost::detail::winapi::sh_get_file_info(p.string().c_str(), 0, 0, 0, ::boost::detail::winapi::SHGFI_EXETYPE_))
::boost::winapi::sh_get_file_info(pp.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))
{
return p;
return pp;
}
}
}

View File

@@ -13,15 +13,15 @@
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/filesystem/path.hpp>
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/get_system_directory.hpp>
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/get_system_directory.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
inline boost::filesystem::path shell_path()
{
::boost::detail::winapi::WCHAR_ sysdir[260];
unsigned int size = ::boost::detail::winapi::get_system_directory(sysdir, sizeof(sysdir));
::boost::winapi::WCHAR_ sysdir[260];
unsigned int size = ::boost::winapi::get_system_directory(sysdir, sizeof(sysdir));
if (!size)
throw_last_error("GetSystemDirectory() failed");
@@ -32,12 +32,12 @@ inline boost::filesystem::path shell_path()
inline boost::filesystem::path shell_path(std::error_code &ec) noexcept
{
::boost::detail::winapi::WCHAR_ sysdir[260];
unsigned int size = ::boost::detail::winapi::get_system_directory(sysdir, sizeof(sysdir));
::boost::winapi::WCHAR_ sysdir[260];
unsigned int size = ::boost::winapi::get_system_directory(sysdir, sizeof(sysdir));
boost::filesystem::path p;
if (!size)
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
::boost::winapi::GetLastError(),
std::system_category());
else
{

View File

@@ -1,39 +1,45 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
#define BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
#ifndef BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
#define BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/show_window.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/show_window.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
template<::boost::detail::winapi::WORD_ Flags>
struct show_window : ::boost::process::detail::handler_base
{
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESHOWWINDOW_;
e.startup_info.wShowWindow |= Flags;
}
};
template<::boost::winapi::WORD_ Flags>
struct show_window : ::boost::process::detail::handler_base
{
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESHOWWINDOW_;
e.startup_info.wShowWindow |= Flags;
}
};
struct create_no_window_ : public ::boost::process::detail::handler_base
{
template <class Executor>
void on_setup(Executor &exec) const
{
exec.creation_flags |= ::boost::winapi::CREATE_NO_WINDOW_;
}
};
}}}}
}}}}
#endif
#endif

View File

@@ -1,36 +1,36 @@
// 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)
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_START_DIR_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_START_DIR_HPP
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_START_DIR_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_START_DIR_HPP
#include <string>
#include <boost/process/detail/windows/handler.hpp>
#include <string>
#include <boost/process/detail/windows/handler.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Char>
struct start_dir_init : handler_base_ext
{
start_dir_init(const std::basic_string<Char> &s) : s_(s) {}
template<typename Char>
struct start_dir_init : handler_base_ext
{
start_dir_init(const std::basic_string<Char> &s) : s_(s) {}
template <class Executor>
void on_setup(Executor& exec) const
{
exec.work_dir = s_.c_str();
}
template <class Executor>
void on_setup(Executor& exec) const
{
exec.work_dir = s_.c_str();
}
const std::basic_string<Char> &str() const {return s_;}
private:
std::basic_string<Char> s_;
};
const std::basic_string<Char> &str() const {return s_;}
private:
std::basic_string<Char> s_;
};
}}}}
}}}}
#endif
#endif

View File

@@ -13,36 +13,31 @@
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <cstdlib>
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/get_last_error.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/get_last_error.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct child_handle;
inline void terminate(child_handle &p)
{
if (!::boost::detail::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
boost::process::detail::throw_last_error("TerminateProcess() failed");
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
}
inline void terminate(child_handle &p, std::error_code &ec) noexcept
{
if (!::boost::detail::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
if (!::boost::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
ec = boost::process::detail::get_last_error();
else
{
ec.clear();
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
::boost::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
}
}
inline void terminate(child_handle &p)
{
std::error_code ec;
terminate(p, ec);
boost::process::detail::throw_error(ec, "TerminateProcess() failed in terminate");
}
}}}}

View File

@@ -13,147 +13,41 @@
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/detail/winapi/synchronization.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/winapi/synchronization.hpp>
#include <boost/winapi/process.hpp>
#include <boost/process/detail/windows/child_handle.hpp>
#include <chrono>
namespace boost { namespace process { namespace detail { namespace windows {
inline void wait(child_handle &p, int & exit_code)
{
if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed)
throw_last_error("WaitForSingleObject() failed");
::boost::detail::winapi::DWORD_ _exit_code;
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
throw_last_error("GetExitCodeProcess() failed");
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
exit_code = static_cast<int>(_exit_code);
}
inline void wait(child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
::boost::detail::winapi::DWORD_ _exit_code = 1;
::boost::winapi::DWORD_ _exit_code = 1;
if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed)
if (::boost::winapi::WaitForSingleObject(p.process_handle(),
::boost::winapi::infinite) == ::boost::winapi::wait_failed)
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
::boost::winapi::GetLastError(),
std::system_category());
else if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
else if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
::boost::winapi::GetLastError(),
std::system_category());
else
ec.clear();
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
::boost::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
exit_code = static_cast<int>(_exit_code);
}
template< class Rep, class Period >
inline bool wait_for(
child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time)
inline void wait(child_handle &p, int & exit_code)
{
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
::boost::detail::winapi::DWORD_ wait_code;
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
static_cast<::boost::detail::winapi::DWORD_>(ms.count()));
if (wait_code == ::boost::detail::winapi::wait_failed)
throw_last_error("WaitForSingleObject() failed");
else if (wait_code == ::boost::detail::winapi::wait_timeout)
return false; //
::boost::detail::winapi::DWORD_ _exit_code;
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
throw_last_error("GetExitCodeProcess() failed");
exit_code = static_cast<int>(_exit_code);
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
return true;
std::error_code ec;
wait(p, exit_code, ec);
boost::process::detail::throw_error(ec, "wait error");
}
template< class Rep, class Period >
inline bool wait_for(
child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code &ec) noexcept
{
std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time);
::boost::detail::winapi::DWORD_ wait_code;
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
static_cast<::boost::detail::winapi::DWORD_>(ms.count()));
if (wait_code == ::boost::detail::winapi::wait_failed)
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
std::system_category());
else if (wait_code == ::boost::detail::winapi::wait_timeout)
return false; //
::boost::detail::winapi::DWORD_ _exit_code = 1;
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
{
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
std::system_category());
return false;
}
else
ec.clear();
exit_code = static_cast<int>(_exit_code);
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
return true;
;
}
template< class Clock, class Duration >
inline bool wait_until(
child_handle &p,
int & exit_code,
const std::chrono::time_point<Clock, Duration>& timeout_time)
{
std::chrono::milliseconds ms =
std::chrono::duration_cast<std::chrono::milliseconds>(
timeout_time - std::chrono::system_clock::now());
::boost::detail::winapi::DWORD_ wait_code;
wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
static_cast<::boost::detail::winapi::DWORD_>(ms.count()));
if (wait_code == ::boost::detail::winapi::wait_failed)
throw_last_error("WaitForSingleObject() failed");
else if (wait_code == ::boost::detail::winapi::wait_timeout)
return false;
::boost::detail::winapi::DWORD_ _exit_code;
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
throw_last_error("GetExitCodeProcess() failed");
exit_code = static_cast<int>(_exit_code);
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
return true;
}
template< class Clock, class Duration >
inline bool wait_until(
child_handle &p,
@@ -163,30 +57,66 @@ inline bool wait_until(
{
std::chrono::milliseconds ms =
std::chrono::duration_cast<std::chrono::milliseconds>(
timeout_time - std::chrono::system_clock::now());
timeout_time - Clock::now());
::boost::detail::winapi::DWORD_ _exit_code = 1;
::boost::winapi::DWORD_ wait_code;
wait_code = ::boost::winapi::WaitForSingleObject(p.process_handle(),
static_cast<::boost::winapi::DWORD_>(ms.count()));
if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(),
static_cast<::boost::detail::winapi::DWORD_>(ms.count()))
== ::boost::detail::winapi::wait_failed)
if (wait_code == ::boost::winapi::wait_failed)
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
::boost::winapi::GetLastError(),
std::system_category());
else if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
else if (wait_code == ::boost::winapi::wait_timeout)
return false;
::boost::winapi::DWORD_ _exit_code;
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code))
ec = std::error_code(
::boost::detail::winapi::GetLastError(),
::boost::winapi::GetLastError(),
std::system_category());
else
ec.clear();
exit_code = static_cast<int>(exit_code);
::boost::detail::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
exit_code = static_cast<int>(_exit_code);
::boost::winapi::CloseHandle(p.proc_info.hProcess);
p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
return true;
;
}
template< class Clock, class Duration >
inline bool wait_until(
child_handle &p,
int & exit_code,
const std::chrono::time_point<Clock, Duration>& timeout_time)
{
std::error_code ec;
bool b = wait_until(p, exit_code, timeout_time, ec);
boost::process::detail::throw_error(ec, "wait_until error");
return b;
}
template< class Rep, class Period >
inline bool wait_for(
child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time,
std::error_code &ec) noexcept
{
return wait_until(p, exit_code, std::chrono::steady_clock::now() + rel_time, ec);
}
template< class Rep, class Period >
inline bool wait_for(
child_handle &p,
int & exit_code,
const std::chrono::duration<Rep, Period>& rel_time)
{
std::error_code ec;
bool b = wait_for(p, exit_code, rel_time, ec);
boost::process::detail::throw_error(ec, "wait_for error");
return b;
}
}}}}

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