Implement clone() C library function properly.

Only provide an implementation for ARM at the moment, since
it requires specific assembly fragments (the standard syscall
stubs cannot be used because the child returns in a different
stack).
diff --git a/libc/Android.mk b/libc/Android.mk
index c32cc30..e820b60 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -289,6 +289,7 @@
 ifeq ($(TARGET_ARCH),arm)
 libc_common_src_files += \
 	bionic/eabi.c \
+	bionic/bionic_clone.c \
 	arch-arm/bionic/__get_pc.S \
 	arch-arm/bionic/__get_sp.S \
 	arch-arm/bionic/_exit_with_stack_teardown.S \
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 684b43e..6a21b04 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -34,7 +34,12 @@
 pid_t   __fork:fork (void)           2
 pid_t   _waitpid:waitpid (pid_t, int*, int, struct rusage*)   -1,7
 int     waitid(int, pid_t, struct siginfo_t*, int,void*)          280,284
-pid_t   __clone:clone(int (*fn)(void*), void *child_stack, int flags, void *arg)  120
+
+# NOTE: this system call is never called directly, but we list it there
+#       to have __NR_clone properly defined.
+#
+pid_t   __sys_clone:clone (int, void*, int*, void*, int*) 120
+
 int     execve (const char*, char* const*, char* const*)  11
 
 int     setuid:setuid32 (uid_t)    213
diff --git a/libc/arch-arm/bionic/clone.S b/libc/arch-arm/bionic/clone.S
index 791c73d..9c25053 100644
--- a/libc/arch-arm/bionic/clone.S
+++ b/libc/arch-arm/bionic/clone.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2010 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,48 +27,102 @@
  */
 #include <sys/linux-syscalls.h>
 
-	.text
-	.type __pthread_clone, #function
-	.global __pthread_clone
-	.align 4
-    
-__pthread_clone:
-	@ insert the args onto the new stack
-	str     r0, [r1, #-4]
-	str     r3, [r1, #-8]
+    .text
+    .type __pthread_clone, #function
+    .global __pthread_clone
+    .align 4
+    .fnstart
 
-	@ do the system call
-	@ get flags
-	
+__pthread_clone:
+    @ insert the args onto the new stack
+    str     r0, [r1, #-4]
+    str     r3, [r1, #-8]
+
+    @ do the system call
+    @ get flags
+
     mov     r0, r2
-	
+
     @ new sp is already in r1
 
 #if __ARM_EABI__
     stmfd   sp!, {r4, r7}
     ldr     r7, =__NR_clone
-	swi     #0
+    swi     #0
 #else
-	swi     #__NR_clone
+    swi     #__NR_clone
 #endif
 
-	movs    r0, r0
+    movs    r0, r0
 #if __ARM_EABI__
     ldmnefd sp!, {r4, r7}
 #endif
-	blt     __error
-	bxne    lr
+    blt     __error
+    bxne    lr
 
 
-	@ pick the function arg and call address off the stack and jump
-	@ to the C __thread_entry function which does some setup and then
-	@ calls the thread's start function
+    @ pick the function arg and call address off the stack and jump
+    @ to the C __thread_entry function which does some setup and then
+    @ calls the thread's start function
 
-	ldr     r0, [sp, #-4]
-	ldr     r1, [sp, #-8]
-	mov     r2, sp			@ __thread_entry needs the TLS pointer
-	b       __thread_entry
+    ldr     r0, [sp, #-4]
+    ldr     r1, [sp, #-8]
+    mov     r2, sp			@ __thread_entry needs the TLS pointer
+    b       __thread_entry
 
 __error:
-	mov     r0, #-1
-	bx      lr
+    mov     r0, #-1
+    bx      lr
+    .fnend
+
+
+    #
+    # This function is defined as:
+    #
+    #   pid_t  __bionic_clone( int  flags, void *child_stack,
+    #                          pid_t *pid, void *tls, pid_t *ctid,
+    #                          int  (*fn)(void *), void* arg );
+    #
+    # NOTE: This is not the same signature than the GLibc
+    #       __clone function here !! Placing 'fn' and 'arg'
+    #       at the end of the parameter list makes the
+    #       implementation much simpler.
+    #
+    .type __bionic_clone, #function
+    .globl __bionic_clone
+    .align 4
+    .fnstart
+
+__bionic_clone:
+    mov     ip, sp
+    .save   {r4, r5, r6, r7}
+
+    # save registers to parent stack
+    stmfd   sp!, {r4, r5, r6, r7}
+
+    # load extra parameters
+    ldmfd   ip, {r4, r5, r6}
+
+    # store 'fn' and 'arg' to the child stack
+    str     r5, [r1, #-4]
+    str     r6, [r1, #-8]
+
+    # system call
+    ldr     r7, =__NR_clone
+    swi     #0
+    movs    r0, r0
+    beq     1f
+
+    # in parent, reload saved registers
+    # then either exit or error
+    #
+    ldmfd   sp!, {r4, r5, r6, r7}
+    bxne    lr
+    b       __set_syscall_errno
+
+1:  # in the child - pick arguments
+    ldr    r0, [sp, #-4]
+    ldr    r1, [sp, #-8]
+    b      __bionic_clone_entry
+
+    .fnend
diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk
index 706cb0c..5f416e8 100644
--- a/libc/arch-arm/syscalls.mk
+++ b/libc/arch-arm/syscalls.mk
@@ -4,7 +4,7 @@
 syscall_src += arch-arm/syscalls/_exit_thread.S
 syscall_src += arch-arm/syscalls/__fork.S
 syscall_src += arch-arm/syscalls/waitid.S
-syscall_src += arch-arm/syscalls/__clone.S
+syscall_src += arch-arm/syscalls/__sys_clone.S
 syscall_src += arch-arm/syscalls/execve.S
 syscall_src += arch-arm/syscalls/setuid.S
 syscall_src += arch-arm/syscalls/getuid.S
diff --git a/libc/arch-arm/syscalls/__clone.S b/libc/arch-arm/syscalls/__clone.S
deleted file mode 100644
index 650e2c0..0000000
--- a/libc/arch-arm/syscalls/__clone.S
+++ /dev/null
@@ -1,19 +0,0 @@
-/* autogenerated by gensyscalls.py */
-#include <sys/linux-syscalls.h>
-
-    .text
-    .type __clone, #function
-    .globl __clone
-    .align 4
-    .fnstart
-
-__clone:
-    .save   {r4, r7}
-    stmfd   sp!, {r4, r7}
-    ldr     r7, =__NR_clone
-    swi     #0
-    ldmfd   sp!, {r4, r7}
-    movs    r0, r0
-    bxpl    lr
-    b       __set_syscall_errno
-    .fnend
diff --git a/libc/arch-arm/syscalls/__sys_clone.S b/libc/arch-arm/syscalls/__sys_clone.S
new file mode 100644
index 0000000..9fe2641
--- /dev/null
+++ b/libc/arch-arm/syscalls/__sys_clone.S
@@ -0,0 +1,21 @@
+/* autogenerated by gensyscalls.py */
+#include <sys/linux-syscalls.h>
+
+    .text
+    .type __sys_clone, #function
+    .globl __sys_clone
+    .align 4
+    .fnstart
+
+__sys_clone:
+    mov     ip, sp
+    .save   {r4, r5, r6, r7}
+    stmfd   sp!, {r4, r5, r6, r7}
+    ldmfd   ip, {r4, r5, r6}
+    ldr     r7, =__NR_clone
+    swi     #0
+    ldmfd   sp!, {r4, r5, r6, r7}
+    movs    r0, r0
+    bxpl    lr
+    b       __set_syscall_errno
+    .fnend
diff --git a/libc/arch-sh/bionic/clone.S b/libc/arch-sh/bionic/clone.S
index 0bbaecb..9cb19ee 100644
--- a/libc/arch-sh/bionic/clone.S
+++ b/libc/arch-sh/bionic/clone.S
@@ -72,3 +72,8 @@
     .align 2
 0:  .long   __NR_clone
 1:  .long   __thread_entry
+
+/* XXX: TODO: Add __bionic_clone here
+ *            See bionic/bionic_clone.c and arch-arm/bionic/clone.S
+ *            for more details...
+ */
\ No newline at end of file
diff --git a/libc/arch-sh/syscalls.mk b/libc/arch-sh/syscalls.mk
index cefb2ec..d3e531e 100644
--- a/libc/arch-sh/syscalls.mk
+++ b/libc/arch-sh/syscalls.mk
@@ -5,7 +5,7 @@
 syscall_src += arch-sh/syscalls/__fork.S
 syscall_src += arch-sh/syscalls/_waitpid.S
 syscall_src += arch-sh/syscalls/waitid.S
-syscall_src += arch-sh/syscalls/__clone.S
+syscall_src += arch-sh/syscalls/__sys_clone.S
 syscall_src += arch-sh/syscalls/execve.S
 syscall_src += arch-sh/syscalls/setuid.S
 syscall_src += arch-sh/syscalls/getuid.S
diff --git a/libc/arch-sh/syscalls/__clone.S b/libc/arch-sh/syscalls/__sys_clone.S
similarity index 74%
rename from libc/arch-sh/syscalls/__clone.S
rename to libc/arch-sh/syscalls/__sys_clone.S
index 1df6ca2..c2e7dd2 100644
--- a/libc/arch-sh/syscalls/__clone.S
+++ b/libc/arch-sh/syscalls/__sys_clone.S
@@ -2,15 +2,18 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type __clone, @function
-    .globl __clone
+    .type __sys_clone, @function
+    .globl __sys_clone
     .align 4
 
-__clone:
+__sys_clone:
+
+    /* get ready for additonal arg */
+    mov.l   @r15, r0
 
     /* invoke trap */
     mov.l   0f, r3  /* trap num */
-    trapa   #(4 + 0x10)
+    trapa   #(5 + 0x10)
 
     /* check return value */
     cmp/pz  r0
diff --git a/libc/arch-x86/bionic/clone.S b/libc/arch-x86/bionic/clone.S
index 361808d..3b50cc3 100644
--- a/libc/arch-x86/bionic/clone.S
+++ b/libc/arch-x86/bionic/clone.S
@@ -48,3 +48,8 @@
         popl    %ecx
         popl    %ebx
         ret
+
+/* XXX: TODO: Add __bionic_clone here
+ *            See bionic/bionic_clone.c and arch-arm/bionic/clone.S
+ *            for more details...
+ */
\ No newline at end of file
diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk
index 86d2308..e718e18 100644
--- a/libc/arch-x86/syscalls.mk
+++ b/libc/arch-x86/syscalls.mk
@@ -5,7 +5,7 @@
 syscall_src += arch-x86/syscalls/__fork.S
 syscall_src += arch-x86/syscalls/_waitpid.S
 syscall_src += arch-x86/syscalls/waitid.S
-syscall_src += arch-x86/syscalls/__clone.S
+syscall_src += arch-x86/syscalls/__sys_clone.S
 syscall_src += arch-x86/syscalls/execve.S
 syscall_src += arch-x86/syscalls/setuid.S
 syscall_src += arch-x86/syscalls/getuid.S
diff --git a/libc/arch-x86/syscalls/__clone.S b/libc/arch-x86/syscalls/__sys_clone.S
similarity index 64%
rename from libc/arch-x86/syscalls/__clone.S
rename to libc/arch-x86/syscalls/__sys_clone.S
index 5862129..172d6af 100644
--- a/libc/arch-x86/syscalls/__clone.S
+++ b/libc/arch-x86/syscalls/__sys_clone.S
@@ -2,19 +2,21 @@
 #include <sys/linux-syscalls.h>
 
     .text
-    .type __clone, @function
-    .globl __clone
+    .type __sys_clone, @function
+    .globl __sys_clone
     .align 4
 
-__clone:
+__sys_clone:
     pushl   %ebx
     pushl   %ecx
     pushl   %edx
     pushl   %esi
-    mov     20(%esp), %ebx
-    mov     24(%esp), %ecx
-    mov     28(%esp), %edx
-    mov     32(%esp), %esi
+    pushl   %edi
+    mov     24(%esp), %ebx
+    mov     28(%esp), %ecx
+    mov     32(%esp), %edx
+    mov     36(%esp), %esi
+    mov     40(%esp), %edi
     movl    $__NR_clone, %eax
     int     $0x80
     cmpl    $-129, %eax
@@ -25,6 +27,7 @@
     addl    $4, %esp
     orl     $-1, %eax
 1:
+    popl    %edi
     popl    %esi
     popl    %edx
     popl    %ecx
diff --git a/libc/bionic/bionic_clone.c b/libc/bionic/bionic_clone.c
new file mode 100644
index 0000000..6b2fa58
--- /dev/null
+++ b/libc/bionic/bionic_clone.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#define __GNU_SOURCE 1
+#include <sched.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/* WARNING: AT THE MOMENT, THIS IS ONLY SUPPORTED ON ARM
+ */
+
+extern int  __bionic_clone(unsigned long   clone_flags,
+                           void*           newsp,
+                           int            *parent_tidptr,
+                           void           *new_tls,
+                           int            *child_tidptr,
+                           int            (*fn)(void *),
+                           void          *arg);
+
+extern void _exit_thread(int  retCode);
+
+/* this function is called from the __bionic_clone
+ * assembly fragment to call the thread function
+ * then exit. */
+extern void
+__bionic_clone_entry( int (*fn)(void *), void *arg )
+{
+    int  ret = (*fn)(arg);
+    _exit_thread(ret);
+}
+
+int
+clone(int (*fn)(void *), void *child_stack, int flags, void*  arg, ...)
+{
+    va_list  args;
+    int     *parent_tidptr = NULL;
+    void    *new_tls = NULL;
+    int     *child_tidptr = NULL;
+    int     ret;
+
+    /* extract optional parameters - they are cummulative */
+    va_start(args, arg);
+    if (flags & (CLONE_PARENT_SETTID|CLONE_SETTLS|CLONE_CHILD_SETTID)) {
+        parent_tidptr = va_arg(args, int*);
+    }
+    if (flags & (CLONE_SETTLS|CLONE_CHILD_SETTID)) {
+        new_tls = va_arg(args, void*);
+    }
+    if (flags & CLONE_CHILD_SETTID) {
+        child_tidptr = va_arg(args, int*);
+    }
+    va_end(args);
+
+    ret = __bionic_clone(flags, child_stack, parent_tidptr, new_tls, child_tidptr, fn, arg);
+    return ret;
+}
diff --git a/libc/docs/CHANGES.TXT b/libc/docs/CHANGES.TXT
index 07eac57..c2655c5 100644
--- a/libc/docs/CHANGES.TXT
+++ b/libc/docs/CHANGES.TXT
@@ -46,6 +46,7 @@
 
 - <wchar.h>: Add mbstowcs() and wcstombs()
 
+- add clone() implementation for ARM (x86 and SH-4 not working yet)
 
 -------------------------------------------------------------------------------
 Differences between Android 2.1 and 2.0.1:
diff --git a/libc/include/sched.h b/libc/include/sched.h
index 6600bae..33b9ad6 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -69,8 +69,9 @@
 #define CLONE_CHILD_SETTID   0x01000000
 #define CLONE_STOPPED        0x02000000
 
-extern int    clone(int (*fn)(void*), void *child_stack, int flags, void *arg);
-extern pid_t  __clone(int, void *);
+#ifdef __GNU_SOURCE
+extern int clone(int (*fn)(void *), void *child_stack, int flags, void*  arg, ...);
+#endif
 
 __END_DECLS
 
diff --git a/libc/include/sys/linux-unistd.h b/libc/include/sys/linux-unistd.h
index 12f7704..9a151d2 100644
--- a/libc/include/sys/linux-unistd.h
+++ b/libc/include/sys/linux-unistd.h
@@ -10,7 +10,7 @@
 pid_t            __fork (void);
 pid_t            _waitpid (pid_t, int*, int, struct rusage*);
 int              waitid (int, pid_t, struct siginfo_t*, int,void*);
-pid_t            __clone (int (*fn)(void*), void *child_stack, int flags, void *arg);
+pid_t            __sys_clone (int, void*, int*, void*, int*);
 int              execve (const char*, char* const*, char* const*);
 int              setuid (uid_t);
 uid_t            getuid (void);