1 /* $NetBSD: clonetest.c,v 1.9 2004/07/19 06:34:10 chs Exp $ */
4 * This file placed in the public domain.
5 * Jason R. Thorpe, July 16, 2001.
11 #include <sys/resource.h>
20 static int newclone(void *);
21 static int stackdir(void *);
22 static void test1(void);
23 static void test2(void);
24 static void test3(void);
26 int main(int, char *[]);
29 #define STACKSIZE (8 * 1024)
32 #define CHILDEXIT 0xa5
35 main(int argc
, char *argv
[])
47 void *allocstack
, *stack
;
49 volatile long frobme
[2];
52 allocstack
= mmap(NULL
, STACKSIZE
, PROT_READ
|PROT_WRITE
|PROT_EXEC
,
53 MAP_PRIVATE
|MAP_ANON
, -1, (off_t
) 0);
55 if (allocstack
== MAP_FAILED
)
58 stack
= (caddr_t
) allocstack
+ STACKSIZE
* stackdir(&stat
);
60 printf("parent: stack = %p, frobme = %p\n", stack
, frobme
);
63 frobme
[0] = (long)getpid();
64 frobme
[1] = (long)stack
;
67 sigaddset(&mask
, SIGUSR1
);
69 if (sigprocmask(SIG_BLOCK
, &mask
, NULL
) == -1)
70 err(1, "sigprocmask (SIGUSR1)");
72 switch (pid
= __clone(newclone
, stack
,
73 CLONE_VM
|CLONE_FS
|CLONE_FILES
|CLONE_SIGHAND
|SIGUSR1
,
76 errx(1, "clone returned 0");
82 while (waitpid(pid
, &stat
, __WCLONE
) != pid
)
86 if (WIFEXITED(stat
) == 0)
87 errx(1, "child didn't exit");
89 printf("parent: childexit = 0x%x, frobme = %ld\n",
90 WEXITSTATUS(stat
), frobme
[1]);
92 if (WEXITSTATUS(stat
) != CHILDEXIT
|| frobme
[1] != FROBVAL
)
95 if (munmap(allocstack
, STACKSIZE
) == -1)
96 err(1, "munmap stack");
98 printf("test1: PASS\n");
104 void *allocstack
, *stack
;
107 allocstack
= mmap(NULL
, STACKSIZE
, PROT_READ
|PROT_WRITE
|PROT_EXEC
,
108 MAP_PRIVATE
|MAP_ANON
, -1, (off_t
) 0);
110 if (allocstack
== MAP_FAILED
)
111 err(1, "mmap stack");
113 stack
= (caddr_t
) allocstack
+ STACKSIZE
* stackdir(&stat
);
116 rv
= __clone(0, stack
,
117 CLONE_VM
|CLONE_FS
|CLONE_FILES
|CLONE_SIGHAND
|SIGCHLD
, NULL
);
118 if (rv
!= -1 || errno
!= EINVAL
)
119 errx(1, "clone did not return EINVAL on NULL function pointer: "
120 "rv %d errno %d", rv
, errno
);
121 rv
= __clone(newclone
, NULL
,
122 CLONE_VM
|CLONE_FS
|CLONE_FILES
|CLONE_SIGHAND
|SIGCHLD
,
124 if (rv
!= -1 || errno
!= EINVAL
)
125 errx(1, "clone did not return EINVAL on NULL stack pointer: "
126 "rv %d errno %d", rv
, errno
);
128 if (munmap(allocstack
, STACKSIZE
) == -1)
129 err(1, "munmap stack");
131 printf("test2: PASS\n");
139 /* Can't enforce resource limit on root */
143 if (getrlimit(RLIMIT_NPROC
, &rl
) == -1)
147 if (setrlimit(RLIMIT_NPROC
, &rl
) == -1)
149 if (__clone(newclone
, malloc(10240),
150 CLONE_VM
|CLONE_FS
|CLONE_FILES
|CLONE_SIGHAND
|SIGCHLD
,
151 (void *)&rl
) != -1 || errno
!= EAGAIN
)
152 errx(1, "clone did not return EAGAIN running out of procs");
154 printf("test3: PASS\n");
160 long *frobp
= arg
, diff
;
162 printf("child: stack ~= %p, frobme = %p\n", &frobp
, frobp
);
165 if (frobp
[0] != getppid())
166 errx(1, "argument does not contain parent's pid");
168 if (frobp
[0] == getpid())
169 errx(1, "called in parent's pid");
171 if (frobp
[1] > (long)&frobp
)
172 diff
= frobp
[1] - (long)&frobp
;
174 diff
= (long)&frobp
- frobp
[1];
177 errx(1, "called with bad stack");
185 * return 1 if the stack grows down, 0 if it grows up.
193 return p
< q
? 0 : 1;