From: Tollef Fog Heen Date: Tue, 30 Jun 2009 02:49:07 +0000 (+0200) Subject: parallel: Implement -l (maxload) and -i (replace {}) X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e608a0284a84bb37a5a621eae72b0a456ec5484b;p=moreutils parallel: Implement -l (maxload) and -i (replace {}) Add support for only starting jobs when the load average is low enough, this is done with -l and acts similarly to how make does it. In order to construct more complex commands, add -i which will make parallel replace {} with the argument at an arbitrary place in the command line. --- diff --git a/parallel.c b/parallel.c index 2333a3d..438bc93 100644 --- a/parallel.c +++ b/parallel.c @@ -38,7 +38,7 @@ void usage() exit(1); } -void exec_child(char **command, char *argument) +void exec_child(char **command, char *argument, int replace_cb) { char **argv; int argc = 0; @@ -47,12 +47,16 @@ void exec_child(char **command, char *argument) while (command[argc] != 0) { argc++; } - argc++; + if (replace_cb == 0) + argc++; argv = calloc(sizeof(char*), argc+1); for (i = 0; i < argc; i++) { argv[i] = command[i]; + if (replace_cb && (strcmp(argv[i], "{}") == 0)) + argv[i] = argument; } - argv[i-1] = argument; + if (replace_cb == 0) + argv[i-1] = argument; if (fork() == 0) { /* Child */ execvp(argv[0], argv); @@ -61,11 +65,15 @@ void exec_child(char **command, char *argument) return; } -int wait_for_child(void) +int wait_for_child(int options) { id_t id_ignored = 0; siginfo_t infop; - waitid(P_ALL, id_ignored, &infop, WEXITED); + + infop.si_pid = 0; + waitid(P_ALL, id_ignored, &infop, WEXITED | options); + if (infop.si_pid == 0) + return -1; /* Nothing to wait for */ if (infop.si_code == CLD_EXITED) return infop.si_status; return 1; @@ -82,12 +90,16 @@ int main(int argc, char **argv) int argidx = 0; int cidx = 0; int returncode = 0; + int replace_cb = 0; - while ((opt = getopt(argc, argv, "+hj:l:")) != -1) { + while ((opt = getopt(argc, argv, "+hij:l:")) != -1) { switch (opt) { case 'h': usage(); break; + case 'i': + replace_cb = 1; + break; case 'j': maxjobs = atoi(optarg); break; @@ -100,7 +112,7 @@ int main(int argc, char **argv) } } - if (maxjobs < 0) { + if (maxjobs < 0 && maxload < 0) { usage(); } @@ -130,19 +142,35 @@ int main(int argc, char **argv) } while (arguments[argidx] != 0) { - if (maxjobs > 0 && curjobs < maxjobs) { - exec_child(command, arguments[argidx]); + double load; + + getloadavg(&load, 1); + + if ((maxjobs > 0 && curjobs < maxjobs) || + (maxload > 0 && load < maxload)) { + exec_child(command, arguments[argidx], replace_cb); argidx++; curjobs++; } if (maxjobs > 0 && curjobs == maxjobs) { - returncode |= wait_for_child(); + returncode |= wait_for_child(0); curjobs--; } + + if (maxload > 0 && load > maxload) { + int r; + sleep(1); /* XXX We should have a better + * heurestic than this */ + r = wait_for_child(WNOHANG); + if (r > 0) { + returncode |= r; + curjobs--; + } + } } while (curjobs > 0) { - returncode |= wait_for_child(); + returncode |= wait_for_child(0); curjobs--; }