OSDN Git Service

nptl: mips needs updated clone() implementation
authorAndreas Schultz <andreas.schultz@gmail.com>
Tue, 27 Apr 2010 15:43:43 +0000 (08:43 -0700)
committerAustin Foxley <austinf@cetoncorp.com>
Tue, 27 Apr 2010 15:43:43 +0000 (08:43 -0700)
Signed-off-by: Andreas Schultz <andreas.schultz@gmail.com>
Signed-off-by: Austin Foxley <austinf@cetoncorp.com>
libc/sysdeps/linux/mips/clone.S
libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch
libpthread/nptl/sysdeps/unix/sysv/linux/mips/clone.S [new file with mode: 0644]
libpthread/nptl/sysdeps/unix/sysv/linux/mips/vfork.S [new file with mode: 0644]

index a53d5c4..7148e9d 100644 (file)
@@ -1,6 +1,6 @@
-/* Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 2000, 2003, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>, 1996.
+   Contributed by Ralf Baechle <ralf@linux-mips.org>, 1996.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    and invokes a function in the right context after its all over.  */
 
 #include <features.h>
-#include <asm/unistd.h>
-#include <sys/regdef.h>
-#define _ERRNO_H       1
-#include <bits/errno.h>
 #include <sys/asm.h>
+#include <sysdep.h>
+#define _ERRNO_H        1
+#include <bits/errno.h>
+#ifdef RESET_PID
+#include <tls.h>
+#endif
 
-/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg) */
+#define CLONE_VM      0x00000100
+#define CLONE_THREAD  0x00010000
+
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+            void *parent_tidptr, void *tls, void *child_tidptr) */
 
        .text
-.globl   clone ;
-       .align       2;
-       .type         clone,@function;
-       .ent        clone, 0;
-       
-clone:
-       .frame      sp, 4*SZREG, sp
-#ifdef __PIC__
-#if _MIPS_SIM == _MIPS_SIM_ABI32
-       .set            noreorder
-       .cpload         $25
-       .set            reorder
-       subu            sp,32
-       .cprestore      16
-#else  /* N32 */
-       PTR_SUBU        sp,32   /* fn, arg, gp, pad */
-       .cpsetup        $25, 16, clone
-#endif /* N32 */
+#if _MIPS_SIM == _ABIO32
+# define EXTRA_LOCALS 1
 #else
-       subu            sp,32
+# define EXTRA_LOCALS 0
+#endif
+LOCALSZ= 4
+FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
+GPOFF= FRAMESZ-(1*SZREG)
+NESTED(clone,4*SZREG,sp)
+#ifdef __PIC__
+       SETUP_GP
+#endif
+       PTR_SUBU sp, FRAMESZ
+       SETUP_GP64 (GPOFF, clone)
+#ifdef __PIC__
+       SAVE_GP (GPOFF)
+#endif
+#ifdef PROF
+       .set            noat
+       move            $1,ra
+       jal             _mcount
+       .set            at
 #endif
 
 
@@ -58,64 +66,78 @@ clone:
        beqz            a0,L(error)     /* No NULL function pointers.  */
        beqz            a1,L(error)     /* No NULL stack pointers.  */
 
-#if _MIPS_SIM != _MIPS_SIM_ABI32
-       and             a1,~(16-1)      /* force alignment */
-#endif
        PTR_SUBU        a1,32           /* Reserve argument save space.  */
        PTR_S           a0,0(a1)        /* Save function pointer.  */
        PTR_S           a3,PTRSIZE(a1)  /* Save argument pointer.  */
+#ifdef RESET_PID
+       LONG_S          a2,(PTRSIZE*2)(a1)      /* Save clone flags.  */
+#endif
 
+       move            a0,a2
+
+       /* Shuffle in the last three arguments - arguments 5, 6, and 7 to
+          this function, but arguments 3, 4, and 5 to the syscall.  */
+#if _MIPS_SIM == _ABIO32
+       PTR_L           a2,(FRAMESZ+PTRSIZE+PTRSIZE+16)(sp)
+       PTR_S           a2,16(sp)
+       PTR_L           a2,(FRAMESZ+16)(sp)
+       PTR_L           a3,(FRAMESZ+PTRSIZE+16)(sp)
+#else
+       move            a2,a4
+       move            a3,a5
+       move            a4,a6
+#endif
 
        /* Do the system call */
-       move            a0,a2
        li              v0,__NR_clone
        syscall
 
        bnez            a3,L(error)
-       beqz            v0,L(__thread_start)
+       beqz            v0,L(thread_start)
 
        /* Successful return from the parent */
-#if _MIPS_SIM != _MIPS_SIM_ABI32
-       .cpreturn
-#endif
-       PTR_ADDU        sp,32
+       RESTORE_GP64
+       PTR_ADDU        sp, FRAMESZ
        j $31  ; nop
 
        /* Something bad happened -- no child created */
 L(error):
-#if _MIPS_SIM != _MIPS_SIM_ABI32
-       .cpreturn
-#endif
-       PTR_ADDU        sp,32
-
-       /* uClibc change -- start */
-       move            a0,v0           /* Pass return val to C function. */
-       /* uClibc change -- stop */
-
 #ifdef __PIC__
        PTR_LA          t9,__syscall_error
+       RESTORE_GP64
+       PTR_ADDU        sp, FRAMESZ
+       /* uClibc change -- start */
+       move            a0,v0           /* Pass return val to C function. */
+       /* uClibc change -- stop */
        jr              t9
 #else
+       RESTORE_GP64
+       PTR_ADDU        sp, FRAMESZ
+       /* uClibc change -- start */
+       move            a0,v0           /* Pass return val to C function. */
+       /* uClibc change -- stop */
        j               __syscall_error
 #endif
-       .end  clone
+       END(clone)
 
 /* Load up the arguments to the function.  Put this block of code in
    its own function so that we can terminate the stack trace with our
    debug info.  */
 
-       .globl  __thread_start;
-       .align 2;
-       .ent  __thread_start, 0;
-
-__thread_start:
-L(__thread_start):
-#if _MIPS_SIM == _MIPS_SIM_ABI32
-       .frame  sp, 24, sp
+ENTRY(__thread_start)
+L(thread_start):
        /* cp is already loaded.  */
-       .cprestore      16
-#endif
+       SAVE_GP (GPOFF)
        /* The stackframe has been created on entry of clone().  */
+
+#ifdef RESET_PID
+       /* Check and see if we need to reset the PID.  */
+       LONG_L          a0,(PTRSIZE*2)(sp)
+       and             a1,a0,CLONE_THREAD
+       beqz            a1,L(restore_pid)
+L(donepid):
+#endif
+
        /* Restore the arg for user's function.  */
        PTR_L           t9,0(sp)        /* Function pointer.  */
        PTR_L           a0,PTRSIZE(sp)  /* Argument pointer.  */
@@ -126,10 +148,26 @@ L(__thread_start):
        /* Call _exit rather than doing it inline for breakpoint purposes.  */
        move            a0,v0
 #ifdef __PIC__
-        PTR_LA          t9,_exit
-        jalr            t9
+       PTR_LA          t9,_exit
+       jalr            t9
 #else
-        jal             _exit
+       jal             _exit
 #endif
-       .end  __thread_start
+
+#ifdef RESET_PID
+L(restore_pid):
+       and             a1,a0,CLONE_VM
+       li              v0,-1
+       bnez            a1,L(gotpid)
+       li              v0,__NR_getpid
+       syscall
+L(gotpid):
+       READ_THREAD_POINTER(v1)
+       INT_S           v0,PID_OFFSET(v1)
+       INT_S           v0,TID_OFFSET(v1)
+       b               L(donepid)
+#endif
+
+       END(__thread_start)
+
 weak_alias(clone, __clone)
index 8e7917b..3042cb4 100644 (file)
@@ -5,10 +5,11 @@
 # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 #
 
-libpthread_SSRC = pt-vfork.S
+libpthread_SSRC = pt-vfork.S clone.S
 libpthread_CSRC = pthread_once.c pt-__syscall_rt_sigaction.c
 
 libc_a_CSRC = fork.c
+libc_a_SSRC = clone.S vfork.S
 
 CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
 ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y)
@@ -19,6 +20,9 @@ CFLAGS-pt-__syscall_rt_sigaction.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
 
 ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1
 
+ASFLAGS-clone.S = -D_LIBC_REENTRANT
+ASFLAGS-vfork.S = -D_LIBC_REENTRANT
+
 CFLAGS += $(SSP_ALL_CFLAGS)
 #CFLAGS:=$(CFLAGS:-O1=-O2)
 
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/clone.S
new file mode 100644 (file)
index 0000000..858877f
--- /dev/null
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include <libc/sysdeps/linux/mips/clone.S>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/vfork.S
new file mode 100644 (file)
index 0000000..9d489e3
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <features.h>
+#include <tls.h>
+
+/* Save the PID value.  */
+#define SAVE_PID \
+       READ_THREAD_POINTER(v1);        /* Get the thread pointer.  */  \
+       lw      a2, PID_OFFSET(v1);     /* Load the saved PID.  */      \
+       subu    a2, $0, a2;             /* Negate it.  */               \
+       bnez    a2, 1f;                 /* If it was zero... */         \
+       lui     a2, 0x8000;             /* use 0x80000000 instead.  */  \
+1:     sw      a2, PID_OFFSET(v1);     /* Store the temporary PID.  */
+
+/* Restore the old PID value in the parent.  */
+#define RESTORE_PID \
+       beqz    v0, 1f;                 /* If we are the parent... */   \
+       READ_THREAD_POINTER(v1);        /* Get the thread pointer.  */  \
+       lw      a2, PID_OFFSET(v1);     /* Load the saved PID.  */      \
+       subu    a2, $0, a2;             /* Re-negate it.  */            \
+       lui     a0, 0x8000;             /* Load 0x80000000... */        \
+       bne     a2, a0, 2f;             /* ... compare against it... */ \
+       li      a2, 0;                  /* ... use 0 instead.  */       \
+2:     sw      a2, PID_OFFSET(v1);     /* Restore the PID.  */         \
+1:
+
+#include <../../../../../../../libc/sysdeps/linux/mips/vfork.S>