- make tests independent of the direction the stack grows

- add more sanity checks in the regression:
  1. check that we get a new pid in the child
  2. check that the stack in the child is the one we passed
  3. check invalid argument handling
  4. check running out of processes returns the right cod
     XXX: does not work on the sparc, so it is ifdef'ed out
This commit is contained in:
christos 2001-07-23 01:45:34 +00:00
parent fdda22398f
commit 3952c8bf3b

View File

@ -1,4 +1,4 @@
/* $NetBSD: clonetest.c,v 1.2 2001/07/18 19:24:02 thorpej Exp $ */
/* $NetBSD: clonetest.c,v 1.3 2001/07/23 01:45:34 christos Exp $ */
/*
* This file placed in the public domain.
@ -8,16 +8,26 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <err.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int newclone(void *);
static int newclone(void *);
static int stackdir(void *);
static void test1(void);
static void test2(void);
#ifndef __sparc__
static void test3(void);
#endif
int main(int, char *[]);
#define STACKSIZE (8 * 1024)
#define FROBVAL 41973
@ -25,62 +35,132 @@ int main(int, char *[]);
int
main(int argc, char *argv[])
{
test1();
test2();
#ifndef __sparc__
test3();
#endif
return 0;
}
static void
test1()
{
sigset_t mask;
void *stack;
__volatile int frobme = 0;
pid_t pid;
__volatile long frobme[2];
int stat;
stack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANON, -1, (off_t) 0);
if (stack == MAP_FAILED)
err(1, "mmap stack");
/*
* XXX FIX ME FOR UPWARD-GROWING STACK
*/
stack = (caddr_t) stack + STACKSIZE;
stack = (caddr_t) stack + STACKSIZE * stackdir(&stat);
printf("parent: stack = %p\n", stack);
printf("parent: stack = %p, frobme = %p\n", stack, frobme);
fflush(stdout);
frobme[0] = (long)getpid();
frobme[1] = (long)stack;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
err(1, "sigprocmask (SIGUSR1)");
pid = __clone(newclone, stack,
CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGUSR1,
(void *) &frobme);
if (pid == -1)
switch (pid = __clone(newclone, stack,
CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD,
(void *)frobme)) {
case 0:
errx(1, "clone returned 0\n");
/*NOTREACHED*/
case -1:
err(1, "clone");
while (waitpid(pid, &stat, __WCLONE) != pid)
/* spin */ ;
/*NOTREACHED*/
default:
while (waitpid(pid, &stat, 0) != pid)
continue;
}
if (WIFEXITED(stat) == 0)
errx(1, "child didn't exit\n");
printf("parent: childexit = 0x%x frobme = %d\n",
WEXITSTATUS(stat), frobme);
printf("parent: childexit = 0x%x, frobme = %ld\n",
WEXITSTATUS(stat), frobme[1]);
if (WEXITSTATUS(stat) != CHILDEXIT || frobme != FROBVAL)
if (WEXITSTATUS(stat) != CHILDEXIT || frobme[1] != FROBVAL)
exit(1);
exit(0);
}
int
static void
test2()
{
if (__clone(0, NULL,
CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD,
(void *)NULL) != -1 || errno != EINVAL)
errx(1, "clone did not return EINVAL on invalid arguments");
}
#ifndef __sparc__
/*
* XXX: does not work on the sparc, why?
*/
static void
test3()
{
struct rlimit rl;
if (getrlimit(RLIMIT_NPROC, &rl) == -1)
err(1, "getrlimit");
rl.rlim_cur = 0;
rl.rlim_max = 0;
if (setrlimit(RLIMIT_NPROC, &rl) == -1)
err(1, "setrlimit");
if (__clone(newclone, malloc(10240),
CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD,
(void *)&rl) != -1 || errno != EAGAIN)
errx(1, "clone did not return EAGAIN running out of procs");
}
#endif
static int
newclone(void *arg)
{
int *frobp = arg;
long *frobp = arg, diff;
printf("child: stack ~= %p\n", &frobp);
printf("child: stack ~= %p, frobme = %p\n", &frobp, frobp);
fflush(stdout);
*frobp = FROBVAL;
if (frobp[0] != getppid())
errx(1, "argument does not contain parent's pid\n");
if (frobp[0] == getpid())
errx(1, "called in parent's pid\n");
if (frobp[1] > (long)&frobp)
diff = frobp[1] - (long)&frobp;
else
diff = (long)&frobp - frobp[1];
if (diff > 1024)
errx(1, "called with bad stack\n");
frobp[1] = FROBVAL;
return (CHILDEXIT);
}
/*
* return 1 if the stack grows down, 0 if it grows up.
*/
static int
stackdir(void *p)
{
void *q;
return p < q ? 0 : 1;
}