2 * parallel.c - run commands in parallel until you run out of commands
4 * Copyright © 2008 Tollef Fog Heen <tfheen@err.no>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <sys/select.h>
31 #include <sys/types.h>
36 printf("parallel [OPTIONS] command -- arguments: for each argument, "
37 "run command with argument\n");
41 void exec_child(char **command
, char **arguments
, int replace_cb
, int nargs
) {
46 while (command
[argc
] != 0) {
51 argv
= calloc(sizeof(char*), argc
+ nargs
);
52 for (i
= 0; i
< argc
; i
++) {
54 if (replace_cb
&& (strcmp(argv
[i
], "{}") == 0))
55 argv
[i
] = arguments
[0];
58 memcpy(argv
+ i
- 1, arguments
, nargs
* sizeof(char *));
61 execvp(argv
[0], argv
);
67 int wait_for_child(int options
) {
72 waitid(P_ALL
, id_ignored
, &infop
, WEXITED
| options
);
73 if (infop
.si_pid
== 0)
74 return -1; /* Nothing to wait for */
75 if (infop
.si_code
== CLD_EXITED
)
76 return infop
.si_status
;
80 int main(int argc
, char **argv
) {
86 char **command
= calloc(sizeof(char*), argc
);
87 char **arguments
= NULL
;
95 while ((opt
= getopt(argc
, argv
, "+hij:l:n:")) != -1) {
105 maxjobs
= strtoul(optarg
, &t
, 0);
106 if (errno
!= 0 || (t
-optarg
) != strlen(optarg
)) {
107 fprintf(stderr
, "option '%s' is not a number\n",
114 maxload
= strtoul(optarg
, &t
, 0);
115 if (errno
!= 0 || (t
-optarg
) != strlen(optarg
)) {
116 fprintf(stderr
, "option '%s' is not a number\n",
123 argsatonce
= strtoul(optarg
, &t
, 0);
124 if (errno
!= 0 || argsatonce
< 1 || (t
-optarg
) != strlen(optarg
)) {
125 fprintf(stderr
, "option '%s' is not a positive number\n",
136 if (replace_cb
&& argsatonce
> 1) {
137 fprintf(stderr
, "options -i and -n are incomaptible\n");
142 #ifdef _SC_NPROCESSORS_ONLN
143 maxjobs
= sysconf(_SC_NPROCESSORS_ONLN
);
145 #warning Cannot autodetect number of CPUS on this system: _SC_NPROCESSORS_ONLN not defined.
150 while (optind
< argc
) {
151 if (strcmp(argv
[optind
], "--") == 0) {
155 arglen
= argc
- optind
;
156 arguments
= calloc(sizeof(char *), arglen
);
161 for (i
= 0; i
< arglen
; i
++) {
162 arguments
[i
] = strdup(argv
[optind
+ i
]);
167 command
[cidx
] = strdup(argv
[optind
]);
173 while (argidx
< arglen
) {
176 getloadavg(&load
, 1);
178 if ((maxjobs
> 0 && curjobs
< maxjobs
) ||
179 (maxload
> 0 && load
< maxload
)) {
180 if (argsatonce
> arglen
- argidx
)
181 argsatonce
= arglen
- argidx
;
182 exec_child(command
, arguments
+ argidx
,
183 replace_cb
, argsatonce
);
184 argidx
+= argsatonce
;
188 if (maxjobs
> 0 && curjobs
== maxjobs
) {
189 returncode
|= wait_for_child(0);
193 if (maxload
> 0 && load
> maxload
) {
195 sleep(1); /* XXX We should have a better
196 * heurestic than this */
197 r
= wait_for_child(WNOHANG
);
204 while (curjobs
> 0) {
205 returncode
|= wait_for_child(0);