clone testcases in LTP
Could someone in the Linux ia64 community look at the clone system call tests that the LTP has under ltp/testcases/kernel/syscalls/clone? I know that ia64 uses clone2() instead of clone() but I don't know where the differences are documented. I would like to get these test cases, or some variation or them, compiling and running on ia64.
Thanks,
Signature · 3 lines
Nate Straz [email protected] sgi, inc http://www.sgi.com/ Linux Test Project http://ltp.sf.net/
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Nathan Straz
Nathan> Could someone in the Linux ia64 community look at the clone Nathan> system call tests that the LTP has under
Nathan> ltp/testcases/kernel/syscalls/clone? I know that ia64 uses Nathan> clone2() instead of clone() but I don't know where the Nathan> differences are documented. I would like to get these test Nathan> cases, or some variation or them, compiling and running on Nathan> ia64.
The only difference between clone() and clone2() is the explicit stack-size argument. clone2() is discussed in detail in my book, but if you're already familiar with clone(), it's easy to understand what's going on. Here is the pseudo prototype (from glibc):
/* int __clone2(int (*fn) (void *arg), void *child_stack_base, */
/* size_t child_stack_size, int flags, void *arg, */
/* pid_t *parent_tid, void *tls, pid_t *child_tid) */
--david
Quoted 8 lines · David Mosberger
The only difference between
clone()andclone2()is the explicit stack-size argument.clone2()is discussed in detail in my book, but if you're already familiar withclone(), it's easy to understand what's going on. Here is the pseudo prototype (from glibc):/* int __clone2(int (*fn) (void *arg), void
*child_stack_base, */
/*size_tchild_stack_size, int flags, void *arg, */
/*pid_t*parent_tid, void *tls,pid_t*child_tid) */
Hmm, that prototype seems to have a lot more args than the clone man page states:
#include <sched.h> int clone(int (*fn)(void *), void *child_stack, int flags, void *arg); _syscall2(int, clone, int, flags, void *, child_stack);
What are the parameters parent_tid, tls, and child_tid supposed to be?
Signature · 3 lines
Nate Straz [email protected] sgi, inc http://www.sgi.com/ Linux Test Project http://ltp.sf.net/
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line · Nathan Straz
/* int __clone2(int (*fn) (void *arg), void
*child_stack_base, */ /*size_tchild_stack_size, int flags, void *arg, */ /*pid_t*parent_tid, void *tls,pid_t*child_tid) */
Nathan> Hmm, that prototype seems to have a lot more args than the Nathan> clone man page states:
Nathan> #include <sched.h> int clone(int (*fn)(void *), void
Nathan> *child_stack, int flags, void *arg); _syscall2(int, clone, Nathan> int, flags, void *, child_stack);
Nathan> What are the parameters parent_tid, tls, and child_tid Nathan> supposed to be?
Hint 1: search google for "NPTL".
Hint 2: it's nothing ia64-specific.
Hint 3: the arguments are ignored unless you specify certain CLONE* flags,
so the interface remains backwards-compatible.
Hope this helps.
--david
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
"David" = David Mosberger <[email protected]> writes:
On Thu, 10 Jul 2003 11:18:38 -0500, Nathan Straz <[email protected]> said:
/* int __clone2(int (*fn) (void *arg), void
*child_stack_base, */ /*size_tchild_stack_size, int flags, void *arg, */ /*pid_t*parent_tid, void *tls,pid_t*child_tid) */
I'm not finding that clone2() works -- We get a segfault in the cloned process when it returns.
This is the program:
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int func(void *arg) {
fprintf(stderr, "In child\n");
return 0;
} int main(void)
{
int pagesize = sysconf(_SC_PAGESIZE);
char *stack;
int status;
pid_t kidpid; #define STACKSIZE (pagesize*8)
stack = valloc(STACKSIZE);
if ((kidpid = __clone2(func, stack, STACKSIZE, SIGCHLD, NULL,
NULL, NULL, NULL)) = -1)
perror("clone");
else {
waitpid(kidpid, &status, __WALL);
if (status)
fprintf(stderr, "child failed: status %x\n",
status);
}
return 0;
}I see:
In child
child failed: status b
where b translates to segfault.
Peter c
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Peter Chubb
Peter> I'm not finding that clone2() works -- We get a segfault in the cloned Peter> process when it returns.
Peter> __clone2(func, stack, STACKSIZE, SIGCHLD, NULL, NULL, NULL, NULL))
Umh, you're creating a new process with a different initial function. I doubt this has ever been tested. It probably should work, but I don't know of any app doing this for real (either you fork, or you create a thread).
--david
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
"David" = David Mosberger <[email protected]> writes:
On Fri, 11 Jul 2003 09:22:42 +1000, Peter Chubb <[email protected]> said:
Peter> I'm not finding that clone2() works -- We get a segfault in the Peter> cloned process when it returns.
Peter> __clone2(func, stack, STACKSIZE, SIGCHLD, NULL, NULL, NULL, Peter> NULL))
David> Umh, you're creating a new process with a different initial David> function. I doubt this has ever been tested. It probably David> should work, but I don't know of any app doing this for real David> (either you fork, or you create a thread).
The library __clone2() call should cope with this. It does, essentially,
switch(kidpid = sys_clone2(flags, stackbase, stacksize, ptidp, tlsp, tidp)) { case -1:
goto __syscall_error; case 0: exit(fn(arg)); default: return kidpid;
}
Peter C
Quoted 4 lines · David Mosberger
Nathan> Could someone in the Linux ia64 community look at the clone Nathan> system call tests that the LTP has under
The only difference betweenclone()andclone2()is the explicit stack-size argument.
And that you pass the bottom of the stack, not the top? Also, are there explicit alignment requirements? I thought it needed to be aligned to page size (or maybe it was 16 bytes). And should the stack size be at a minimum ~8K, to allow enough room for register stack?
I have noticed a problem from the LTP tests. Either I'm doing something wrong (likely related to my assumptions above) or there is something wrong. See clone2.c below. gdb doesn't catch the new thread, but if you watch with strace you see the new thread gets a SEGV somewhere in the dynamic loader on exit, and doesn't set the return value properly. The LTP tests pick this up.
This doesn't happen if thread() explicitly calls _exit(), rather than just return (which should just call _exit). This makes me think it's something to do with __clone2 in in glibc. It looks OK to me by inspection, but unfortunately I am going away for some weeks today so can't look into this much further.
Am I misunderstanding something? Should my example work?
(I attached what I did anyway. BTW the files have DOS line feeds, which seems wrong)
-i
[email protected]
http://www.gelato.unsw.edu.au
--- clone2.c ---
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sched.h>
#include <sys/wait.h>
#include <sys/types.h>
#define MB (1024*1024)
int thread(void *nothing)
{
printf("HELLO\n");
return 100;
}int main(void)
{
int ret, status;
char *child_stack_base;
child_stack_base = valloc( MB );
printf("I see the stack @ %lx\n", child_stack_base);
ret = __clone2(&thread, child_stack_base , MB, SIGCHLD);
wait(&status);
printf("Child exited (%d)\n", WEXITSTATUS(status));
exit(0);}
Only in ltp-full-20030606-newgen/testcases/kernel/syscalls/clone/: .nfs0000000000c943670000009d
testcases/kernel/syscalls/clone/clone01.c +13 -1
@@ -75,13 +75,23 @@#include "test.h" #include "usctest.h" +#if defined (__ia64__) +#define CHILD_STACK_SIZE 65536 +#else #define CHILD_STACK_SIZE 1024 +#endif #if defined (__s390__) || (__s390x__)#define clone __cloneextern int __clone (int (void *),void *,int ,void *);#endif +#if defined (__ia64__) +#define clone2 __clone2 +extern int __clone2 (int (void *),void *,size_t ,int ,void *); +#endif + +static void setup ();static void cleanup ();static int do_child ();
@@ -109,7 +119,7 @@setup ();/* Allocate stack for child */ -if ((child_stack = (void *)malloc (CHILD_STACK_SIZE )) ==NULL ) { +if ((child_stack = (void *)valloc (CHILD_STACK_SIZE )) ==NULL ) {tst_brkm (TBROK , cleanup,"Cannot allocate stack for child" ); }
@@ -124,6 +134,8 @@*/ #ifdef __hppa__TEST (clone (do_child, child_stack,SIGCHLD ,NULL )); +#elif defined (__ia64__) +TEST (clone2 (do_child, child_stack,CHILD_STACK_SIZE ,SIGCHLD ,NULL ));#else TEST (clone (do_child, child_stack +CHILD_STACK_SIZE ,SIGCHLD ,NULL ));#endif
testcases/kernel/syscalls/clone/clone02.c +14 -2
@@ -94,7 +94,12 @@#include "test.h" #include "usctest.h" +#if defined (__ia64__) +#define CHILD_STACK_SIZE 65536 +#else #define CHILD_STACK_SIZE 1024 +#endif +#define FLAG_ALL CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD#define FLAG_NONE SIGCHLD#define PARENT_VALUE 1
@@ -107,6 +112,10 @@extern int __clone (int (void *),void *,int ,void *);#endif +#if defined (__ia64__) +#define clone2 __clone2 +extern int __clone2 (int (void *),void *,size_t ,int ,void *); +#endif static void setup ();static int test_setup ();
@@ -165,7 +174,7 @@setup ();/* Allocate stack for child */ -if ((child_stack = (void *)malloc (CHILD_STACK_SIZE )) ==NULL ) { +if ((child_stack = (void *)valloc (CHILD_STACK_SIZE )) ==NULL ) {tst_brkm (TBROK , cleanup,"Cannot allocate stack for child" ); }
@@ -188,6 +197,9 @@#ifdef __hppa__TEST (clone (child_fn, child_stack, test_cases[i].flags,NULL )); +#elif (defined __ia64__) +TEST (clone2 (child_fn, child_stack, +CHILD_STACK_SIZE , test_cases[i].flags,NULL ));#else TEST (clone (child_fn, child_stack +CHILD_STACK_SIZE , test_cases[i].flags,NULL ));
@@ -217,6 +229,7 @@* parent function. If both functions returned * successfully, test passed, else failed */ +if ((WIFEXITED (status)) && (WEXITSTATUS (status)) && (test_cases[i].parent_fn ())) {tst_resm (TPASS ,"Test Passed" );
@@ -358,7 +371,6 @@/* save child pid */ child_pid =getpid (); -if (test_VM () &&test_FILES () &&test_FS () &&test_SIG ()) {return 1 ; }
testcases/kernel/syscalls/clone/clone03.c +12 -1
@@ -72,13 +72,21 @@#include "test.h" #include "usctest.h" +#if defined (__ia64__) +#define CHILD_STACK_SIZE 65536 +#else #define CHILD_STACK_SIZE 1024 +#endif #if defined (__s390__) || (__s390x__)#define clone __cloneextern int __clone (int (void *),void *,int ,void *);#endif +#if defined (__ia64__) +#define clone2 __clone2 +extern int __clone2 (int (void *),void *,size_t ,int ,void *); +#endif static void setup ();static void cleanup ();
@@ -109,7 +117,7 @@setup ();/* Allocate stack for child */ -if ((child_stack = (void *)malloc (CHILD_STACK_SIZE )) ==NULL ) { +if ((child_stack = (void *)valloc (CHILD_STACK_SIZE )) ==NULL ) {tst_brkm (TBROK , cleanup,"Cannot allocate stack for child" ); }
@@ -129,6 +137,8 @@*/ #ifdef __hppa__TEST (clone (child_fn, child_stack, (int )NULL ,NULL )); +#elif (defined __ia64__) +TEST (clone2 (child_fn, child_stack,CHILD_STACK_SIZE , (int )NULL ,NULL ));#else TEST (clone (child_fn, child_stack +CHILD_STACK_SIZE , (int )NULL ,NULL ));#endif
@@ -234,6 +244,7 @@if ((close (pfd[1 ])) ==-1 ) {tst_resm (TWARN ,"close(pfd[1]) failed" ); } +return 1 ; }
testcases/kernel/syscalls/clone/clone04.c +19 -3
@@ -73,13 +73,24 @@#include "test.h" #include "usctest.h" + +#if defined (__ia64__) +#define CHILD_STACK_SIZE 65536 +#else #define CHILD_STACK_SIZE 1024 +#endif #if defined (__s390__) || (__s390x__)#define clone __cloneextern int __clone (int (void *),void *,int ,void *);#endif + +#if defined (__ia64__) +#define clone2 __clone2 +extern int __clone2 (int (void *),void *,size_t ,int ,void *); +#endif +static void cleanup (void );static void setup (void );static int child_fn ();
@@ -117,7 +128,7 @@setup ();/* global setup */ /* Allocate stack for child */ - child_stack = (void *)malloc (CHILD_STACK_SIZE ); + child_stack = (void *)valloc (CHILD_STACK_SIZE );/* The following loop checks looping state if -i option given */
@@ -132,7 +143,7 @@ "child, skipping test case");continue ; } -#ifdef __hppa__ +#if (defined __hppa__) || (defined __ia64) test_stack = child_stack;#else test_stack = child_stack +CHILD_STACK_SIZE ;
@@ -144,8 +155,13 @@/* * call the system call with the TEST() macro */ +#ifdef __ia64__ +TEST (clone2 (test_cases[ind].child_fn, test_stack, +CHILD_STACK_SIZE , (int )NULL ,NULL )); +#else TEST (clone (test_cases[ind].child_fn, test_stack, - (int )NULL ,NULL )); +CHILD_STACK_SIZE , (int )NULL ,NULL )); +#endif if ((TEST_RETURN ==-1 ) && (TEST_ERRNO == test_cases[ind].exp_errno)) {
testcases/kernel/syscalls/clone/clone05.c +13 -1
@@ -76,8 +76,18 @@extern int __clone (int (void *),void *,int ,void *);#endif +#if defined (__ia64__) +#define clone2 __clone2 +extern int __clone2 (int (void *),void *,size_t ,int ,void *); +#endif +#if defined (__ia64__) +#define CHILD_STACK_SIZE 65536 +#else #define CHILD_STACK_SIZE 1024 +#endif + +#define MAX_LINE_LENGTH 256#define FLAG CLONE_VM | CLONE_VFORKstatic void setup ();
@@ -108,7 +118,7 @@setup ();/* Allocate stack for child */ -if ((child_stack = (void *)malloc (CHILD_STACK_SIZE )) ==NULL ) { +if ((child_stack = (void *)valloc (CHILD_STACK_SIZE )) ==NULL ) {tst_brkm (TBROK , cleanup,"Cannot allocate stack for child" ); }
@@ -123,6 +133,8 @@*/ #ifdef __hppa__TEST (clone (child_fn, child_stack,FLAG ,NULL )); +#elif (defined __ia64__) +TEST (clone2 (child_fn, child_stack,CHILD_STACK_SIZE ,FLAG ,NULL ));#else TEST (clone (child_fn, child_stack +CHILD_STACK_SIZE ,FLAG ,NULL ));#endif
testcases/kernel/syscalls/clone/clone06.c +17 -5
@@ -82,8 +82,17 @@extern int __clone (int (void *),void *,int ,void *);#endif +#if defined (__ia64__) +#define clone2 __clone2 +extern int __clone2 (int (void *),void *,size_t ,int ,void *); +#endif +#if defined (__ia64__) +#define CHILD_STACK_SIZE 65536 +#else #define CHILD_STACK_SIZE 1024 +#endif +#define MAX_LINE_LENGTH 256static void setup ();
@@ -116,7 +125,7 @@setup ();/* Allocate stack for child */ -if ((child_stack = (void *)malloc (CHILD_STACK_SIZE )) ==NULL ) { +if ((child_stack = (void *)valloc (CHILD_STACK_SIZE )) ==NULL ) {tst_brkm (TBROK , cleanup,"Cannot allocate stack for child" ); }
@@ -136,6 +145,8 @@*/ #ifdef __hppa__TEST (clone (child_environ, child_stack, (int )NULL ,NULL )); +#elif (defined __ia64__) +TEST (clone2 (child_environ, child_stack,CHILD_STACK_SIZE , (int )NULL ,NULL ));#else TEST (clone (child_environ, child_stack +CHILD_STACK_SIZE , (int )NULL ,NULL ));#endif
@@ -225,10 +236,11 @@if ((close (pfd[0 ])) ==-1 ) {tst_brkm (TBROK , cleanup,"close(pfd[0]) failed" ); } - -if ((sprintf (var,getenv ("TERM" ))) <=0 ){ -tst_resm (TWARN ,"sprintf() failed" ); + +if (getenv ("TERM" ) ==NULL ) { +tst_resm (TWARN ,"can't get TERM value" ); } +strncpy (var,getenv ("TERM" ),sizeof (getenv ("TERM" )));if ((write (pfd[1 ], var,MAX_LINE_LENGTH )) ==-1 ) {tst_resm (TWARN ,"write to pipe failed" );
@@ -238,7 +250,7 @@if ((close (pfd[1 ])) ==-1 ) {tst_resm (TWARN ,"close(pfd[1]) failed" ); } - +return 0 ; }
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Ian Wienand
Ian> And that you pass the bottom of the stack, not the top?
Yes.
Ian> Also, are there explicit alignment requirements?
Not from the kernel per se.
Ian> I thought it needed to be aligned to page size (or maybe it was Ian> 16 bytes).
It the memory stack pointer has to be 16-byte aligned and the register-backing store pointer has to be 8-byte aligned, as per architecture/software conventions.
Ian> And should the stack size be at a minimum ~8K, to allow enough Ian> room for register stack?
The kernel doesn't care about the stack size. If you can live with 4KB, fine.
Ian> I have noticed a problem from the LTP tests. Either I'm doing Ian> something wrong (likely related to my assumptions above) or there is Ian> something wrong.
It's entirely possible something is wrong (that's almost always true).
Ian> See clone2.c below.
Time to clarify my role (once again): I'm currently playing maintainer of the ia64 linux tree. That doesn't mean I fix or investigate all bugs that come along. If something is broken or not working as expected then someone who cares should investigate.
It should be trivial for anyone who cares to reproduce this with the Ski simulator. This is exactly the type of questions that can be solved very easily with a simulator.
--david
Peter Chubb <[email protected]> writes:
|> >>>>> "David" = David Mosberger <[email protected]> writes: |> |> >>>>> On Thu, 10 Jul 2003 11:18:38 -0500, Nathan Straz <[email protected]> said: |> >>> /* int __clone2(int (*fn) (void *arg), void *child_stack_base, */ |> >>> /* size_t child_stack_size, int flags, void *arg, */ /* pid_t |> >>> *parent_tid, void *tls, pid_t *child_tid) */ |> |> I'm not finding that clone2() works -- We get a segfault in the cloned |> process when it returns. |> |> This is the program: |> |> #include <stdio.h> |> #include <sys/wait.h> |> #include <unistd.h> |> #include <sys/types.h> |> #include <stdlib.h> |> |> int func(void *arg) { |> fprintf(stderr, "In child\n"); |> return 0; |> }
You can't return from the function, only exit() or _exit() works.
Andreas.
Signature · 4 lines
Andreas Schwab, SuSE Labs, [email protected] SuSE Linux AG, Deutschherrnstr. 15-19, D-90429 Nürnberg Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different."
Quoted 5 lines · Andreas Schwab
Peter Chubb <[email protected]> writes:
|> I'm not finding thatclone2()works -- We get a segfault in the cloned |> process when it returns.You can't return from the function, only
exit()or_exit()works.
That seems really odd that you can't return from the function. The clone man page (dated 2001-06-26) says either way is an option. I did test it with the explicit exit() call and that does clean up the SIGSEGV.
Signature · 3 lines
Nate Straz [email protected] sgi, inc http://www.sgi.com/ Linux Test Project http://ltp.sf.net/
Nathan Straz <[email protected]> writes:
|> On Fri, Jul 11, 2003 at 11:57:30AM +0200, Andreas Schwab wrote: |> > Peter Chubb <[email protected]> writes: |> > |> I'm not finding that clone2() works -- We get a segfault in the cloned |> > |> process when it returns. |> > |> > You can't return from the function, only exit() or _exit() works. |> |> That seems really odd that you can't return from the function.
Please forget what I wrote, I've now realized that this is supposed to work.
Andreas.
Signature · 4 lines
Andreas Schwab, SuSE Labs, [email protected] SuSE Linux AG, Deutschherrnstr. 15-19, D-90429 Nürnberg Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different."