diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2024-11-06 08:05:33 +0000 |
---|---|---|
committer | Laurent Bercot <ska@appnovation.com> | 2024-11-06 08:05:33 +0000 |
commit | 3d91d9ce645efa020800b85be1ac2727ebcbad19 (patch) | |
tree | 4461d2c99abfb80f3955b4f775b26767e823fc6a | |
parent | 32ed930a967c83c5b683d1d22c286b46a9f792ea (diff) | |
download | execline-3d91d9ce645efa020800b85be1ac2727ebcbad19.tar.gz execline-3d91d9ce645efa020800b85be1ac2727ebcbad19.tar.xz execline-3d91d9ce645efa020800b85be1ac2727ebcbad19.zip |
Prepare for 2.9.7.0 ; rework forx/forstdin -p, add -P maxpar
Also refactor several things to keep global footprint low Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | doc/forstdin.html | 14 | ||||
-rw-r--r-- | doc/forx.html | 14 | ||||
-rw-r--r-- | doc/index.html | 2 | ||||
-rw-r--r-- | doc/upgrade.html | 7 | ||||
-rw-r--r-- | package/deps.mak | 8 | ||||
-rw-r--r-- | package/info | 2 | ||||
-rw-r--r-- | src/execline/forstdin.c | 89 | ||||
-rw-r--r-- | src/execline/forx.c | 78 | ||||
-rw-r--r-- | src/include/execline/execline.h | 17 | ||||
-rw-r--r-- | src/libexecline/deps-lib/execline | 2 | ||||
-rw-r--r-- | src/libexecline/el_forx_pidinfo.c | 25 | ||||
-rw-r--r-- | src/libexecline/el_gspawn0.c | 8 | ||||
-rw-r--r-- | src/libexecline/el_modif_and_exec.c | 5 | ||||
-rw-r--r-- | src/libexecline/el_modif_and_spawn.c | 13 | ||||
-rw-r--r-- | src/libexecline/el_modifs_and_exec.c | 5 | ||||
-rw-r--r-- | src/libexecline/el_spawn0.c | 8 | ||||
-rw-r--r-- | src/libexecline/el_trueargv.c | 7 |
18 files changed, 150 insertions, 159 deletions
diff --git a/NEWS b/NEWS index 8e5602f..72be9f5 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,10 @@ Changelog for execline. +In 2.9.7.0 + + - New "-P maxpar" option to forx and forstdin, for bounded parallelism. + + In 2.9.6.1 ---------- diff --git a/doc/forstdin.html b/doc/forstdin.html index 25f951f..14b9a3b 100644 --- a/doc/forstdin.html +++ b/doc/forstdin.html @@ -50,6 +50,11 @@ and 1 if it hasn't read anything. </li> instance to finish before spawning the next one. forstdin will still wait for all instances of <em>loop</em> to terminate before exiting, though. </li> + <li> <tt>-P</tt> <em>maxpar</em> : like <tt>-p</tt>, but only +run up to <em>maxpar</em> instances at a time. Minimum is 1; maximum is +10000. <tt>-p</tt> is equivalent to <tt>-P 10000</tt>, i.e. it can +spawn a very large number of loop instances in parallel, but it's +technically not infinite. </li> <li> <tt>-o</tt> <em>okcodes</em> : <em>okcodes</em> must be a comma-separated list of exit codes. If the <tt>-p</tt> flag hasn't been given and <em>loop</em> exits with one of the codes in @@ -63,7 +68,7 @@ that will make forstdin break the loop and exit, and the unlisted exit codes will make it keep looping. </li> <li> <tt>-e</tt> : no autoimport. This is the default. </li> <li> <tt>-E</tt> : autoimport. Instead of spawning -<em>loop...</em>, spawn <tt>importas -ui <em>variable</em> <em>variable</em> +<em>loop...</em>, spawn <tt>importas -uSi <em>variable</em> <em>loop...</em></tt>. This substitutes <em>variable</em> into the command line instead of putting it into the environment. </li> </ul> @@ -94,12 +99,5 @@ used simultaneously, the rightmost one wins. </li> the input is only split on newlines. </li> </ul> -<h2> Notes </h2> - -<ul> - <li> You can start <em>loop...</em> with <tt>importas -u <em>variable</em> <em>variable</em></tt> -to perform variable substitution. </li> -</ul> - </body> </html> diff --git a/doc/forx.html b/doc/forx.html index 8f1d558..b20ab65 100644 --- a/doc/forx.html +++ b/doc/forx.html @@ -29,7 +29,7 @@ </p> <pre> - forx [ -E | -e ] [ -p ] [ -o <em>okcodes</em> | -x <em>breakcodes</em> ] <em>variable</em> { <em>args...</em> } <em>loop...</em> + forx [ -E | -e ] [ -p | -P <em>maxpar</em> ] [ -o <em>okcodes</em> | -x <em>breakcodes</em> ] <em>variable</em> { <em>args...</em> } <em>loop...</em> </pre> <ul> @@ -65,16 +65,12 @@ list, else it will exit 1. If the <tt>-x</tt> option has been given, listed in the <em>breakcodes</em> list, else it will exit 1. </li> <li> <tt>-e</tt> : no autoimport. This is the default. </li> <li> <tt>-E</tt> : autoimport. Instead of spawning -<em>loop...</em>, spawn <tt>importas -ui <em>variable</em> <em>variable</em> +<em>loop...</em>, spawn <tt>importas -uSi <em>variable</em> <em>loop...</em></tt>. This substitutes <em>variable</em> into the command line instead of putting it into the environment. </li> -</ul> - -<h2> Notes </h2> - -<ul> - <li> You can start <em>loop</em> with "importas -u <em>variable</em> <em>variable</em>" -if you want variable substitution. </li> + <li> <tt>-P</tt> <em>maxpar</em> : similar to <tt>-p</tt>, but run +up to <em>maxpar</em> instances in parallel, i.e. never have more than <em>maxpar</em> +children at the same time. Minimum is 1. </li> </ul> </body> diff --git a/doc/index.html b/doc/index.html index beb61bd..6dbab1c 100644 --- a/doc/index.html +++ b/doc/index.html @@ -77,7 +77,7 @@ want nsswitch-like functionality: <h3> Download </h3> <ul> - <li> The current released version of execline is <a href="execline-2.9.6.1.tar.gz">2.9.6.1</a>. </li> + <li> The current released version of execline is <a href="execline-2.9.7.0.tar.gz">2.9.7.0</a>. </li> <li> Alternatively, you can checkout a copy of the <a href="//git.skarnet.org/cgi-bin/cgit.cgi/execline/">execline git repository</a>: diff --git a/doc/upgrade.html b/doc/upgrade.html index aeaf0ba..31ddf00 100644 --- a/doc/upgrade.html +++ b/doc/upgrade.html @@ -18,6 +18,13 @@ <h1> What has changed in execline </h1> +<h2> in 2.9.7.0 </h2> + +<ul> + <li> <em> New <tt>-P</tt> option to +<a href="forx.html">forx</a> and <a href="forstdin.html">forstdin</a>. </li> +</ul> + <h2> in 2.9.6.1 </h2> <ul> diff --git a/package/deps.mak b/package/deps.mak index a8acd4d..1944f0c 100644 --- a/package/deps.mak +++ b/package/deps.mak @@ -53,6 +53,7 @@ src/execline/unexport.o src/execline/unexport.lo: src/execline/unexport.c src/execline/wait.o src/execline/wait.lo: src/execline/wait.c src/include/execline/config.h src/include/execline/execline.h src/execline/withstdinas.o src/execline/withstdinas.lo: src/execline/withstdinas.c src/include/execline/execline.h src/libexecline/el_execsequence.o src/libexecline/el_execsequence.lo: src/libexecline/el_execsequence.c src/include/execline/execline.h +src/libexecline/el_forx_pidinfo.o src/libexecline/el_forx_pidinfo.lo: src/libexecline/el_forx_pidinfo.c src/include/execline/execline.h src/libexecline/el_getstrict.o src/libexecline/el_getstrict.lo: src/libexecline/el_getstrict.c src/include/execline/execline.h src/libexecline/el_gspawn0.o src/libexecline/el_gspawn0.lo: src/libexecline/el_gspawn0.c src/include/execline/config.h src/include/execline/execline.h src/libexecline/el_modif_and_exec.o src/libexecline/el_modif_and_exec.lo: src/libexecline/el_modif_and_exec.c src/include/execline/config.h src/include/execline/execline.h @@ -69,6 +70,7 @@ src/libexecline/el_substandrun.o src/libexecline/el_substandrun.lo: src/libexecl src/libexecline/el_substandrun_str.o src/libexecline/el_substandrun_str.lo: src/libexecline/el_substandrun_str.c src/include/execline/execline.h src/include-local/exlsn.h src/libexecline/el_substitute.o src/libexecline/el_substitute.lo: src/libexecline/el_substitute.c src/include/execline/execline.h src/libexecline/el_transform.o src/libexecline/el_transform.lo: src/libexecline/el_transform.c src/include/execline/execline.h +src/libexecline/el_trueargv.o src/libexecline/el_trueargv.lo: src/libexecline/el_trueargv.c src/include/execline/config.h src/include/execline/execline.h src/libexecline/el_vardupl.o src/libexecline/el_vardupl.lo: src/libexecline/el_vardupl.c src/include/execline/execline.h src/libexecline/exlp.o src/libexecline/exlp.lo: src/libexecline/exlp.c src/include/execline/execline.h src/include-local/exlsn.h src/libexecline/exlsn_define.o src/libexecline/exlsn_define.lo: src/libexecline/exlsn_define.c src/include/execline/execline.h src/include-local/exlsn.h @@ -180,12 +182,12 @@ wait: src/execline/wait.o ${LIBEXECLINE} withstdinas: EXTRA_LIBS := -lskarnet withstdinas: src/execline/withstdinas.o ${LIBEXECLINE} ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),) -libexecline.a.xyzzy: src/libexecline/el_execsequence.o src/libexecline/el_getstrict.o src/libexecline/el_modif_and_exec.o src/libexecline/el_modif_and_spawn.o src/libexecline/el_modifs_and_exec.o src/libexecline/el_parse.o src/libexecline/el_parse_from_buffer.o src/libexecline/el_parse_from_string.o src/libexecline/el_popenv.o src/libexecline/el_pushenv.o src/libexecline/el_semicolon.o src/libexecline/el_spawn0.o src/libexecline/el_gspawn0.o src/libexecline/el_substandrun.o src/libexecline/el_substandrun_str.o src/libexecline/el_substitute.o src/libexecline/el_transform.o src/libexecline/el_vardupl.o src/libexecline/exlsn_define.o src/libexecline/exlsn_elglob.o src/libexecline/exlsn_importas.o src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_exlp.o src/libexecline/exlsn_main.o src/libexecline/exlsn_free.o src/libexecline/exlp.o +libexecline.a.xyzzy: src/libexecline/el_execsequence.o src/libexecline/el_forx_pidinfo.o src/libexecline/el_getstrict.o src/libexecline/el_modif_and_exec.o src/libexecline/el_modif_and_spawn.o src/libexecline/el_modifs_and_exec.o src/libexecline/el_parse.o src/libexecline/el_parse_from_buffer.o src/libexecline/el_parse_from_string.o src/libexecline/el_popenv.o src/libexecline/el_pushenv.o src/libexecline/el_semicolon.o src/libexecline/el_spawn0.o src/libexecline/el_gspawn0.o src/libexecline/el_substandrun.o src/libexecline/el_substandrun_str.o src/libexecline/el_substitute.o src/libexecline/el_transform.o src/libexecline/el_trueargv.o src/libexecline/el_vardupl.o src/libexecline/exlsn_define.o src/libexecline/exlsn_elglob.o src/libexecline/exlsn_importas.o src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_exlp.o src/libexecline/exlsn_main.o src/libexecline/exlsn_free.o src/libexecline/exlp.o else -libexecline.a.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_modif_and_exec.lo src/libexecline/el_modif_and_spawn.lo src/libexecline/el_modifs_and_exec.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_gspawn0.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo +libexecline.a.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_forx_pidinfo.lo src/libexecline/el_getstrict.lo src/libexecline/el_modif_and_exec.lo src/libexecline/el_modif_and_spawn.lo src/libexecline/el_modifs_and_exec.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_gspawn0.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_trueargv.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo endif libexecline.so.xyzzy: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} -libexecline.so.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_modif_and_exec.lo src/libexecline/el_modif_and_spawn.lo src/libexecline/el_modifs_and_exec.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_gspawn0.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo +libexecline.so.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_forx_pidinfo.lo src/libexecline/el_getstrict.lo src/libexecline/el_modif_and_exec.lo src/libexecline/el_modif_and_spawn.lo src/libexecline/el_modifs_and_exec.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_gspawn0.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_trueargv.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo execline: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} ${MAYBEPTHREAD_LIB} execline: src/multicall/execline.o ${LIBEXECLINE} ${LIBNSSS} INTERNAL_LIBS := diff --git a/package/info b/package/info index 0ee7de4..3e3b38d 100644 --- a/package/info +++ b/package/info @@ -1,4 +1,4 @@ package=execline -version=2.9.6.1 +version=2.9.7.0 category=admin package_macro_name=EXECLINE diff --git a/src/execline/forstdin.c b/src/execline/forstdin.c index b023640..d1e065c 100644 --- a/src/execline/forstdin.c +++ b/src/execline/forstdin.c @@ -2,6 +2,7 @@ #include <string.h> #include <errno.h> +#include <signal.h> #include <skalibs/types.h> #include <skalibs/sgetopt.h> @@ -19,56 +20,31 @@ #define USAGE "forstdin [ -E | -e ] [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] [ -N | -n ] [ -C | -c ] [ -0 | -d delim ] var command..." #define dieusage() strerr_dieusage(100, USAGE) -static genalloc *forstdin_pids_p = 0 ; /* minimize bss/data */ - -static int fs_isok (unsigned short *tab, unsigned int n, int code) -{ - unsigned int i = 0 ; - for (; i < n ; i++) if ((unsigned short)code == tab[i]) break ; - return i < n ; -} - -static void parallel_sigchld_handler (int sig) -{ - pid_t *tab = genalloc_s(pid_t, forstdin_pids_p) ; - size_t len = genalloc_len(pid_t, forstdin_pids_p) ; - int wstat ; - for (;;) - { - ssize_t r = wait_pids_nohang(tab, len, &wstat) ; - if (r <= 0) break ; - tab[r-1] = tab[--len] ; - } - genalloc_setlen(pid_t, forstdin_pids_p, len) ; - (void)sig ; -} - int main (int argc, char const **argv) { - genalloc pids = GENALLOC_ZERO ; + el_forx_pidinfo_t pidinfo = EL_FORX_PIDINFO_ZERO ; stralloc value = STRALLOC_ZERO ; + sigset_t emptyset ; char const *delim = "\n" ; size_t delimlen = 1 ; size_t nbc = 0 ; + unsigned int maxpar = 1 ; unsigned short okcodes[256] ; int crunch = 0, chomp = 1, not = 1, eofcode = 1, doimport = 0 ; PROG = "forstdin" ; - forstdin_pids_p = &pids ; + el_forx_pidinfo = &pidinfo ; + sigemptyset(&emptyset) ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { - int opt = subgetopt_r(argc, argv, "pNnCc0d:o:x:Ee", &l) ; + int opt = subgetopt_r(argc, argv, "pP:NnCc0d:o:x:Ee", &l) ; if (opt == -1) break ; switch (opt) { - case 'p' : - { - if (!genalloc_ready(pid_t, &pids, 1)) - strerr_diefu1sys(111, "genalloc_ready") ; - break ; - } + case 'p' : maxpar = 10000 ; break ; + case 'P' : if (!uint0_scan(l.arg, &maxpar)) dieusage() ; break ; case 'N' : chomp = 0 ; break ; case 'n' : chomp = 1 ; break ; case 'C' : crunch = 1 ; break ; @@ -92,15 +68,16 @@ int main (int argc, char const **argv) } if (argc < 2) dieusage() ; if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ; + if (maxpar < 1) maxpar = 1 ; + if (maxpar >= 10000) maxpar = 10000 ; + if (!sig_catch(SIGCHLD, &el_forx_sigchld_handler)) + strerr_diefu1sys(111, "install SIGCHLD handler") ; - if (pids.s) - { - if (!sig_catch(SIGCHLD, ¶llel_sigchld_handler)) - strerr_diefu1sys(111, "install SIGCHLD handler") ; - } + pid_t pidtab[maxpar] ; + pidinfo.tab = pidtab ; + sig_block(SIGCHLD) ; for (;;) { - pid_t pid ; value.len = 0 ; if (delimlen) { @@ -125,34 +102,16 @@ int main (int argc, char const **argv) } eofcode = 0 ; if (!stralloc_0(&value)) strerr_diefu1sys(111, "stralloc_0") ; - if (pids.s) sig_block(SIGCHLD) ; - pid = el_modif_and_spawn(argv + 1, argv[0], value.s, doimport) ; - if (!pid) strerr_diefu2sys(111, "spawn ", argv[1]) ; - if (pids.s) - { - if (!genalloc_append(pid_t, &pids, &pid)) - strerr_diefu1sys(111, "genalloc_append") ; - sig_unblock(SIGCHLD) ; - } - else - { - int wstat ; - if (wait_pid(pid, &wstat) < 0) - strerr_diefu2sys(111, "wait for ", argv[1]) ; - if (not == fs_isok(okcodes, nbc, wait_estatus(wstat))) - return wait_estatus(wstat) ; - } - } - if (pids.s) - { - sigset_t empty ; - sigemptyset(&empty) ; - sig_block(SIGCHLD) ; - for (;;) + pidtab[pidinfo.len] = el_modif_and_spawn(argv + 1, argv[0], value.s, doimport) ; + if (!pidtab[pidinfo.len]) strerr_diefu2sys(111, "spawn ", argv[1]) ; + pidinfo.len++ ; + while (pidinfo.len >= maxpar) { - if (!pids.len) break ; - sigsuspend(&empty) ; + sigsuspend(&emptyset) ; + if (maxpar == 1 && not == el_forx_isok(okcodes, nbc, wait_estatus(pidinfo.wstat))) + return wait_estatus(pidinfo.wstat) ; } } + while (pidinfo.len) sigsuspend(&emptyset) ; return eofcode ; } diff --git a/src/execline/forx.c b/src/execline/forx.c index 1695c00..07ac4e6 100644 --- a/src/execline/forx.c +++ b/src/execline/forx.c @@ -1,11 +1,14 @@ /* ISC license. */ #include <string.h> +#include <signal.h> +#include <limits.h> #include <skalibs/sgetopt.h> #include <skalibs/bytestr.h> #include <skalibs/strerr.h> #include <skalibs/env.h> +#include <skalibs/sig.h> #include <skalibs/djbunix.h> #include <skalibs/skamisc.h> #include <skalibs/types.h> @@ -13,52 +16,32 @@ #include <execline/config.h> #include <execline/execline.h> -#define USAGE "forx [ -E | -e ] [ -p ] [ -o okcode,okcode,... | -x breakcode,breakcode,... ] var { values... } command..." +#define USAGE "forx [ -E | -e ] [ -p | -P maxpar ] [ -o okcode,okcode,... | -x breakcode,breakcode,... ] var { values... } command..." #define dieusage() strerr_dieusage(100, USAGE) -static int fx_isok (unsigned short const *tab, unsigned int n, int code) -{ - unsigned int i = 0 ; - for (; i < n ; i++) if ((unsigned short)code == tab[i]) break ; - return i < n ; -} - -static int waitn_code (unsigned short const *tab, unsigned int nbc, pid_t *pids, unsigned int n, int not) -{ - int ok = 1 ; - while (n) - { - int wstat ; - unsigned int i = 0 ; - pid_t pid = wait_nointr(&wstat) ; - if (pid < 0) return -1 ; - for (; i < n ; i++) if (pid == pids[i]) break ; - if (i < n) - { - if (not == fx_isok(tab, nbc, wait_estatus(wstat))) ok = 0 ; - pids[i] = pids[--n] ; - } - } - return ok ; -} - int main (int argc, char const **argv) { char const *var ; + el_forx_pidinfo_t pidinfo = EL_FORX_PIDINFO_ZERO ; + sigset_t emptyset ; unsigned short okcodes[256] ; size_t nbc = 0 ; - int flagpar = 0, not = 1, doimport = 0 ; - unsigned int argc1 ; + int not = 1, doimport = 0 ; + unsigned int maxpar = 1, argc1 ; PROG = "forx" ; + el_forx_pidinfo = &pidinfo ; + sigemptyset(&emptyset) ; + { subgetopt l = SUBGETOPT_ZERO ; for (;;) { - int opt = subgetopt_r(argc, argv, "po:x:Ee", &l) ; + int opt = subgetopt_r(argc, argv, "pP:o:x:Ee", &l) ; if (opt == -1) break ; switch (opt) { - case 'p' : flagpar = 1 ; break ; + case 'p' : maxpar = UINT_MAX ; break ; + case 'P' : if (!uint0_scan(l.arg, &maxpar)) dieusage() ; break ; case 'o' : not = 0 ; if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ; @@ -81,30 +64,29 @@ int main (int argc, char const **argv) argc1 = el_semicolon(argv) ; if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; if (!argc1 || (argc1 + 1 == argc)) return 0 ; + if (maxpar < 1) maxpar = 1 ; + if (maxpar > argc1) maxpar = argc1 ; + if (!sig_catch(SIGCHLD, &el_forx_sigchld_handler)) + strerr_diefu1sys(111, "install SIGCHLD handler") ; { - pid_t pids[flagpar ? argc1 : 1] ; + pid_t pidtab[maxpar] ; + pidinfo.tab = pidtab ; + sig_block(SIGCHLD) ; + for (unsigned int i = 0 ; i < argc1 ; i++) { - pid_t pid = el_modif_and_spawn(argv + argc1 + 1, var, argv[i], doimport) ; - if (!pid) strerr_diefu2sys(111, "spawn ", argv[argc1+1]) ; - if (flagpar) pids[i] = pid ; - else + pidtab[pidinfo.len] = el_modif_and_spawn(argv + argc1 + 1, var, argv[i], doimport) ; + if (!pidtab[pidinfo.len]) strerr_diefu2sys(111, "spawn ", argv[argc1+1]) ; + pidinfo.len++ ; + while (pidinfo.len >= maxpar) { - int wstat ; - if (wait_pid(pid, &wstat) == -1) - strerr_diefu2sys(111, "wait for ", argv[argc1+1]) ; - if (not == fx_isok(okcodes, nbc, wait_estatus(wstat))) - return wait_estatus(wstat) ; + sigsuspend(&emptyset) ; + if (maxpar == 1 && not == el_forx_isok(okcodes, nbc, wait_estatus(pidinfo.wstat))) + return wait_estatus(pidinfo.wstat) ; } } - - if (flagpar) - { - int r = waitn_code(okcodes, nbc, pids, argc1, not) ; - if (r < 0) strerr_diefu1sys(111, "waitn") ; - else if (!r) return 1 ; - } + while (pidinfo.len) sigsuspend(&emptyset) ; } return 0 ; } diff --git a/src/include/execline/execline.h b/src/include/execline/execline.h index 8a204d8..7fdef51 100644 --- a/src/include/execline/execline.h +++ b/src/include/execline/execline.h @@ -80,8 +80,25 @@ extern int el_substitute (stralloc *, char const *, size_t, char const *, char c /* Execution with or without substitution */ +extern char const *const *el_trueargv ; extern void el_modif_and_exec (char const *const *, char const *, char const *, int) gccattr_noreturn ; extern pid_t el_modif_and_spawn (char const *const *, char const *, char const *, int) ; extern void el_modifs_and_exec (char const *const *, char const *const *, char const *const *, size_t, int) gccattr_noreturn ; + + /* Spawning and waiting for several children at once */ + +typedef struct el_forx_pidinfo_s el_forx_pidinfo_t, *el_forx_pidinfo_t_ref ; +struct el_forx_pidinfo_s +{ + pid_t *tab ; + unsigned int len ; + int wstat ; +} ; +#define EL_FORX_PIDINFO_ZERO { .tab = 0, .len = 0, .wstat = 0 } + +extern el_forx_pidinfo_t *el_forx_pidinfo ; +extern void el_forx_sigchld_handler (int) ; +extern int el_forx_isok (unsigned short const *, unsigned int, unsigned short) ; + #endif diff --git a/src/libexecline/deps-lib/execline b/src/libexecline/deps-lib/execline index 608fa7f..d5888c0 100644 --- a/src/libexecline/deps-lib/execline +++ b/src/libexecline/deps-lib/execline @@ -1,4 +1,5 @@ el_execsequence.o +el_forx_pidinfo.o el_getstrict.o el_modif_and_exec.o el_modif_and_spawn.o @@ -15,6 +16,7 @@ el_substandrun.o el_substandrun_str.o el_substitute.o el_transform.o +el_trueargv.o el_vardupl.o exlsn_define.o exlsn_elglob.o diff --git a/src/libexecline/el_forx_pidinfo.c b/src/libexecline/el_forx_pidinfo.c new file mode 100644 index 0000000..61c5a26 --- /dev/null +++ b/src/libexecline/el_forx_pidinfo.c @@ -0,0 +1,25 @@ +/* ISC license. */ + +#include <skalibs/djbunix.h> + +#include <execline/execline.h> + +el_forx_pidinfo_t *el_forx_pidinfo = 0 ; + +int el_forx_isok (unsigned short const *tab, unsigned int n, unsigned short code) +{ + unsigned int i = 0 ; + for (; i < n ; i++) if (code == tab[i]) break ; + return i < n ; +} + +void el_forx_sigchld_handler (int sig) +{ + for (;;) + { + ssize_t r = wait_pids_nohang(el_forx_pidinfo->tab, el_forx_pidinfo->len, &el_forx_pidinfo->wstat) ; + if (r <= 0) break ; + el_forx_pidinfo->tab[r-1] = el_forx_pidinfo->tab[--el_forx_pidinfo->len] ; + } + (void)sig ; +} diff --git a/src/libexecline/el_gspawn0.c b/src/libexecline/el_gspawn0.c index d6e0d3a..2a5cb97 100644 --- a/src/libexecline/el_gspawn0.c +++ b/src/libexecline/el_gspawn0.c @@ -7,10 +7,6 @@ pid_t el_gspawn0 (char const *prog, char const *const *argv, char const *const *envp) { - if (!argv[0]) - { - static char const *const newargv[3] = { EXECLINE_BINPREFIX "exit", "0", 0 } ; - return gcspawn(newargv[0], newargv, envp, 0, 0, 0) ; - } - else return gcspawn(prog, argv, envp, 0, 0, 0) ; + if (!argv[0]) argv = el_trueargv ; + return gcspawn(prog, argv, envp, 0, 0, 0) ; } diff --git a/src/libexecline/el_modif_and_exec.c b/src/libexecline/el_modif_and_exec.c index e2a3618..c94d301 100644 --- a/src/libexecline/el_modif_and_exec.c +++ b/src/libexecline/el_modif_and_exec.c @@ -22,12 +22,11 @@ void el_modif_and_exec (char const *const *argv, char const *var, char const *va if (doimport) { size_t m = 0 ; - char const *newargv[env_len(argv) + 6] ; + char const *newargv[env_len(argv) + 5] ; newargv[m++] = EXECLINE_BINPREFIX "importas" ; - newargv[m++] = "-ui" ; + newargv[m++] = "-uSi" ; newargv[m++] = "--" ; newargv[m++] = var ; - newargv[m++] = var ; while (*argv) newargv[m++] = *argv++ ; newargv[m++] = 0 ; xmexec0_n(newargv, value ? modifs : var, value ? modiflen : varlen + 1, 1) ; diff --git a/src/libexecline/el_modif_and_spawn.c b/src/libexecline/el_modif_and_spawn.c index 863ca92..7f36a37 100644 --- a/src/libexecline/el_modif_and_spawn.c +++ b/src/libexecline/el_modif_and_spawn.c @@ -4,6 +4,7 @@ #include <skalibs/posixplz.h> #include <skalibs/env.h> +#include <skalibs/cspawn.h> #include <execline/config.h> #include <execline/execline.h> @@ -22,18 +23,18 @@ pid_t el_modif_and_spawn (char const *const *argv, char const *var, char const * memcpy(modifs + varlen + 1, value, modiflen - varlen - 1) ; } env_mergen(newenv, envlen + 2, (char const *const *)environ, envlen, value ? modifs : var, value ? modiflen : varlen + 1, 1) ; - if (doimport) + if (doimport && argv[0]) { size_t m = 0 ; - char const *newargv[env_len(argv) + 6] ; + char const *newargv[env_len(argv) + 5] ; newargv[m++] = EXECLINE_BINPREFIX "importas" ; - newargv[m++] = "-ui" ; + newargv[m++] = "-uSi" ; newargv[m++] = "--" ; newargv[m++] = var ; - newargv[m++] = var ; while (*argv) newargv[m++] = *argv++ ; newargv[m++] = 0 ; - return el_spawn0(newargv[0], newargv, newenv) ; + return cspawn(newargv[0], newargv, newenv, CSPAWN_FLAGS_SIGBLOCKNONE, 0, 0) ; } - else return el_spawn0(argv[0], argv, newenv) ; + if (!argv[0]) argv = el_trueargv ; + return cspawn(argv[0], argv, newenv, CSPAWN_FLAGS_SIGBLOCKNONE, 0, 0) ; } diff --git a/src/libexecline/el_modifs_and_exec.c b/src/libexecline/el_modifs_and_exec.c index ca72291..675e284 100644 --- a/src/libexecline/el_modifs_and_exec.c +++ b/src/libexecline/el_modifs_and_exec.c @@ -47,7 +47,7 @@ void el_modifs_and_exec (char const *const *argv, char const *const *vars, char { size_t m = 0 ; size_t ypos = 0 ; - char const *newargv[env_len(argv) + 3 + 5 * yesn] ; + char const *newargv[env_len(argv) + 3 + 4 * yesn] ; char yesvars[yeslen ? yeslen : 1] ; newargv[m++] = EXECLINE_BINPREFIX "multisubstitute" ; for (size_t i = 0 ; i < n ; i++) if (values[i]) @@ -55,10 +55,9 @@ void el_modifs_and_exec (char const *const *argv, char const *const *vars, char size_t len = strlen(vars[i]) + 1 ; char *p = yesvars + ypos ; newargv[m++] = " importas" ; - newargv[m++] = " -ui" ; + newargv[m++] = " -uSi" ; newargv[m++] = " --" ; newargv[m++] = p ; - newargv[m++] = p ; yesvars[ypos++] = ' ' ; memcpy(yesvars + ypos, vars[i], len) ; ypos += len ; diff --git a/src/libexecline/el_spawn0.c b/src/libexecline/el_spawn0.c index d397557..a05ed5d 100644 --- a/src/libexecline/el_spawn0.c +++ b/src/libexecline/el_spawn0.c @@ -7,10 +7,6 @@ pid_t el_spawn0 (char const *prog, char const *const *argv, char const *const *envp) { - if (!argv[0]) - { - static char const *const newargv[3] = { EXECLINE_BINPREFIX "exit", "0", 0 } ; - return cspawn(newargv[0], newargv, envp, 0, 0, 0) ; - } - else return cspawn(prog, argv, envp, 0, 0, 0) ; + if (!argv[0]) argv = el_trueargv ; + return cspawn(prog, argv, envp, 0, 0, 0) ; } diff --git a/src/libexecline/el_trueargv.c b/src/libexecline/el_trueargv.c new file mode 100644 index 0000000..c08e127 --- /dev/null +++ b/src/libexecline/el_trueargv.c @@ -0,0 +1,7 @@ +/* ISC license. */ + +#include <execline/config.h> +#include <execline/execline.h> + +static char const *const el_trueargv_[3] = { EXECLINE_BINPREFIX "exit", "0", 0 } ; +char const *const *el_trueargv = el_trueargv_ ; |