/* * Copied from * * http://lkml.indiana.edu/hypermail/linux/kernel/0104.3/0322.html * * and hacked to suit clone_with_pids() (Sukadev Bhattiprolu) */ /* * Implementation of Dijkstra's parbegin/parend using clone() * Modified from original Linus' clone.c example * A proof of concept for academic purposes * (c) Francesc Oller 2001, Linus Torvalds * Under GPL license */ #include #include #include #include #include #include #include #define STACKSIZE 8192 #define __NR_clone_with_pids 335 pid_t clone_with_pids(int clone_flags, long *ptid, long *ctid, void *setp) { long retval; long *childsp; register long * motherbp __asm__ ("%ebp"); /* * allocate new stack for child */ childsp = malloc(STACKSIZE); if (!childsp) return -1; childsp = (long *)(((char *)childsp) + STACKSIZE); *--childsp = *(motherbp + 1); /* push return address */ *--childsp = *motherbp; /* push mother's bp */ /* * Do clone() system call. We need to do the low-level stuff * entirely in assembly as we're returning with a different * stack in the child process and we couldn't otherwise guarantee * that the program doesn't use the old stack incorrectly. * * Parameters to clone() system call: * %eax - __NR_clone, clone system call number * %ebx - clone_flags, bitmap of cloned data * %ecx - new stack pointer for cloned child * * In this example %ebx is CLONE_VM | CLONE_FS | CLONE_FILES | * CLONE_SIGHAND which shares as much as possible between parent * and child. (We or in the signal to be sent on child termination * into clone_flags: SIGCHLD makes the cloned process work like * a "normal" unix child process) * * The clone() system call returns (in %eax) the pid of the newly * cloned process to the mother, and 0 to the cloned process. If * an error occurs, the return value will be the negative errno. * * Prior to the creation of the child process, we have stored * return adress and caller's bp in child's stack. Child will * restore caller's bp and jmp to the post-clone adress. The * "_exit()" system call at the child's body end will terminate * the child. */ /* * The last (sixth) parameter goes into ebp but ebp is needed to * reference local variables. So push values from local variables * into registers before pushing the pid_set into ebp */ __asm__ ( "mov %0, %%ebx" : : "r" (clone_flags) ); __asm__ ( "mov %0, %%ecx" : : "r" (childsp) ); __asm__ ( "mov %0, %%edx" : : "r" (&ptid) ); __asm__ ( "mov %0, %%edi" : : "r" (&ctid) ); __asm__ ( "mov %0, %%ebp" : : "r" (setp) ); __asm__ __volatile__( "int $0x80\n\t" /* Linux/i386 system call */ "testl %0,%0\n\t" /* check return value */ "jne 1f\n\t" /* jump if mother */ "popl %%ebp\n\t" /* restore caller's bp */ "ret\n" /* jmp to return address */ "1:\t" :"=a" (retval) :"0" (__NR_clone_with_pids) : "%ebx", "%ecx", "%edx", "%edi", "%ebp" ); if (retval < 0) { errno = -retval; retval = -1; } return retval; }