From 059aa5c98d47b129c833ea15ce60af8e4ae38211 Mon Sep 17 00:00:00 2001 From: Michael Santos Date: Sun, 16 Mar 2014 16:32:18 -0400 Subject: [PATCH] Allowing setting the number of children per fork Add the ability to set the number of children per process at runtime. Since the port uses select(), the number of processes is limited by FD_SETSIZE: FD_SETSIZE / 3 - 3 3 fd's per child process + the parent's stdin, stdout and stderr. --- c_src/alcove.c | 24 +++++++++++++++++------- c_src/alcove.h | 3 +-- c_src/alcove_call.c | 20 +++++++++++--------- src/alcove_drv.erl | 14 +++++--------- test/alcove_tests.erl | 2 +- 5 files changed, 35 insertions(+), 28 deletions(-) diff --git a/c_src/alcove.c b/c_src/alcove.c index 4bb45a5..2a95366 100644 --- a/c_src/alcove.c +++ b/c_src/alcove.c @@ -88,16 +88,21 @@ main(int argc, char *argv[]) if (!ap) erl_err_sys("calloc"); - ap->child = calloc(ALCOVE_MAX_CHILD, sizeof(alcove_child_t)); - if (!ap->child) - erl_err_sys("calloc"); - act.sa_handler = sighandler; if (sigaction(SIGCHLD, &act, NULL) < 0) erl_err_sys("sigaction"); - while ( (ch = getopt(argc, argv, "hv")) != -1) { + /* 3 pipes per child */ + ap->maxchild = FD_SETSIZE / 3 - 3; + + while ( (ch = getopt(argc, argv, "am:hv")) != -1) { switch (ch) { + case 'm': { + u_int16_t n = (u_int16_t)atoi(optarg); + + if (n < ap->maxchild) + ap->maxchild = n; + } case 'v': ap->verbose++; break; @@ -107,6 +112,10 @@ main(int argc, char *argv[]) } } + ap->child = calloc(ap->maxchild, sizeof(alcove_child_t)); + if (!ap->child) + erl_err_sys("calloc"); + alcove_ctl(ap); exit(0); } @@ -119,7 +128,7 @@ alcove_ctl(alcove_state_t *ap) erl_init(NULL, 0); - (void)memset(ap->child, 0, sizeof(alcove_child_t) * ALCOVE_MAX_CHILD); + (void)memset(ap->child, 0, sizeof(alcove_child_t) * ap->maxchild); sigcaught = 0; for ( ; ; ) { @@ -380,7 +389,7 @@ pid_foreach(alcove_state_t *ap, pid_t pid, void *arg1, void *arg2, int i = 0; int rv = 0; - for (i = 0; i < ALCOVE_MAX_CHILD; i++) { + for (i = 0; i < ap->maxchild; i++) { if ((*comp)(ap->child[i].pid, pid) == 0) continue; @@ -555,6 +564,7 @@ usage(alcove_state_t *ap) __progname, ALCOVE_VERSION); (void)fprintf(stderr, "usage: %s \n" + " -m max children\n" " -v verbose mode\n", __progname ); diff --git a/c_src/alcove.h b/c_src/alcove.h index 74024df..663cd28 100644 --- a/c_src/alcove.h +++ b/c_src/alcove.h @@ -46,11 +46,10 @@ typedef struct { int fderr; } alcove_child_t; -#define ALCOVE_MAX_CHILD 16 - typedef struct { u_int32_t opt; u_int8_t verbose; + u_int16_t maxchild; alcove_child_t *child; } alcove_state_t; diff --git a/c_src/alcove_call.c b/c_src/alcove_call.c index 9b875b5..5b0e164 100644 --- a/c_src/alcove_call.c +++ b/c_src/alcove_call.c @@ -26,6 +26,8 @@ #include +static int cons_pid(alcove_child_t *c, void *arg1, void *arg2); + ETERM * alcove_call(alcove_state_t *ap, u_int32_t call, ETERM *arg) { @@ -52,15 +54,7 @@ alcove_version(alcove_state_t *ap, ETERM *arg) alcove_pid(alcove_state_t *ap, ETERM *arg) { ETERM *t = erl_mk_empty_list(); - int i = 0; - - for (i = 0; i < ALCOVE_MAX_CHILD; i++) { - if (ap->child[i].pid <= 0) - continue; - - t = erl_cons(erl_mk_int(ap->child[i].pid), t); - } - + (void)pid_foreach(ap, 0, &t, NULL, pid_not_equal, cons_pid); return t; } @@ -114,3 +108,11 @@ alcove_free_argv(char **argv) free(argv); } + + static int +cons_pid(alcove_child_t *c, void *arg1, void *arg2) +{ + ETERM **t = arg1; + *t = erl_cons(erl_mk_int(c->pid), *t); + return 1; +} diff --git a/src/alcove_drv.erl b/src/alcove_drv.erl index 4bc2ea9..d5062ba 100644 --- a/src/alcove_drv.erl +++ b/src/alcove_drv.erl @@ -325,25 +325,21 @@ getopts(Options) when is_list(Options) -> Exec = proplists:get_value(exec, Options, ""), Progname = proplists:get_value(progname, Options, progname()), - Options1 = proplists:substitute_aliases([{ns, namespace}], Options), - - Options2 = lists:map(fun + Options1 = lists:map(fun (verbose) -> {verbose, 1}; - ({Tag, [H|_] = N}) when is_atom(Tag), (is_list(H) orelse is_binary(H)) -> - [{Tag, X} || X <- N]; (N) when is_atom(N) -> {N, true}; ({_,_} = N) -> N - end, Options1), + end, Options), - Switches = lists:append([ optarg(N) || N <- lists:flatten(Options2) ]), + Switches = lists:append([ optarg(N) || N <- Options1 ]), [Cmd|Argv] = [ N || N <- string:tokens(Exec, " ") ++ [Progname|Switches], N /= ""], [find_executable(Cmd)|Argv]. optarg({verbose, Arg}) -> switch(string:copies("v", Arg)); -optarg({namespace, Arg}) -> switch("n", Arg); +optarg({maxchild, Arg}) -> switch("m", Arg); optarg(_) -> "". switch(Switch) -> @@ -352,7 +348,7 @@ switch(Switch) -> switch(Switch, Arg) when is_binary(Arg) -> switch(Switch, binary_to_list(Arg)); switch(Switch, Arg) -> - [lists:concat(["-", Switch]), Arg]. + [lists:concat(["-", Switch, " ", Arg])]. find_executable(Exe) -> case os:find_executable(Exe) of diff --git a/test/alcove_tests.erl b/test/alcove_tests.erl index 8f6eb14..63e49e5 100644 --- a/test/alcove_tests.erl +++ b/test/alcove_tests.erl @@ -51,7 +51,7 @@ run(State) -> ]. start() -> - Port = alcove_drv:start([{exec, "sudo"}]), + Port = alcove_drv:start([{exec, "sudo"}, {maxchild, 16}]), case os:type() of {unix,linux} = OS -> Flags = alcove:define(Port, clone, [