home *** CD-ROM | disk | FTP | other *** search
/ PC World 1999 August / PCWorld_1999-08_cd.bin / doc / FAQ / html / clone.c < prev    next >
C/C++ Source or Header  |  1996-10-08  |  4KB  |  124 lines

  1. /*I'd suggest people also take a look at the (beta) pthreads library that 
  2. somebody wrote on top of clone() (the announcement is probably still in 
  3. comp.os.linux.announce if you have a reasonable news spool). That is 
  4. probably actually useful, unlike my minimal example.
  5.  
  6.         Linus
  7.  
  8. ----*/
  9. #include <signal.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <fcntl.h>
  13.  
  14. #include <linux/unistd.h>
  15.  
  16. #define STACKSIZE 16384
  17.  
  18. #define CSIGNAL         0x000000ff      /* signal mask to be sent at exit */
  19. #define CLONE_VM        0x00000100      /* set if VM shared between processes */
  20. #define CLONE_FS        0x00000200      /* set if fs info shared between processes */
  21. #define CLONE_FILES     0x00000400      /* set if open files shared between processes */
  22. #define CLONE_SIGHAND   0x00000800      /* set if signal handlers shared */
  23.  
  24. int start_thread(void (*fn)(void *), void *data)
  25. {
  26.     long retval;
  27.     void **newstack;
  28.  
  29.     /*
  30.      * allocate new stack for subthread
  31.      */
  32.     newstack = (void **) malloc(STACKSIZE);
  33.     if (!newstack)
  34.         return -1;
  35.  
  36.     /*
  37.      * Set up the stack for child function, put the (void *)
  38.      * argument on the stack.
  39.      */
  40.     newstack = (void **) (STACKSIZE + (char *) newstack);
  41.     *--newstack = data;
  42.  
  43.     /*
  44.      * Do clone() system call. We need to do the low-level stuff
  45.      * entirely in assembly as we're returning with a different
  46.      * stack in the child process and we couldn't otherwise guarantee
  47.      * that the program doesn't use the old stack incorrectly.
  48.      *
  49.      * Parameters to clone() system call:
  50.      *    %eax - __NR_clone, clone system call number
  51.      *    %ebx - clone_flags, bitmap of cloned data
  52.      *    %ecx - new stack pointer for cloned child
  53.      *
  54.      * In this example %ebx is CLONE_VM | CLONE_FS | CLONE_FILES |
  55.      * CLONE_SIGHAND which shares as much as possible between parent
  56.      * and child. (We or in the signal to be sent on child termination
  57.      * into clone_flags: SIGCHLD makes the cloned process work like
  58.      * a "normal" unix child process)
  59.      *
  60.      * The clone() system call returns (in %eax) the pid of the newly
  61.      * cloned process to the parent, and 0 to the cloned process. If
  62.      * an error occurs, the return value will be the negative errno.
  63.      *
  64.      * In the child process, we will do a "jsr" to the requested function
  65.      * and then do a "exit()" system call which will terminate the child.
  66.      */
  67.     __asm__ __volatile__(
  68.         "int $0x80\n\t"        /* Linux/i386 system call */
  69.         "testl %0,%0\n\t"    /* check return value */
  70.         "jne 1f\n\t"        /* jump if parent */
  71.         "call *%3\n\t"        /* start subthread function */
  72.         "movl %2,%0\n\t"
  73.         "int $0x80\n"        /* exit system call: exit subthread */
  74.         "1:\t"
  75.         :"=a" (retval)
  76.         :"0" (__NR_clone),"i" (__NR_exit),
  77.          "r" (fn),
  78.          "b" (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD),
  79.          "c" (newstack));
  80.  
  81.     if (retval < 0) {
  82.         errno = -retval;
  83.         retval = -1;
  84.     }
  85.     return retval;
  86. }
  87.  
  88. int show_same_vm;
  89.  
  90. void cloned_process_starts_here(void * data)
  91. {
  92.     printf("child:\t got argument %d as fd\n", (int) data);
  93.     show_same_vm = 5;
  94.     printf("child:\t vm = %d\n", show_same_vm);
  95.     close((int) data);
  96. }
  97.  
  98. int main()
  99. {
  100.     int fd, pid;
  101.  
  102.     fd = open("/dev/null", O_RDWR);
  103.     if (fd < 0) {
  104.         perror("/dev/null");
  105.         exit(1);
  106.     }
  107.     printf("mother:\t fd = %d\n", fd);
  108.  
  109.     show_same_vm = 10;
  110.     printf("mother:\t vm = %d\n", show_same_vm);
  111.  
  112.     pid = start_thread(cloned_process_starts_here, (void *) fd);
  113.     if (pid < 0) {
  114.         perror("start_thread");
  115.         exit(1);
  116.     }
  117.  
  118.     sleep(1);
  119.     printf("mother:\t vm = %d\n", show_same_vm);
  120.     if (write(fd, "c", 1) < 0)
  121.         printf("mother:\t child closed our file descriptor\n");
  122. }
  123.  
  124.