diff options
author | Johannes Schindelin <johannes.schindelin@gmx.de> | 2017-08-23 16:47:04 +0200 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2017-10-01 08:36:07 +0100 |
commit | ab450021a99ba66126cc6d668fb06ec3829a572b (patch) | |
tree | 73ce5e5c4d3054e7e59772ff4aa3bcd9d5c8db5d | |
parent | 2ac01855ce6667e9e3d23c76616eb38a73200883 (diff) | |
download | busybox-w32-ab450021a99ba66126cc6d668fb06ec3829a572b.tar.gz busybox-w32-ab450021a99ba66126cc6d668fb06ec3829a572b.tar.bz2 busybox-w32-ab450021a99ba66126cc6d668fb06ec3829a572b.zip |
mingw: special-case xargs -P on Windows
The patches to let xargs support parallel operations on Linux/Unix was
contributed and accepted in upstream BusyBox.
To benefit from this on Windows, we have to work quite a bit harder, was
it is pretty hard to emulate the waitpid() semantics on Windows when pid
is -1, i.e. when waiting for any child to exit.
The problem is not so much accumulating the process handles of children
we spawned (we could do that in our own spawn() implementation), but the
fact that waitpid() returns exactly one pid even when multiple children
have exited, retaining the rest of them for subsequent waitpid() calls.
And on Linux/Unix, those pids are reserved even if the processes have
exited, at least for a while, but not on Windows.
And then there is the problem that BusyBox may have spawned *other*
processes, too, not just the ones we care about in xargs -P.
A much more elegant way is to add Windows-specific code to xargs.c that
specifically handles the child processes spawned by xargs. So let's do
this.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Ron Yorston <rmy@pobox.com>
-rw-r--r-- | configs/mingw32_defconfig | 2 | ||||
-rw-r--r-- | configs/mingw64_defconfig | 2 | ||||
-rw-r--r-- | findutils/xargs.c | 75 |
3 files changed, 77 insertions, 2 deletions
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig index 92935f9fb..e401f3f83 100644 --- a/configs/mingw32_defconfig +++ b/configs/mingw32_defconfig | |||
@@ -465,7 +465,7 @@ CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y | |||
465 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y | 465 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y |
466 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y | 466 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y |
467 | CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y | 467 | CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y |
468 | # CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL is not set | 468 | CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y |
469 | CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y | 469 | CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y |
470 | 470 | ||
471 | # | 471 | # |
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig index cc845c3f2..daa74a4ce 100644 --- a/configs/mingw64_defconfig +++ b/configs/mingw64_defconfig | |||
@@ -465,7 +465,7 @@ CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y | |||
465 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y | 465 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y |
466 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y | 466 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y |
467 | CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y | 467 | CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y |
468 | # CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL is not set | 468 | CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y |
469 | CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y | 469 | CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y |
470 | 470 | ||
471 | # | 471 | # |
diff --git a/findutils/xargs.c b/findutils/xargs.c index caa89f13e..9e475d7e6 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -115,6 +115,9 @@ struct globals { | |||
115 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | 115 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL |
116 | int running_procs; | 116 | int running_procs; |
117 | int max_procs; | 117 | int max_procs; |
118 | #if ENABLE_PLATFORM_MINGW32 | ||
119 | HANDLE *procs; | ||
120 | #endif | ||
118 | #endif | 121 | #endif |
119 | smalluint xargs_exitcode; | 122 | smalluint xargs_exitcode; |
120 | } FIX_ALIASING; | 123 | } FIX_ALIASING; |
@@ -125,12 +128,61 @@ struct globals { | |||
125 | G.idx = 0; \ | 128 | G.idx = 0; \ |
126 | IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.running_procs = 0;) \ | 129 | IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.running_procs = 0;) \ |
127 | IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.max_procs = 1;) \ | 130 | IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.max_procs = 1;) \ |
131 | IF_FEATURE_XARGS_SUPPORT_PARALLEL(IF_PLATFORM_MINGW32(G.procs = NULL;)) \ | ||
128 | G.xargs_exitcode = 0; \ | 132 | G.xargs_exitcode = 0; \ |
129 | IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \ | 133 | IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \ |
130 | IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \ | 134 | IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \ |
131 | } while (0) | 135 | } while (0) |
132 | 136 | ||
133 | 137 | ||
138 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL && ENABLE_PLATFORM_MINGW32 | ||
139 | static int wait_for_slot(int *idx) | ||
140 | { | ||
141 | int i; | ||
142 | |||
143 | /* if less than max_procs running, set status to 0, return next free slot */ | ||
144 | if (G.running_procs < G.max_procs) { | ||
145 | *idx = G.running_procs++; | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | check_exit_codes: | ||
150 | for (i = G.running_procs - 1; i >= 0; i--) { | ||
151 | DWORD status = 0; | ||
152 | if (!GetExitCodeProcess(G.procs[i], &status) || | ||
153 | status != STILL_ACTIVE) { | ||
154 | CloseHandle(G.procs[i]); | ||
155 | if (i + 1 < G.running_procs) | ||
156 | G.procs[i] = G.procs[G.running_procs - 1]; | ||
157 | *idx = G.running_procs - 1; | ||
158 | if (!G.max_procs) | ||
159 | G.running_procs--; | ||
160 | return status; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | if (G.running_procs < MAXIMUM_WAIT_OBJECTS) | ||
165 | WaitForMultipleObjects((DWORD)G.running_procs, G.procs, FALSE, | ||
166 | INFINITE); | ||
167 | else { | ||
168 | /* Fall back to polling */ | ||
169 | for (;;) { | ||
170 | DWORD nr = i + MAXIMUM_WAIT_OBJECTS > G.running_procs ? | ||
171 | MAXIMUM_WAIT_OBJECTS : (DWORD)(G.running_procs - i); | ||
172 | DWORD ret = WaitForMultipleObjects(nr, G.procs + i, FALSE, 100); | ||
173 | |||
174 | if (ret != WAIT_TIMEOUT) | ||
175 | break; | ||
176 | i += MAXIMUM_WAIT_OBJECTS; | ||
177 | if (i > G.running_procs) | ||
178 | i = 0; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | goto check_exit_codes; | ||
183 | } | ||
184 | #endif /* SUPPORT_PARALLEL && PLATFORM_MINGW32 */ | ||
185 | |||
134 | /* | 186 | /* |
135 | * Returns 0 if xargs should continue (but may set G.xargs_exitcode to 123). | 187 | * Returns 0 if xargs should continue (but may set G.xargs_exitcode to 123). |
136 | * Else sets G.xargs_exitcode to error code and returns nonzero. | 188 | * Else sets G.xargs_exitcode to error code and returns nonzero. |
@@ -147,6 +199,23 @@ static int xargs_exec(void) | |||
147 | if (G.max_procs == 1) { | 199 | if (G.max_procs == 1) { |
148 | status = spawn_and_wait(G.args); | 200 | status = spawn_and_wait(G.args); |
149 | } else { | 201 | } else { |
202 | #if ENABLE_PLATFORM_MINGW32 | ||
203 | int idx; | ||
204 | status = !G.running_procs && !G.max_procs ? 0 : wait_for_slot(&idx); | ||
205 | if (G.max_procs) { | ||
206 | HANDLE p = (HANDLE)mingw_spawn_proc((const char **)G.args); | ||
207 | if (p < 0) | ||
208 | status = -1; | ||
209 | else | ||
210 | G.procs[idx] = p; | ||
211 | } else { | ||
212 | while (G.running_procs) { | ||
213 | int status2 = wait_for_slot(&idx); | ||
214 | if (status2 && !status) | ||
215 | status = status2; | ||
216 | } | ||
217 | } | ||
218 | #else | ||
150 | pid_t pid; | 219 | pid_t pid; |
151 | int wstat; | 220 | int wstat; |
152 | again: | 221 | again: |
@@ -187,6 +256,7 @@ static int xargs_exec(void) | |||
187 | /* final waitpid() loop: must be ECHILD "no more children" */ | 256 | /* final waitpid() loop: must be ECHILD "no more children" */ |
188 | status = 0; | 257 | status = 0; |
189 | } | 258 | } |
259 | #endif | ||
190 | } | 260 | } |
191 | #endif | 261 | #endif |
192 | /* Manpage: | 262 | /* Manpage: |
@@ -622,7 +692,12 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) | |||
622 | 692 | ||
623 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL | 693 | #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL |
624 | if (G.max_procs <= 0) /* -P0 means "run lots of them" */ | 694 | if (G.max_procs <= 0) /* -P0 means "run lots of them" */ |
695 | #if !ENABLE_PLATFORM_MINGW32 | ||
625 | G.max_procs = 100; /* let's not go crazy high */ | 696 | G.max_procs = 100; /* let's not go crazy high */ |
697 | #else | ||
698 | G.max_procs = MAXIMUM_WAIT_OBJECTS; | ||
699 | G.procs = xmalloc(sizeof(G.procs[0]) * G.max_procs); | ||
700 | #endif | ||
626 | #endif | 701 | #endif |
627 | 702 | ||
628 | #if ENABLE_FEATURE_XARGS_SUPPORT_ARGS_FILE | 703 | #if ENABLE_FEATURE_XARGS_SUPPORT_ARGS_FILE |