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.
This commit is contained in:
Michael Santos
2014-03-16 16:32:18 -04:00
parent c1e7a219f5
commit 059aa5c98d
5 changed files with 35 additions and 28 deletions

View File

@@ -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 <options>\n"
" -m <num> max children\n"
" -v verbose mode\n",
__progname
);

View File

@@ -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;

View File

@@ -26,6 +26,8 @@
#include <sys/types.h>
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;
}

View File

@@ -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

View File

@@ -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, [