mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 04:42:24 +00:00
Compare commits
547 Commits
boost-1.64
...
boost-1.77
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2a96a3e13 | ||
|
|
1dbb3626a9 | ||
|
|
d79e1f2443 | ||
|
|
605dcd19d8 | ||
|
|
6b6a6fa61c | ||
|
|
295e2bdd9c | ||
|
|
dd1513846b | ||
|
|
7a94abfaf2 | ||
|
|
b55a09479c | ||
|
|
5afb20760c | ||
|
|
eec87e1dd9 | ||
|
|
f250a33fb4 | ||
|
|
570cf83a96 | ||
|
|
d52d244f83 | ||
|
|
04ab646f12 | ||
|
|
31c65b5442 | ||
|
|
ebbb6d8b36 | ||
|
|
b9c0140a26 | ||
|
|
27f587a4be | ||
|
|
7f6061c956 | ||
|
|
2f32c95341 | ||
|
|
a8029fc191 | ||
|
|
9f4bd9bce3 | ||
|
|
71f844c24f | ||
|
|
b0b6d67e6f | ||
|
|
3a2576a4d8 | ||
|
|
34eaa262dd | ||
|
|
ce3b3d8f99 | ||
|
|
429f2ba95c | ||
|
|
0c2e7387c8 | ||
|
|
2a2ea4b92d | ||
|
|
873ab2558d | ||
|
|
03571d4eaf | ||
|
|
46ab3ba9b8 | ||
|
|
3aba1f6eb1 | ||
|
|
44771769fa | ||
|
|
8704416941 | ||
|
|
f48392399f | ||
|
|
80f81117aa | ||
|
|
9cff55215d | ||
|
|
2e4b3c2406 | ||
|
|
b510b6a9d9 | ||
|
|
046b96186f | ||
|
|
1df2e67bc4 | ||
|
|
6cf69e2797 | ||
|
|
d3e4cbf3b3 | ||
|
|
e67e49c891 | ||
|
|
29a43b17e4 | ||
|
|
6d10c3a807 | ||
|
|
668579ed6f | ||
|
|
8af828cd43 | ||
|
|
590cc10b42 | ||
|
|
3bc11ce3ac | ||
|
|
603441ecc3 | ||
|
|
612a953369 | ||
|
|
1554773d39 | ||
|
|
dd003bf2b0 | ||
|
|
0341e08297 | ||
|
|
5853345715 | ||
|
|
41f8b1cf00 | ||
|
|
56ae00c7a4 | ||
|
|
f58882c956 | ||
|
|
3f14ebc755 | ||
|
|
1502de1001 | ||
|
|
8541cae396 | ||
|
|
38fa1fd040 | ||
|
|
ba15f760ab | ||
|
|
5e3e8f977e | ||
|
|
6182876d4f | ||
|
|
5bfd2ee08c | ||
|
|
c91b227c47 | ||
|
|
6a4d2ff721 | ||
|
|
6bf37ea8e8 | ||
|
|
ad38cdfada | ||
|
|
167ee79fa9 | ||
|
|
6b83d0b9dd | ||
|
|
16d16d40be | ||
|
|
f5f0866745 | ||
|
|
408cff1997 | ||
|
|
09faec4732 | ||
|
|
5ab43529b7 | ||
|
|
97f5b3c049 | ||
|
|
6dd3e0bdb4 | ||
|
|
eba5cb7be2 | ||
|
|
f4c51bcd5a | ||
|
|
410c0d592e | ||
|
|
40df7899b2 | ||
|
|
51083a8fa8 | ||
|
|
fe3cb0efc7 | ||
|
|
e0dd3b9658 | ||
|
|
d7d84f3952 | ||
|
|
6ccce9104a | ||
|
|
984c0c5b71 | ||
|
|
43523fcf8b | ||
|
|
cf7ad36438 | ||
|
|
ca994c1972 | ||
|
|
0a554c92b5 | ||
|
|
fa81cecffc | ||
|
|
977b76f6aa | ||
|
|
fc1acb82d9 | ||
|
|
db7af9f87d | ||
|
|
a350cc346b | ||
|
|
9fa86d3d65 | ||
|
|
e426f2bfac | ||
|
|
6b173117aa | ||
|
|
ecbc93408f | ||
|
|
6ba9a48d15 | ||
|
|
519c0a636a | ||
|
|
82195c61af | ||
|
|
c604e3a20e | ||
|
|
b27d0170ba | ||
|
|
98fd4eecf0 | ||
|
|
3799315ce7 | ||
|
|
b9431ba492 | ||
|
|
c0dca35615 | ||
|
|
790d79db9c | ||
|
|
5de0a795d1 | ||
|
|
cbaa913e3d | ||
|
|
5786162fb5 | ||
|
|
78c44dd560 | ||
|
|
23ff67d83d | ||
|
|
476c6ccd95 | ||
|
|
28126b3432 | ||
|
|
ed8388d091 | ||
|
|
43c402a5da | ||
|
|
9ff2f6f3ef | ||
|
|
b2a0fadaca | ||
|
|
3c4057204e | ||
|
|
717ac47510 | ||
|
|
4f6f4eb391 | ||
|
|
99e04036c7 | ||
|
|
519e339365 | ||
|
|
d2c930470f | ||
|
|
d5709ae747 | ||
|
|
d2ab81b1b9 | ||
|
|
885557fe01 | ||
|
|
b5b758f89a | ||
|
|
2a954eb809 | ||
|
|
0edff5449a | ||
|
|
417ea77f2f | ||
|
|
9e3fdc9669 | ||
|
|
66c2867371 | ||
|
|
caa7b2fcc8 | ||
|
|
6263e74bcd | ||
|
|
faae08ee64 | ||
|
|
2314e19f12 | ||
|
|
cfd0fc055c | ||
|
|
849b5d0f30 | ||
|
|
d13df2a194 | ||
|
|
86fc3b0b4d | ||
|
|
4733ca719f | ||
|
|
296f12eb64 | ||
|
|
96d3470e37 | ||
|
|
2265c98d81 | ||
|
|
060e5c2526 | ||
|
|
b4894807f1 | ||
|
|
2aa5e1461c | ||
|
|
61fa15fa48 | ||
|
|
92508e06a1 | ||
|
|
e85f0d0816 | ||
|
|
5e90c8de9b | ||
|
|
a486a25a07 | ||
|
|
f8c0dd4da5 | ||
|
|
ee6870bfbc | ||
|
|
0422b6bfb8 | ||
|
|
7fc41b2815 | ||
|
|
a49f1f6e2d | ||
|
|
af54484bc2 | ||
|
|
ebcb30e4bd | ||
|
|
5371c9813b | ||
|
|
9a833c610d | ||
|
|
c99ebfee7a | ||
|
|
34861366e0 | ||
|
|
e6722c452c | ||
|
|
b1e38842fb | ||
|
|
bcc9826e67 | ||
|
|
b6c6753b87 | ||
|
|
0d008a88fc | ||
|
|
f92ec53968 | ||
|
|
00a87d0a67 | ||
|
|
462334639c | ||
|
|
7129182044 | ||
|
|
03fbed44ad | ||
|
|
0277c4fcec | ||
|
|
4bc1ae6ff8 | ||
|
|
266c4503aa | ||
|
|
80479b6b70 | ||
|
|
823a346a08 | ||
|
|
8f3a7b9c63 | ||
|
|
2ebcc07892 | ||
|
|
a673cd9643 | ||
|
|
12971db132 | ||
|
|
94be279992 | ||
|
|
12cded5995 | ||
|
|
0c16a0e5b3 | ||
|
|
e4a6fde7b9 | ||
|
|
92d2bebaaf | ||
|
|
7e7a8cbc1d | ||
|
|
4f767f4bfe | ||
|
|
63f714ae2f | ||
|
|
1b3b9b707c | ||
|
|
f64bc8a6d4 | ||
|
|
102834130d | ||
|
|
fdc6a11cbc | ||
|
|
19b20f55ce | ||
|
|
60d072ce46 | ||
|
|
34f05b9276 | ||
|
|
1b476b0430 | ||
|
|
b294710e60 | ||
|
|
f8cd325d1b | ||
|
|
2a6c23e173 | ||
|
|
d7768b7221 | ||
|
|
b8821eac57 | ||
|
|
d20b64cf37 | ||
|
|
f0ddd6ca29 | ||
|
|
574d9e09d6 | ||
|
|
7085a50f36 | ||
|
|
0485459da2 | ||
|
|
318439af2e | ||
|
|
4d52ff362f | ||
|
|
8d48d9cbfa | ||
|
|
f25c31c847 | ||
|
|
192191ecfb | ||
|
|
3eacae5e38 | ||
|
|
14b294c10c | ||
|
|
881da4f9e2 | ||
|
|
3aeb6601cd | ||
|
|
8a7c37617e | ||
|
|
2758e8d438 | ||
|
|
b5a6b4b945 | ||
|
|
ac94f81b77 | ||
|
|
06747d7dd3 | ||
|
|
fb9b9215e0 | ||
|
|
eed0505f6e | ||
|
|
8f6aa8bcff | ||
|
|
6f9cabbd04 | ||
|
|
355d20faf3 | ||
|
|
15c4a64a81 | ||
|
|
49ec65a735 | ||
|
|
7cdea96caf | ||
|
|
8bf7da3b6b | ||
|
|
c1ad9d1227 | ||
|
|
1b6ccb6d39 | ||
|
|
e2e2b5ddb2 | ||
|
|
b4584dd0b0 | ||
|
|
55e5d178bd | ||
|
|
f778702257 | ||
|
|
b4ff07cfcb | ||
|
|
d43858078f | ||
|
|
f2cf918be5 | ||
|
|
54dd027a64 | ||
|
|
1ea894ab30 | ||
|
|
92c45f4b61 | ||
|
|
03cba8f5bd | ||
|
|
97f08ba0b3 | ||
|
|
c843815c6c | ||
|
|
b5785b3370 | ||
|
|
a6e5a5a619 | ||
|
|
2d627f633b | ||
|
|
ef486764ac | ||
|
|
fce3962376 | ||
|
|
5a40a0ee9c | ||
|
|
4bf795922d | ||
|
|
1646b240c7 | ||
|
|
d4f7bfaa6c | ||
|
|
bac06d2bc7 | ||
|
|
579499d9e8 | ||
|
|
b8c46bfc47 | ||
|
|
d234ce4f63 | ||
|
|
1be807e748 | ||
|
|
f4db2613eb | ||
|
|
bae6098e91 | ||
|
|
c40153fab1 | ||
|
|
e5eec4a5dc | ||
|
|
887bb8c482 | ||
|
|
0642bf5e70 | ||
|
|
513208a117 | ||
|
|
49247f0a83 | ||
|
|
ccb7dd482a | ||
|
|
08f40ff46b | ||
|
|
956f7b5fdf | ||
|
|
40d0f8c401 | ||
|
|
cbc7580fcd | ||
|
|
f96dfd6e8f | ||
|
|
ea24ebaf92 | ||
|
|
504e760760 | ||
|
|
c5e7cfb4f5 | ||
|
|
9904e3a5e8 | ||
|
|
191673b049 | ||
|
|
3a6d11f9b8 | ||
|
|
e022ad3742 | ||
|
|
16d9350992 | ||
|
|
5e1d7b6901 | ||
|
|
82d4cef182 | ||
|
|
5a112ea4bb | ||
|
|
b058e1cadf | ||
|
|
a8b28ef262 | ||
|
|
080f3fb074 | ||
|
|
997f10c7e9 | ||
|
|
4ced4d0933 | ||
|
|
eafe8e327a | ||
|
|
a4c89a3dec | ||
|
|
902390d57a | ||
|
|
5c55590922 | ||
|
|
0485932309 | ||
|
|
e1a3aded4e | ||
|
|
5b2d5c76c8 | ||
|
|
2c3c9e84a5 | ||
|
|
ad90ca6366 | ||
|
|
88952f0ab2 | ||
|
|
29cd54ea8c | ||
|
|
c2ee6da367 | ||
|
|
317801ca5e | ||
|
|
3923da14f7 | ||
|
|
5aa691cc3a | ||
|
|
04712d57f4 | ||
|
|
ed4c861e78 | ||
|
|
587eaa8054 | ||
|
|
78b5ea1f6b | ||
|
|
6412aa3ece | ||
|
|
68a3ba0c41 | ||
|
|
ecaba9efc1 | ||
|
|
fb682944d9 | ||
|
|
9c60e4987c | ||
|
|
59b361fb46 | ||
|
|
f3b2c0a67e | ||
|
|
69c04d5e29 | ||
|
|
78f4115a32 | ||
|
|
9b1b83f5e7 | ||
|
|
bd859e98d3 | ||
|
|
d7accdcf0c | ||
|
|
d159fea7b8 | ||
|
|
b5b91d578d | ||
|
|
498055bc8d | ||
|
|
502169a5ad | ||
|
|
42fbbbd8a6 | ||
|
|
dd0b26de4c | ||
|
|
10665bfaff | ||
|
|
2576ed166f | ||
|
|
9ad7413189 | ||
|
|
9cd405a66f | ||
|
|
fc6773d7d3 | ||
|
|
c3b707b709 | ||
|
|
57e9dfb705 | ||
|
|
4fd8887601 | ||
|
|
3cf4bf6480 | ||
|
|
256523d36e | ||
|
|
6ba8e88def | ||
|
|
f139f863a0 | ||
|
|
0938103427 | ||
|
|
e72127f9f8 | ||
|
|
eea73753b5 | ||
|
|
4f3b425073 | ||
|
|
dcb8a0266a | ||
|
|
99285a9de6 | ||
|
|
6cc31b93d8 | ||
|
|
d1ce19d848 | ||
|
|
f00895a9fc | ||
|
|
8d2bd87707 | ||
|
|
44162ecf22 | ||
|
|
d709c1cd07 | ||
|
|
90d2c0ceca | ||
|
|
9549ffe7e1 | ||
|
|
dd0edb4aee | ||
|
|
3029f4623a | ||
|
|
74606db379 | ||
|
|
81803868a3 | ||
|
|
eff42f91ef | ||
|
|
a25b6ca35b | ||
|
|
1c8323650d | ||
|
|
52f030a83c | ||
|
|
9cc651bdeb | ||
|
|
128cb0283d | ||
|
|
bb259f8f16 | ||
|
|
bb1bb431e5 | ||
|
|
41b7e30c18 | ||
|
|
f1c6909eb0 | ||
|
|
35fda5aa6a | ||
|
|
1f7f805858 | ||
|
|
d47b7f7ac4 | ||
|
|
2bc2531d2a | ||
|
|
c5798fdf7f | ||
|
|
5e43e7c07c | ||
|
|
6abce365c5 | ||
|
|
4fc4784506 | ||
|
|
900aab5d6d | ||
|
|
f61a61cf59 | ||
|
|
8e8d36772e | ||
|
|
ec04919825 | ||
|
|
6625999765 | ||
|
|
0d3688aca5 | ||
|
|
40be786c43 | ||
|
|
d4a0444223 | ||
|
|
f99cfe77f4 | ||
|
|
ed32531369 | ||
|
|
751af041cd | ||
|
|
a0ceebd59f | ||
|
|
b0b37f2ce6 | ||
|
|
cf1f904ae2 | ||
|
|
8aaf53d76d | ||
|
|
76c03ded89 | ||
|
|
e6fa19b4c5 | ||
|
|
92ee239891 | ||
|
|
c37e2a7524 | ||
|
|
a610fe74ff | ||
|
|
ea49952da2 | ||
|
|
a55946eb5d | ||
|
|
9f6c338631 | ||
|
|
60302c0017 | ||
|
|
08eaf8b7a1 | ||
|
|
cc70ec9362 | ||
|
|
b58ecc7c9d | ||
|
|
668cbcdaf4 | ||
|
|
6d7cbd0989 | ||
|
|
0764f788a6 | ||
|
|
2b95dd7011 | ||
|
|
ae380c30ad | ||
|
|
d2265890bd | ||
|
|
831d49c1b3 | ||
|
|
6935c53510 | ||
|
|
f30d90a179 | ||
|
|
55cfcecfb8 | ||
|
|
233f46a2cb | ||
|
|
342554b3d8 | ||
|
|
7aa812a0e1 | ||
|
|
c4ffd0c18d | ||
|
|
a411f06dc4 | ||
|
|
d085262076 | ||
|
|
0396740467 | ||
|
|
0fd7de9481 | ||
|
|
ba790dad0a | ||
|
|
f2e8776965 | ||
|
|
444d5eb702 | ||
|
|
3e12e989ab | ||
|
|
917030c3cd | ||
|
|
faf848bd8b | ||
|
|
d78c7901b3 | ||
|
|
09e98d8746 | ||
|
|
ab6e5b54ec | ||
|
|
b268e0e1fb | ||
|
|
996f4b357c | ||
|
|
8ce3e760dc | ||
|
|
6e60928b1f | ||
|
|
e27baa7628 | ||
|
|
337a6e3e83 | ||
|
|
bbfc334c93 | ||
|
|
1a9fa2cc2c | ||
|
|
1296e02372 | ||
|
|
585104605e | ||
|
|
d0c07b7c63 | ||
|
|
7c9ce7f8b9 | ||
|
|
c388f24d6e | ||
|
|
b1f50e953b | ||
|
|
852d8f3d9d | ||
|
|
2c026e43a8 | ||
|
|
51396227a0 | ||
|
|
75d3049199 | ||
|
|
3d9a8b2353 | ||
|
|
8097c2e07a | ||
|
|
d9231d466c | ||
|
|
153e05eac0 | ||
|
|
883b6ac937 | ||
|
|
764fff1f65 | ||
|
|
16ff42290a | ||
|
|
6adf1bf545 | ||
|
|
126659f2f9 | ||
|
|
90adf118ac | ||
|
|
63952fa2a6 | ||
|
|
2f00162817 | ||
|
|
28b402eed1 | ||
|
|
3f12d82e00 | ||
|
|
e01c1e0d37 | ||
|
|
c2602e86e9 | ||
|
|
e2a2a57820 | ||
|
|
547c04fc1f | ||
|
|
6ab2ed1723 | ||
|
|
79e26878b1 | ||
|
|
d15e7be16a | ||
|
|
3ab038fc0f | ||
|
|
66989a25f2 | ||
|
|
c748fff766 | ||
|
|
4772a08f89 | ||
|
|
054d7980ab | ||
|
|
4c6b0fff2a | ||
|
|
449eef0b98 | ||
|
|
3992965359 | ||
|
|
264b517b38 | ||
|
|
71c2fad8ce | ||
|
|
5b45fad163 | ||
|
|
e899189bf4 | ||
|
|
241883c9e4 | ||
|
|
aeee4e5dbb | ||
|
|
e08e095fd1 | ||
|
|
da34b4020d | ||
|
|
99001ccb50 | ||
|
|
f402f48138 | ||
|
|
1960360099 | ||
|
|
83019b5f70 | ||
|
|
76418ca191 | ||
|
|
f02e72304f | ||
|
|
4850ae493f | ||
|
|
77aecb43b8 | ||
|
|
66e576806f | ||
|
|
15445fd2bf | ||
|
|
6f49261c6e | ||
|
|
062b26e046 | ||
|
|
bb0fe86292 | ||
|
|
a3d3a98d5b | ||
|
|
950f16fe42 | ||
|
|
225b322e56 | ||
|
|
3e31d43d61 | ||
|
|
085adc07ec | ||
|
|
6aaefedf25 | ||
|
|
8df9c467e5 | ||
|
|
529d09f43b | ||
|
|
ce2a06f3a6 | ||
|
|
93a077e911 | ||
|
|
9ed2ebef27 | ||
|
|
7882bad799 | ||
|
|
92e1e04ae4 | ||
|
|
cf19c451fa | ||
|
|
74dd6570e3 | ||
|
|
826177a12e | ||
|
|
6712c54827 | ||
|
|
6a64b9e0bd | ||
|
|
34377ecad0 | ||
|
|
ae2b0a9024 | ||
|
|
712ebf772b | ||
|
|
7a99be71d3 | ||
|
|
210efd8dc5 | ||
|
|
ed15395f6d | ||
|
|
05443af621 | ||
|
|
a25665aeff | ||
|
|
ee4428c226 | ||
|
|
74814e46c1 | ||
|
|
f27898cdcd | ||
|
|
007dd97486 | ||
|
|
f0082aa797 | ||
|
|
ba14d9f870 | ||
|
|
684f9bcf11 | ||
|
|
51735a5640 | ||
|
|
d6b242c54a | ||
|
|
9daf3b4717 | ||
|
|
9cab8d455a | ||
|
|
f1bd81d56e | ||
|
|
28dc0c8830 | ||
|
|
7e217fe012 |
75
.circleci/config.yml
Normal file
75
.circleci/config.yml
Normal 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
96
.gitattributes
vendored
Normal 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
|
||||
185
.travis.yml
185
.travis.yml
@@ -10,28 +10,6 @@
|
||||
#
|
||||
# File revision #6
|
||||
|
||||
env:
|
||||
global:
|
||||
# Autodetect Boost branch by using the following code: - BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE=''
|
||||
|
||||
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# By default is eaual to - BOOST_REMOVE=`basename $TRAVIS_BUILD_DIR`
|
||||
# This will force to use local repo content, instead of the Boost's default
|
||||
# not needed because process is not yet in boost.
|
||||
- BOOST_REMOVE=process
|
||||
|
||||
matrix:
|
||||
- CXX_STANDARD=c++11 TOOLSET=gcc-5
|
||||
- CXX_STANDARD=c++1y TOOLSET=gcc-5
|
||||
|
||||
|
||||
###############################################################################################################
|
||||
# From this point and below code is same for all the Boost libs
|
||||
@@ -39,81 +17,120 @@ env:
|
||||
sudo: false
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
- gcc
|
||||
|
||||
os:
|
||||
- linux
|
||||
- linux
|
||||
- osx
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BADGE=linux
|
||||
- BADGE=osx
|
||||
global:
|
||||
# Autodetect Boost branch by using the following code: - BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE=''
|
||||
|
||||
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# By default is eaual to - BOOST_REMOVE=`basename $TRAVIS_BUILD_DIR`
|
||||
# This will force to use local repo content, instead of the Boost's default
|
||||
# not needed because process is not yet in boost.
|
||||
- BOOST_REMOVE=process
|
||||
- CXX_STANDARD=gnu++11
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: linux
|
||||
env: BADGE=osx
|
||||
- os: osx
|
||||
env: BADGE=linux
|
||||
|
||||
|
||||
|
||||
# Installing additional tools
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- valgrind
|
||||
- python-yaml
|
||||
- gcc-5
|
||||
- g++-5
|
||||
# - lcov
|
||||
- clang
|
||||
- valgrind
|
||||
- python-yaml
|
||||
- gcc-5
|
||||
- g++-5
|
||||
# - lcov
|
||||
- clang
|
||||
|
||||
before_install:
|
||||
# Set this to the name of the library
|
||||
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
|
||||
- echo "Testing $PROJECT_TO_TEST"
|
||||
# Cloning Boost libraries (fast nondeep cloning)
|
||||
- BOOST=$HOME/boost-local
|
||||
- git init $BOOST
|
||||
- cd $BOOST
|
||||
- if [ $(BRANCH_TO_TEST) = "master" ]; then
|
||||
BOOST_BRANCH=master;
|
||||
else BOOST_BRANCH=develop; fi
|
||||
- git remote add --no-tags -t $BOOST_BRANCH origin https://github.com/boostorg/boost.git
|
||||
- git fetch --depth=1
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule update --init --merge
|
||||
- git remote set-branches --add origin $BOOST_BRANCH
|
||||
- git pull --recurse-submodules
|
||||
- git submodule update --init
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
|
||||
- git reset --hard; git clean -fxd
|
||||
- git status
|
||||
- echo "Removing $BOOST/libs/$BOOST_REMOVE"
|
||||
- rm -rf $BOOST/libs/$BOOST_REMOVE
|
||||
- mv $TRAVIS_BUILD_DIR/../$PROJECT_TO_TEST/ $BOOST/libs/$PROJECT_TO_TEST
|
||||
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
|
||||
- ./bootstrap.sh
|
||||
- ./b2 headers
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test
|
||||
|
||||
# Set this to the name of the library
|
||||
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
|
||||
- echo "Testing $PROJECT_TO_TEST"
|
||||
- if [ $TRAVIS_OS_NAME = "osx" ]; then brew install gcc5; brew install valgrind; brew install llvm; TOOLSET=clang; BOOST_TEST_CATCH_SYSTEM_ERRORS=no; MULTITHREAD=-j8; else TOOLSET=gcc-5; REPORT_CI=--boost-process-report-ci USE_VALGRIND="testing.launcher=valgrind valgrind=on"; fi
|
||||
# Cloning Boost libraries (fast nondeep cloning)
|
||||
- BOOST=$HOME/boost-local
|
||||
- git init $BOOST
|
||||
- cd $BOOST
|
||||
- echo Branch to test $BRANCH_TO_TEST
|
||||
- if [ $BRANCH_TO_TEST = "master" ]; then
|
||||
BOOST_BRANCH=master;
|
||||
else BOOST_BRANCH=develop; fi
|
||||
- git remote add --no-tags -t $BOOST_BRANCH origin https://github.com/boostorg/boost.git
|
||||
- git fetch --depth=1
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule update --init --merge
|
||||
- git remote set-branches --add origin $BOOST_BRANCH
|
||||
- git pull --recurse-submodules || true
|
||||
- git submodule update --init
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
|
||||
- git reset --hard; git clean -fxd
|
||||
- git status
|
||||
- echo "Removing $BOOST/libs/$BOOST_REMOVE"
|
||||
- rm -rf $BOOST/libs/$BOOST_REMOVE
|
||||
- mv $TRAVIS_BUILD_DIR/../$PROJECT_TO_TEST/ $BOOST/libs/$PROJECT_TO_TEST
|
||||
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
|
||||
- ./bootstrap.sh
|
||||
- ./b2 headers
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test
|
||||
- echo BOOST_TEST_CATCH_SYSTEM_ERRORS $BOOST_TEST_CATCH_SYSTEM_ERRORS
|
||||
script:
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
- ../../../b2 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
|
||||
# Sending data to Coveralls
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- gem install coveralls-lcov
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
|
||||
after_script:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test
|
||||
- curl -s https://report.ci/report.py | python - --name="$BADGE test run"
|
||||
|
||||
15
README.md
15
README.md
@@ -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: | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://ci.appveyor.com/project/klemens-morgenstern/boost-process) | [](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=develop) |
|
||||
Master: | [] (https://travis-ci.org/klemens-morgenstern/boost-process) [](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) | [](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) |
|
||||
Branches | Linux | OSX | Windows | Code coverage | Matrix |
|
||||
----------------|-------|-----|---------| ------------- |--------|
|
||||
Develop: | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=linux) | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=osx) | [](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/develop) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=windows) | [](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=develop) | [](http://www.boost.org/development/tests/develop/developer/process.html)
|
||||
Master: | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=linux) | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=osx) | [](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=windows) | [](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) | [](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.
|
||||
|
||||
@@ -16,11 +16,11 @@ In that it is different than other facilities (like sockets) and provides anothe
|
||||
Pipes are typically used for interprocess communication. The main reason is, that pipes can be directly assigned to the process stdio, i.e. stderr, stdin and stdout.
|
||||
Additionally, half of the pipe can be inherited to the child process and closed in the father process. This will cause the pipe to be broken when the child process exits.
|
||||
|
||||
Though please not, that if the the same thread reads and write to a pipe, it will only talk to itself.
|
||||
Though please note, that if the same thread reads and writes to a pipe, it will only talk to itself.
|
||||
|
||||
[section:anonymous Anonymous Pipes]
|
||||
|
||||
The usual type of pipes, are the anonymous ones. Since the have no name,
|
||||
The most common pipes are anonymous. Since they have no name,
|
||||
a handle to them can only be obtained from duplicating either handle.
|
||||
|
||||
In this library the following functions are used for the creation of unnamed pipes:
|
||||
@@ -50,19 +50,19 @@ 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`.
|
||||
|
||||
[section:exit_code Exit code]
|
||||
A process will return an integer value indicating whether it was successful. On posix
|
||||
there are more codes associated with that, but not so on windows. Therefore there is not such encoding currently in the library.
|
||||
there are more codes associated with that, but not so on windows. Therefore there is no such encoding currently in the library.
|
||||
However an exit code of zero means the process was successful, while one different than zero indicates an error.
|
||||
[endsect]
|
||||
|
||||
[section:termination Termination]
|
||||
Processes can also be forced to exit. There are two ways to do this, signal the process to so and wait, and just terminate the process without conditions.
|
||||
Processes can also be forced to exit. There are two ways to do this, signal the process to do so and wait, and just terminate the process without conditions.
|
||||
|
||||
Usually the first approach is to signal an exit request, but windows - unlike posix - does not provide a consistent way to do this. Hence this is not part of the
|
||||
library and only the hard terminate is.
|
||||
@@ -79,4 +79,4 @@ The environment is a map of variables local to every process. The most significa
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[section:design Design Rationale]
|
||||
[section Scope]
|
||||
This library is meant to give an wrapper around the different OS-specific methods
|
||||
This library is meant to give a wrapper around the different OS-specific methods
|
||||
to launch processes. Its aim is to provide all functionality that is available on
|
||||
those systems and allow the user to do all related things, which require using the OS APIs.
|
||||
|
||||
[*This library does not try to provide a full library for everything process related]
|
||||
[*This library does not try to provide a full library for everything process related.]
|
||||
In many discussions the proposal was made to build boost.process into a DSEL [footnote Domain Specific Embedded Language] of some sort.
|
||||
This is not the goal, it rather provides the facilities to build such a DSEL-Library on top of it.
|
||||
This is not the goal, it rather provides the facilities to build such a DSEL-library on top of it.
|
||||
Therefore the library also does [*not] force any particular use (such as only asynchronous communication) on its user.
|
||||
It rather could be integrated with such a library.
|
||||
|
||||
@@ -33,7 +33,7 @@ Both styles can also be mixed in some cases.
|
||||
system("gcc", "-c", args+={"main.cpp"});
|
||||
```
|
||||
|
||||
In the following section the avaible styles will be described. Note that the
|
||||
In the following section the available styles will be described. Note that the
|
||||
overload style is implemented via type traits, so the types will be listed.
|
||||
|
||||
[caution There is no guarantee in which order the arguments will be applied!
|
||||
@@ -54,7 +54,7 @@ interpret each string as an argument.
|
||||
]
|
||||
|
||||
When using the overloading variant, a single string will result in a cmd interpretation,
|
||||
several strings will yield a exe-args interpretation. Both version can be set explicitly:
|
||||
several strings will yield a exe-args interpretation. Both versions can be set explicitly:
|
||||
|
||||
```
|
||||
system("grep -c false /etc/passwd"); //cmd style
|
||||
@@ -65,7 +65,7 @@ system(exe="grep", args={"-c", "false", "/etc/passwd"}); //exe-/args-
|
||||
```
|
||||
|
||||
[note If a '"' sign is used in the argument style, it will be passed as part of the argument.
|
||||
If the same effect it wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
|
||||
If the same effect is wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
|
||||
[note The `PATH` variable will automatically be searched in the command style,
|
||||
but the one of the launching process, not the one passed to the child process.]
|
||||
[endsect]
|
||||
|
||||
@@ -5,24 +5,24 @@
|
||||
[def __on_success__ [memberref boost::process::extend::handler::on_success on_success]]
|
||||
[def __posix_executor__ [classref boost::process::extend::posix_executor ex::posix_executor]]
|
||||
[def __windows_executor__ [classref boost::process::extend::windows_executor ex::windows_executor]]
|
||||
[def io_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]]
|
||||
[def __require_io_service__ [classref boost::process::extend::require_io_service ex::require_io_service]]
|
||||
[def __io_context__ [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_context.html boost::asio::io_context]]
|
||||
[def __require_io_context__ [classref boost::process::extend::require_io_context ex::require_io_context]]
|
||||
[def __async_handler__ [classref boost::process::extend::async_handler ex::async_handler]]
|
||||
[def __get_io_service__ [funcref boost::process::extend::get_io_service ex::get_io_service]]
|
||||
[def __get_io_context__ [funcref boost::process::extend::get_io_context ex::get_io_context]]
|
||||
|
||||
[section:extend Extensions]
|
||||
To extend the library, the header [headerref boost/process/extend.hpp extend] is provided.
|
||||
|
||||
It only provides the explicit style for custom properties, but no implicit style.
|
||||
|
||||
What this means is, that a custom initializer can be implemented, a reference to which can be passed to one of the launching functions.
|
||||
If a class inherits [classref boost::process::extend::handler] it will be regarded as a initializer and thus directly put into the sequence
|
||||
What this means is, that a custom initializer can be implemented, a reference which can be passed to one of the launching functions.
|
||||
If a class inherits [classref boost::process::extend::handler] it will be regarded as an initializer and thus directly put into the sequence
|
||||
the executor gets passed.
|
||||
|
||||
[section:structure Structure]
|
||||
|
||||
The executor calls different handlers of the initializers during the process launch.
|
||||
The basic structure is consists of three functions, as given below:
|
||||
The basic structure consists of three functions, as given below:
|
||||
|
||||
* [globalref boost::process::extend::on_setup on_setup]
|
||||
* [globalref boost::process::extend::on_error on_error]
|
||||
@@ -50,10 +50,10 @@ So let's start with a simple hello-world example, while we use a C++14 generic l
|
||||
using namespace boost::process;
|
||||
namespace ex = bp::extend;
|
||||
|
||||
__child__ c("foo", ex::__on_success__=[](auto & exec) {std::cout << "hello world" << std::endl;});
|
||||
__child__ c("foo", __on_success__=[](auto & exec) {std::cout << "hello world" << std::endl;});
|
||||
```
|
||||
|
||||
Considering that lambda can also capture values, data can easily be shared between handlers.
|
||||
Considering that lambdas can also capture values, data can easily be shared between handlers.
|
||||
|
||||
To see which members the executor has, refer to [classref boost::process::extend::windows_executor windows_executor]
|
||||
and [classref boost::process::extend::posix_executor posix_executor].
|
||||
@@ -86,7 +86,7 @@ __child__ c("foo", hello_world());
|
||||
|
||||
[note The implementation is done via overloading, not overriding.]
|
||||
|
||||
Every handler not implemented dafaults to [classref boost::process::extend::handler handler], where an empty handler is defined for each event.
|
||||
Every handler not implemented defaults to [classref boost::process::extend::handler handler], where an empty handler is defined for each event.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -95,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>
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
__io_service__ & ios = __get_io_service__(exec.seq); //gives us a reference and a compiler error if not present.
|
||||
__io_context__ & ios = __get_io_context__(exec.seq); //gives us a reference and a compiler error if not present.
|
||||
//do something with ios
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
[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,14 +133,16 @@ struct async_bar : __handler, __async_handler__
|
||||
|
||||
[caution `on_exit_handler` does not default and is always required when [classref boost::process::extend::async_handler async_handler] is inherited. ]
|
||||
|
||||
[caution `on_exit_handler` uses `boost::asio::signal_set` to listen for SIGCHLD on posix. The application must not also register a signal handler for SIGCHLD using functions such as `signal()` or `sigaction()` (but using `boost::asio::signal_set` is fine). ]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:error Error handling]
|
||||
|
||||
If an error occurs in the initializers it shall be told to the executor and not handles directly. This is because
|
||||
the behaviour can be changed through arguments passed to the launching function. Hence the the executor
|
||||
If an error occurs in the initializers it shall be told to the executor and not handled directly. This is because
|
||||
the behaviour can be changed through arguments passed to the launching function. Hence the executor
|
||||
has the function `set_error`, which takes an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code] and a string.
|
||||
Depending on the cofiguration of the executor, this may either throw, set an internal `error_code`, or do nothing.
|
||||
Depending on the configuration of the executor, this may either throw, set an internal `error_code`, or do nothing.
|
||||
|
||||
So let's take a simple example, where we set a randomly chosen `error_code`.
|
||||
|
||||
@@ -201,11 +202,11 @@ struct hello_exe : __handler__
|
||||
};
|
||||
```
|
||||
|
||||
So given our example, the definitions with the non-native exectur are still a template so that they will not be evaluated if not used. Hence this provides a
|
||||
way to implement systems-specific code without using the preprocessor.
|
||||
So given our example, the definitions with the non-native executor are still a template so that they will not be evaluated if not used. Hence this provides a
|
||||
way to implement system-specific code without using the preprocessor.
|
||||
|
||||
[note If you only write a partial implementation, e.g. only for __posix_executor__, the other variants will default to __handler__].
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
128
doc/faq.qbk
128
doc/faq.qbk
@@ -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 automatic pipe-closing in this library, because
|
||||
a pipe might be a file-handle (as for async pipes on windows).]
|
||||
|
||||
But, since pipes are buffered, you might get incomplete data if you do this:
|
||||
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]
|
||||
@@ -68,12 +68,12 @@ namespace bp = boost::process; //we will assume this for all further examples
|
||||
int result = bp::system("g++ main.cpp");
|
||||
```
|
||||
|
||||
If a single string (or the explicit form bp::cmd), it will be interpreted as a command line.
|
||||
If a single string is given (or the explicit form bp::cmd), it will be interpreted as a command line.
|
||||
That will cause the execution function to search the `PATH` variable to find the executable.
|
||||
The alternative is the `exe-args` style, where the first string will be interpreted as a filename (including the path),
|
||||
and the rest as arguments passed to said function.
|
||||
|
||||
[note For more details on the `cmd`/`exe-args` style look [link boost_process.design.arg_cmd_style here]]
|
||||
[note For more details on the `cmd`/`exe-args` style look [link boost_process.design.arg_cmd_style here].]
|
||||
|
||||
So as a first step, we'll use the `exe-args` style.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -141,7 +141,7 @@ things while the process is running and afterwards get the exit code. The call
|
||||
to child_wait is necessary, to obtain it and tell the operating system, that no
|
||||
one is waiting for the process anymore.
|
||||
|
||||
[note You can also wait for a time span or a until a time point with __wait_for__ and __wait_until__]
|
||||
[note You can also wait for a time span or until a time point with __wait_for__ and __wait_until__.]
|
||||
|
||||
[warning If you don't call wait on a child object, it will be terminated on destruction.
|
||||
This can be avoided by calling __detach__ beforehand]
|
||||
@@ -151,14 +151,14 @@ This can be avoided by calling __detach__ beforehand]
|
||||
|
||||
Until now, we have assumed that everything works out, but it is not impossible,
|
||||
that "g++" is not present. That will cause the launch of the process to fail.
|
||||
The default behaviour of all functions is to throw an
|
||||
The default behaviour of all functions is to throw a
|
||||
[@http://en.cppreference.com/w/cpp/error/system_error std::system_error] on failure.
|
||||
As with many other functions in this library, passing an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code]
|
||||
will change the behaviour, so that instead of throwing an exception, the error will be a assigned to the error code.
|
||||
will change the behaviour, so that instead of throwing an exception, the error will be assigned to the error code.
|
||||
|
||||
```
|
||||
std::error_code ec;
|
||||
bp::system c("g++ main.cpp", ec);
|
||||
bp::system("g++ main.cpp", ec);
|
||||
```
|
||||
[endsect]
|
||||
[section:io Synchronous I/O]
|
||||
@@ -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
|
||||
@@ -247,7 +246,7 @@ std::vector<std::string> read_demangled_outline(const std::string & file)
|
||||
|
||||
std::vector<std::string> outline;
|
||||
|
||||
//we just use the same pipe, so the
|
||||
//we just use the same pipe, so the output of nm is directly passed as input to c++filt
|
||||
bp::child nm(bp::search_path("nm"), file, bp::std_out > p);
|
||||
bp::child filt(bp::search_path("c++filt"), bp::std_in < p, bp::std_out > is);
|
||||
|
||||
@@ -271,14 +270,14 @@ If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boos
|
||||
you can use [classref boost::process::async_pipe async_pipe] which is implemented
|
||||
as an I/O-Object and can be used like [classref boost::process::pipe pipe] as shown above.
|
||||
|
||||
Now we get back to our compiling example. `nm` we might analyze it line by line,
|
||||
Now we get back to our compiling example. For `nm` we might analyze the output line by line,
|
||||
but the compiler output will just be put into one large buffer.
|
||||
|
||||
With [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] this is what it looks like.
|
||||
|
||||
```
|
||||
io_service ios;
|
||||
std::vector<char> buf;
|
||||
std::vector<char> buf(4096);
|
||||
|
||||
bp::async_pipe ap(ios);
|
||||
|
||||
@@ -288,26 +287,24 @@ asio_async_read(ap, asio_buffer(buf),
|
||||
[](const boost::system::error_code &ec, std::size_t size){});
|
||||
|
||||
ios.run();
|
||||
c.wait();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
To make it easier, boost.process provides simpler interface for that, so that the buffer can be passed directly,
|
||||
To make it easier, boost.process provides a simpler interface for that, so that the buffer can be passed directly,
|
||||
provided we also pass a reference to an io_service.
|
||||
|
||||
```
|
||||
io_service ios;
|
||||
std::vector<char> buf;
|
||||
std::vector<char> buf(4096);
|
||||
|
||||
bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > asio_buffer(buf), ios);
|
||||
|
||||
ios.run();
|
||||
c.wait();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
[note Passing an instance of io_service to the launching function automatically cause it to wait asynchronously for the exit, so no call of
|
||||
[memberref boost::process::child::wait wait] is needed]
|
||||
[memberref boost::process::child::wait wait] is needed.]
|
||||
|
||||
To make it even easier, you can use [@http://en.cppreference.com/w/cpp/thread/future std::future] for asynchronous operations
|
||||
(you will still need to pass a reference to a io_service) to the launching function, unless you use bp::system or bp::async_system.
|
||||
@@ -334,7 +331,7 @@ auto err = data.get();
|
||||
[endsect]
|
||||
[section:group Groups]
|
||||
|
||||
When launching several processes, processes can be grouped together.
|
||||
When launching several processes, they can be grouped together.
|
||||
This will also apply for a child process, that launches other processes,
|
||||
if they do not modify the group membership. E.g. if you call `make` which
|
||||
launches other processes and call terminate on it,
|
||||
@@ -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 a program like `make`, which does launch its own child processes,
|
||||
a call of child_terminate might not suffice. I.e. if we have a makefile launching `gcc`
|
||||
and use the following code, the `gcc` process will still run afterwards:
|
||||
|
||||
@@ -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"};
|
||||
@@ -415,14 +412,14 @@ bp::system("stuff", env_);
|
||||
```
|
||||
|
||||
A more convenient way to modify the environment for the child is the
|
||||
[globalref boost::process::env env] property, which the example as following:
|
||||
[globalref boost::process::env env] property, which can be used in the example as following:
|
||||
|
||||
```
|
||||
bp::system("stuff", bp::env["VALUE_1"]="foo", bp::env["VALUE_2"]+={"bar1", "bar2"});
|
||||
|
||||
```
|
||||
|
||||
Please see to the [headerref boost/process/environment.hpp reference] for more information.
|
||||
Please see the [headerref boost/process/environment.hpp reference] for more information.
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::io_context ios;
|
||||
boost::asio::streambuf buffer;
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
//[intro
|
||||
#include <boost/process.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
using namespace boost::process;
|
||||
|
||||
int main()
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
14
filter_section_warning.py
Normal 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()
|
||||
@@ -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>
|
||||
|
||||
@@ -138,7 +138,7 @@ struct args_
|
||||
|
||||
arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char>(range.begin(), range.end());
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator+=(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
@@ -146,11 +146,11 @@ struct args_
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
return arg_setter_<char, false>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator()(std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char>(range.begin(), range.end());
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator+=(std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
@@ -158,12 +158,12 @@ struct args_
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
return arg_setter_<char, false>(range.begin(), range.end());
|
||||
}
|
||||
|
||||
arg_setter_<wchar_t, true> operator()(std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator+=(std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
@@ -171,11 +171,11 @@ struct args_
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t, false>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator()(std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator+=(std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
@@ -183,7 +183,7 @@ struct args_
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t, false>(range.begin(), range.end());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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,18 +107,20 @@ 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){});
|
||||
child c("ls", ios, on_exit=[](int exit, const std::error_code& ec_in){});
|
||||
|
||||
std::future<int> exit_code;
|
||||
chlid c2("ls", on_exit=exit_code);
|
||||
chlid c2("ls", ios, on_exit=exit_code);
|
||||
|
||||
\endcode
|
||||
|
||||
\note The handler is not invoked when the launch fails.
|
||||
\warning When used \ref ignore_error it might 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
|
||||
|
||||
@@ -47,32 +47,34 @@ public:
|
||||
*/
|
||||
typedef platform_specific handle_type;
|
||||
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
/** Construct a new async_pipe, does automatically open the pipe.
|
||||
* Initializes source and sink with the same io_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 +91,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 +191,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 &;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)};
|
||||
|
||||
|
||||
@@ -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() */
|
||||
|
||||
@@ -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_() = default;
|
||||
|
||||
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
|
||||
|
||||
@@ -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...);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -65,20 +65,22 @@ 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;
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
explicit child(Args&&...args);
|
||||
child() {}
|
||||
child() { } // Must be kept non defaulted for MSVC 14.1 & 14.2 #113
|
||||
child& operator=(const child&) = delete;
|
||||
child& operator=(child && lhs)
|
||||
{
|
||||
_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);
|
||||
}
|
||||
|
||||
@@ -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';}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <boost/asio/ts/netfwd.hpp>
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
@@ -20,34 +21,19 @@ template<typename Allocator>
|
||||
class basic_streambuf;
|
||||
|
||||
typedef basic_streambuf<std::allocator<char>> streambuf;
|
||||
class io_service;
|
||||
|
||||
|
||||
class signal_set_service;
|
||||
template <typename SignalSetService>
|
||||
|
||||
template <typename Executor>
|
||||
class basic_signal_set;
|
||||
typedef basic_signal_set<signal_set_service> signal_set;
|
||||
typedef basic_signal_set<any_io_executor> signal_set;
|
||||
|
||||
template <typename Handler>
|
||||
class basic_yield_context;
|
||||
|
||||
namespace posix {
|
||||
|
||||
class stream_descriptor_service;
|
||||
|
||||
template <typename StreamDesscriptorService>
|
||||
template <typename Executor>
|
||||
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;
|
||||
typedef basic_stream_descriptor<any_io_executor> stream_descriptor;
|
||||
|
||||
} //posix
|
||||
} //asio
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,170 +1,190 @@
|
||||
// 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;
|
||||
if (buffer_->size() > 0)
|
||||
{
|
||||
arg.resize(buffer_->size());
|
||||
is.read(&*arg.begin(), buffer_->size());
|
||||
}
|
||||
promise_->set_value(std::move(arg));
|
||||
}
|
||||
});
|
||||
|
||||
std::move(*pipe).sink().close();
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -21,11 +23,12 @@ class async_pipe
|
||||
public:
|
||||
typedef int native_handle_type;
|
||||
typedef ::boost::asio::posix::stream_descriptor handle_type;
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
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 +37,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 +50,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 +71,8 @@ public:
|
||||
|
||||
~async_pipe()
|
||||
{
|
||||
if (_sink .native() != -1)
|
||||
::close(_sink.native());
|
||||
if (_source.native() != -1)
|
||||
::close(_source.native());
|
||||
boost::system::error_code ec;
|
||||
close(ec);
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
@@ -108,9 +109,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 +125,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 +148,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 +159,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 +169,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 +218,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 +239,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 +250,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 +277,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 +289,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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
@@ -82,22 +82,30 @@ public:
|
||||
|
||||
int_type write(const char_type * data, int_type count)
|
||||
{
|
||||
auto write_len = ::write(_sink, data, count * sizeof(char_type));
|
||||
if (write_len == -1)
|
||||
::boost::process::detail::throw_last_error();
|
||||
|
||||
int_type write_len;
|
||||
while ((write_len = ::write(_sink, data, count * sizeof(char_type))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::detail::throw_last_error();
|
||||
}
|
||||
return write_len;
|
||||
}
|
||||
int_type read(char_type * data, int_type count)
|
||||
{
|
||||
auto read_len = ::read(_source, data, count * sizeof(char_type));
|
||||
if (read_len == -1)
|
||||
::boost::process::detail::throw_last_error();
|
||||
|
||||
int_type read_len;
|
||||
while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::detail::throw_last_error();
|
||||
}
|
||||
return read_len;
|
||||
}
|
||||
|
||||
bool is_open()
|
||||
bool is_open() const
|
||||
{
|
||||
return (_source != -1) ||
|
||||
(_sink != -1);
|
||||
@@ -105,8 +113,10 @@ public:
|
||||
|
||||
void close()
|
||||
{
|
||||
::close(_source);
|
||||
::close(_sink);
|
||||
if (_source != -1)
|
||||
::close(_source);
|
||||
if (_sink != -1)
|
||||
::close(_sink);
|
||||
_source = -1;
|
||||
_sink = -1;
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;}
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -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<>
|
||||
|
||||
@@ -1,322 +1,326 @@
|
||||
// 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 _env_impl;}
|
||||
};
|
||||
|
||||
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) -> bool
|
||||
{
|
||||
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) -> bool
|
||||
{
|
||||
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) -> bool
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (val.empty())
|
||||
val.push_back(0);
|
||||
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_ */
|
||||
|
||||
@@ -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) && (*e != nullptr) && !boost::starts_with(*e, "PATH="))
|
||||
e++;
|
||||
|
||||
if ((e != nullptr) && (*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";
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
146
include/boost/process/detail/posix/handles.hpp
Normal file
146
include/boost/process/detail/posix/handles.hpp
Normal 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
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 "";
|
||||
|
||||
135
include/boost/process/detail/posix/sigchld_service.hpp
Normal file
135
include/boost/process/detail/posix/sigchld_service.hpp
Normal 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::strand<boost::asio::io_context::executor_type> _strand{get_io_context().get_executor()};
|
||||
boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
|
||||
|
||||
std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
|
||||
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
|
||||
@@ -21,7 +21,7 @@ struct start_dir_init : handler_base_ext
|
||||
{
|
||||
typedef Char value_type;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
start_dir_init(const string_type &s) : s_(s) {}
|
||||
start_dir_init(string_type s) : s_(std::move(s)) {}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_exec_setup(PosixExecutor&) const
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -12,75 +12,92 @@
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/group_handle.hpp>
|
||||
#include <chrono>
|
||||
#include <system_error>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
inline void wait(const group_handle &p)
|
||||
{
|
||||
pid_t ret;
|
||||
int status;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, 0);
|
||||
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
|
||||
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;
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
::timespec sleep_interval;
|
||||
sleep_interval.tv_sec = 0;
|
||||
sleep_interval.tv_nsec = 100000000;
|
||||
|
||||
|
||||
while (!(timed_out = (Clock::now() > time_out)))
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WSTOPPED | WNOHANG);
|
||||
if (ret == -1)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
if ((errno == ECHILD) || (errno == ESRCH))
|
||||
{
|
||||
ec.clear();
|
||||
return true;
|
||||
}
|
||||
ec = boost::process::detail::get_last_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status)));
|
||||
|
||||
|
||||
if (ret == -1)
|
||||
boost::process::detail::throw_last_error("waitpid(2) failed");
|
||||
|
||||
|
||||
return !time_out_occured;
|
||||
//we can wait, because unlike in the wait_for_exit, we have no race condition regarding eh exit code.
|
||||
::nanosleep(&sleep_interval, nullptr);
|
||||
}
|
||||
return !timed_out;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
inline bool wait_until(
|
||||
const group_handle &p,
|
||||
const std::chrono::time_point<Clock, Duration>& time_out) noexcept
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(p, time_out, ec);
|
||||
boost::process::detail::throw_error(ec, "waitpid(2) failed in wait_until");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Rep, class Period >
|
||||
inline bool wait_for(
|
||||
@@ -88,102 +105,18 @@ inline bool wait_for(
|
||||
const std::chrono::duration<Rep, Period>& rel_time,
|
||||
std::error_code & ec) noexcept
|
||||
{
|
||||
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto time_out = start + rel_time;
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
ret = ::waitpid(-p.grp, &status, WUNTRACED | WNOHANG);
|
||||
if (std::chrono::system_clock::now() >= time_out)
|
||||
{
|
||||
time_out_occured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (((ret == -1) && errno == EINTR) ||
|
||||
((ret != -1) && !WIFEXITED(status)));
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
81
include/boost/process/detail/used_handles.hpp
Normal file
81
include/boost/process/detail/used_handles.hpp
Normal 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_ */
|
||||
@@ -7,6 +7,7 @@
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <boost/asio/ts/netfwd.hpp>
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
@@ -19,27 +20,19 @@ template<typename Allocator>
|
||||
class basic_streambuf;
|
||||
|
||||
typedef basic_streambuf<std::allocator<char>> streambuf;
|
||||
class io_service;
|
||||
|
||||
template <typename Handler>
|
||||
class basic_yield_context;
|
||||
|
||||
namespace windows {
|
||||
|
||||
class stream_handle_service;
|
||||
|
||||
template <typename StreamHandleService>
|
||||
template <typename Executor>
|
||||
class basic_stream_handle;
|
||||
typedef basic_stream_handle<any_io_executor> stream_handle;
|
||||
|
||||
typedef basic_stream_handle<stream_handle_service> stream_handle;
|
||||
|
||||
|
||||
class object_handle_service;
|
||||
|
||||
template <typename ObjectHandleService>
|
||||
template <typename Executor>
|
||||
class basic_object_handle;
|
||||
|
||||
typedef basic_object_handle<object_handle_service> object_handle;
|
||||
typedef basic_object_handle<any_io_executor> object_handle;
|
||||
|
||||
} //windows
|
||||
} //asio
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,42 @@ 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;
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios, make_pipe_name(), true) {}
|
||||
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink)
|
||||
: async_pipe(ios_source, ios_sink, make_pipe_name(), true) {}
|
||||
|
||||
async_pipe(boost::asio::io_context & ios, const std::string & name)
|
||||
: async_pipe(ios, ios, name, false) {}
|
||||
|
||||
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name)
|
||||
: async_pipe(ios_source, ios_sink, name, false) {}
|
||||
|
||||
inline async_pipe(boost::asio::io_service & ios,
|
||||
const std::string & name = make_pipe_name())
|
||||
: async_pipe(ios, ios, name) {}
|
||||
|
||||
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 +88,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 +108,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 +121,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 +137,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 +153,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 +176,7 @@ public:
|
||||
const MutableBufferSequence & buffers,
|
||||
ReadHandler &&handler)
|
||||
{
|
||||
_source.async_read_some(buffers, std::forward<ReadHandler>(handler));
|
||||
return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
|
||||
}
|
||||
|
||||
template<typename ConstBufferSequence,
|
||||
@@ -167,7 +187,7 @@ public:
|
||||
const ConstBufferSequence & buffers,
|
||||
WriteHandler && handler)
|
||||
{
|
||||
_sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
|
||||
return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
|
||||
}
|
||||
|
||||
const handle_type & sink () const & {return _sink;}
|
||||
@@ -176,195 +196,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};
|
||||
|
||||
@@ -1,164 +1,190 @@
|
||||
// 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 or double quotes
|
||||
if(!exe.empty())
|
||||
{
|
||||
auto it = st.find_first_of(" \"");
|
||||
|
||||
auto it = std::find(st.begin(), st.end(), ' ');
|
||||
if(it != st.npos)//contains spaces.
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(st, "\"", "\"\"");
|
||||
|
||||
if (it != st.end())//contains spaces.
|
||||
{
|
||||
st.insert(st.begin(), '"');
|
||||
st += '"';
|
||||
}
|
||||
}
|
||||
// surround with quotes
|
||||
st.insert(st.begin(), '"');
|
||||
st += '"';
|
||||
}
|
||||
}
|
||||
|
||||
for (auto & arg : data)
|
||||
{
|
||||
boost::replace_all(arg, "\"", "\\\"");
|
||||
for (auto & arg : data)
|
||||
{
|
||||
if(!arg.empty())
|
||||
{
|
||||
auto it = arg.find_first_of(" \"");//contains space or double quotes?
|
||||
if(it != arg.npos)//yes
|
||||
{
|
||||
// double existing quotes
|
||||
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.
|
||||
}
|
||||
// surround with quotes
|
||||
arg.insert(arg.begin(), '"');
|
||||
arg += '"';
|
||||
}
|
||||
}
|
||||
|
||||
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 or double quotes
|
||||
if(!exe.empty())
|
||||
{
|
||||
auto it = st.find_first_of(L" \"");
|
||||
|
||||
if (!st.empty())//first one does not need a preceeding space
|
||||
st += L' ';
|
||||
if(it != st.npos)//contains spaces or double quotes.
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(st, L"\"", L"\"\"");
|
||||
|
||||
st += arg;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
// surround with quotes
|
||||
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)
|
||||
{
|
||||
if(!arg.empty())
|
||||
{
|
||||
auto it = arg.find_first_of(L" \"");//contains space or double quotes?
|
||||
if(it != arg.npos)//yes
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(arg, L"\"", L"\"\"");
|
||||
|
||||
static const char* c_arg(char) { return "/c";}
|
||||
static const wchar_t* c_arg(wchar_t) { return L"/c";}
|
||||
// surround with quotes
|
||||
arg.insert(arg.begin(), L'"');
|
||||
arg += '"';
|
||||
}
|
||||
}
|
||||
|
||||
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_ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,28 +11,28 @@
|
||||
#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 {
|
||||
|
||||
typedef int pid_t;
|
||||
typedef ::boost::winapi::DWORD_ 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,50 +44,50 @@ 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;
|
||||
}
|
||||
|
||||
pid_t id() const
|
||||
{
|
||||
return static_cast<int>(proc_info.dwProcessId);
|
||||
return static_cast<pid_t>(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;
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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_;
|
||||
}
|
||||
|
||||
}}}}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,104 +1,121 @@
|
||||
// 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>
|
||||
#include <boost/core/exchange.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 &&other)
|
||||
: _handle( boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_) )
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
file_descriptor(const file_descriptor & ) = delete;
|
||||
file_descriptor(file_descriptor && ) = default;
|
||||
file_descriptor& operator=(const file_descriptor & ) = delete;
|
||||
file_descriptor& operator=(file_descriptor &&other)
|
||||
{
|
||||
if (_handle != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::winapi::CloseHandle(_handle);
|
||||
_handle = boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
|
||||
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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.");
|
||||
|
||||
|
||||
262
include/boost/process/detail/windows/handle_workaround.hpp
Normal file
262
include/boost/process/detail/windows/handle_workaround.hpp
Normal 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_ */
|
||||
@@ -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_ */
|
||||
|
||||
176
include/boost/process/detail/windows/handles.hpp
Normal file
176
include/boost/process/detail/windows/handles.hpp
Normal 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 (;
|
||||
nt_status == STATUS_INFO_LENGTH_MISMATCH_;
|
||||
nt_status = workaround::nt_system_query_information(
|
||||
workaround::SystemHandleInformation_,
|
||||
info_pointer, static_cast<::boost::winapi::ULONG_>(buffer.size()),
|
||||
nullptr))
|
||||
{
|
||||
buffer.resize(buffer.size() * 2);
|
||||
info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
|
||||
}
|
||||
|
||||
|
||||
if (nt_status < 0 || nt_status > 0x7FFFFFFF)
|
||||
{
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
return {};
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
std::vector<native_handle_type> res;
|
||||
for (auto itr = info_pointer->Handle; itr != (info_pointer->Handle + info_pointer->Count); itr++)
|
||||
{
|
||||
if (itr->OwnerPid == pid)
|
||||
res.push_back(reinterpret_cast<native_handle_type>(static_cast<std::uintptr_t>(itr->HandleValue)));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::vector<native_handle_type> get_handles()
|
||||
{
|
||||
std::error_code ec;
|
||||
|
||||
auto res = get_handles(ec);
|
||||
if (ec)
|
||||
boost::process::detail::throw_error(ec, "NtQuerySystemInformation failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
|
||||
{
|
||||
::boost::winapi::ULONG_ actual_size;
|
||||
auto nt_status = workaround::nt_query_object(
|
||||
handle,
|
||||
workaround::ObjectTypeInformation,
|
||||
NULL,
|
||||
0, &actual_size);
|
||||
|
||||
std::vector<char> vec;
|
||||
vec.resize(actual_size);
|
||||
|
||||
workaround::OBJECT_TYPE_INFORMATION_ * type_info_p = reinterpret_cast<workaround::OBJECT_TYPE_INFORMATION_*>(vec.data());
|
||||
nt_status = workaround::nt_query_object(
|
||||
handle,
|
||||
workaround::ObjectTypeInformation,
|
||||
type_info_p,
|
||||
actual_size, &actual_size);
|
||||
|
||||
if (nt_status < 0 || nt_status > 0x7FFFFFFF)
|
||||
{
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
auto &nm = type_info_p->TypeName.Buffer;
|
||||
return type_info_p->TypeName.Length >= 5 &&
|
||||
nm[0] == L'F' &&
|
||||
nm[1] == L'i' &&
|
||||
nm[2] == L'l' &&
|
||||
nm[3] == L'e' &&
|
||||
nm[4] == L'\0';
|
||||
}
|
||||
|
||||
|
||||
inline bool is_stream_handle(native_handle_type handle)
|
||||
{
|
||||
std::error_code ec;
|
||||
auto res = is_stream_handle(handle, ec);
|
||||
if (ec)
|
||||
boost::process::detail::throw_error(ec, "NtQueryObject failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
struct limit_handles_ : handler_base_ext
|
||||
{
|
||||
mutable std::vector<::boost::winapi::HANDLE_> handles_with_inherit_flag;
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec) const
|
||||
{
|
||||
auto all_handles = get_handles();
|
||||
foreach_used_handle(exec,
|
||||
[&](::boost::winapi::HANDLE_ handle)
|
||||
{
|
||||
auto itr = std::find(all_handles.begin(), all_handles .end(), handle);
|
||||
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
|
||||
@@ -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_ */
|
||||
@@ -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)
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_ext = p;
|
||||
pp_ext += ext;
|
||||
boost::system::error_code ec;
|
||||
bool file = boost::filesystem::is_regular_file(p, ec);
|
||||
bool file = boost::filesystem::is_regular_file(pp_ext, 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_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))
|
||||
{
|
||||
return p;
|
||||
return pp_ext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user