aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schindelin <johannes.schindelin@gmx.de>2017-08-23 16:47:04 +0200
committerRon Yorston <rmy@pobox.com>2017-10-01 08:36:07 +0100
commitab450021a99ba66126cc6d668fb06ec3829a572b (patch)
tree73ce5e5c4d3054e7e59772ff4aa3bcd9d5c8db5d
parent2ac01855ce6667e9e3d23c76616eb38a73200883 (diff)
downloadbusybox-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_defconfig2
-rw-r--r--configs/mingw64_defconfig2
-rw-r--r--findutils/xargs.c75
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
465CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y 465CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
466CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y 466CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
467CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y 467CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
468# CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL is not set 468CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y
469CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y 469CONFIG_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
465CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y 465CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
466CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y 466CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
467CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y 467CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
468# CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL is not set 468CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y
469CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y 469CONFIG_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
139static 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
149check_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