From f850220be60d259b62f1f5c5d8b568c105c4ecf2 Mon Sep 17 00:00:00 2001 From: Andreas Jaeger Date: Mon, 28 Mar 2005 09:26:46 +0000 Subject: [PATCH] Update. * sysdeps/mips/atomicity.h: Remove unused file. * sysdeps/mips/dl-machine.h (elf_machine_rel): Add TLS relocations. * sysdeps/mips/dl-tls.h: New file. * sysdeps/mips/libc-tls.c: New file. * sysdeps/mips/tls-macros.h: New file. * sysdeps/mips/bits/atomic.h: New file. * sysdeps/mips/bits/setjmp.h: Protect against multiple inclusion. * sysdeps/mips/elf/configure.in: New file. * sysdeps/mips/elf/configure: Generated. * sysdeps/mips/sys/asm.h: New file. * sysdeps/unix/sysv/linux/mips/vfork.S: New file. * sysdeps/unix/sysv/linux/mips/clone.S: Add NPTL and five-argument clone support. * sysdeps/unix/sysv/linux/mips/mips32/sysdep.h (INTERNAL_SYSCALL_NCS): New. (INTERNAL_SYSCALL): Update for non-constant support. (internal_syscall0): Likewise. (internal_syscall1): Likewise. (internal_syscall2): Likewise. (internal_syscall3): Likewise. (internal_syscall4): Likewise. (internal_syscall5): Likewise. (internal_syscall6): Likewise. (internal_syscall7): Likewise. * sysdeps/unix/sysv/linux/mips/bits/siginfo.h (SIGEV_THREAD): Update to match the kernel. (SIGEV_CALLBACK): Likewise. (SIGEV_THREAD_ID): Likewise. 2005-03-28 Daniel Jacobowitz --- ChangeLog | 31 ++ linuxthreads/ChangeLog | 5 + linuxthreads/sysdeps/mips/tls.h | 170 ++++++++++ .../sysdeps/unix/sysv/linux/mips/vfork.S | 104 ++++++ nptl/ChangeLog | 21 ++ nptl/sysdeps/mips/Makefile | 25 ++ nptl/sysdeps/mips/jmpbuf-unwind.h | 30 ++ nptl/sysdeps/mips/nptl-sysdep.S | 2 + nptl/sysdeps/mips/pthread_spin_lock.S | 37 +++ nptl/sysdeps/mips/pthread_spin_trylock.S | 41 +++ nptl/sysdeps/mips/pthreaddef.h | 39 +++ nptl/sysdeps/mips/tcb-offsets.sym | 11 + nptl/sysdeps/mips/tls.h | 161 ++++++++++ .../unix/sysv/linux/mips/bits/semaphore.h | 40 +++ nptl/sysdeps/unix/sysv/linux/mips/clone.S | 2 + .../unix/sysv/linux/mips/createthread.c | 24 ++ nptl/sysdeps/unix/sysv/linux/mips/fork.c | 1 + .../unix/sysv/linux/mips/lowlevellock.h | 216 +++++++++++++ nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S | 37 +++ .../unix/sysv/linux/mips/pthread_once.c | 94 ++++++ .../unix/sysv/linux/mips/sysdep-cancel.h | 170 ++++++++++ nptl/sysdeps/unix/sysv/linux/mips/vfork.S | 42 +++ sysdeps/mips/atomicity.h | 113 ------- sysdeps/mips/bits/atomic.h | 303 ++++++++++++++++++ sysdeps/mips/dl-tls.h | 46 +++ sysdeps/mips/dl-trampoline.c | 2 +- sysdeps/mips/elf/configure | 46 +++ sysdeps/mips/elf/configure.in | 35 ++ sysdeps/mips/libc-tls.c | 37 +++ sysdeps/mips/sys/asm.h | 19 +- sysdeps/mips/tls-macros.h | 88 +++++ sysdeps/unix/sysv/linux/mips/bits/siginfo.h | 9 +- sysdeps/unix/sysv/linux/mips/clone.S | 60 +++- sysdeps/unix/sysv/linux/mips/mips32/sysdep.h | 285 ++++++++-------- sysdeps/unix/sysv/linux/mips/vfork.S | 98 ++++++ 35 files changed, 2186 insertions(+), 258 deletions(-) create mode 100644 linuxthreads/sysdeps/mips/tls.h create mode 100644 linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S create mode 100644 nptl/sysdeps/mips/Makefile create mode 100644 nptl/sysdeps/mips/jmpbuf-unwind.h create mode 100644 nptl/sysdeps/mips/nptl-sysdep.S create mode 100644 nptl/sysdeps/mips/pthread_spin_lock.S create mode 100644 nptl/sysdeps/mips/pthread_spin_trylock.S create mode 100644 nptl/sysdeps/mips/pthreaddef.h create mode 100644 nptl/sysdeps/mips/tcb-offsets.sym create mode 100644 nptl/sysdeps/mips/tls.h create mode 100644 nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h create mode 100644 nptl/sysdeps/unix/sysv/linux/mips/clone.S create mode 100644 nptl/sysdeps/unix/sysv/linux/mips/createthread.c create mode 100644 nptl/sysdeps/unix/sysv/linux/mips/fork.c create mode 100644 nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h create mode 100644 nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S create mode 100644 nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c create mode 100644 nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h create mode 100644 nptl/sysdeps/unix/sysv/linux/mips/vfork.S delete mode 100644 sysdeps/mips/atomicity.h create mode 100644 sysdeps/mips/bits/atomic.h create mode 100644 sysdeps/mips/dl-tls.h create mode 100644 sysdeps/mips/elf/configure create mode 100644 sysdeps/mips/elf/configure.in create mode 100644 sysdeps/mips/libc-tls.c create mode 100644 sysdeps/mips/tls-macros.h create mode 100644 sysdeps/unix/sysv/linux/mips/vfork.S diff --git a/ChangeLog b/ChangeLog index 48d7deab70..966cb8245c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2005-03-28 Daniel Jacobowitz + + * sysdeps/mips/atomicity.h: Remove unused file. + * sysdeps/mips/dl-machine.h (elf_machine_rel): Add TLS relocations. + * sysdeps/mips/dl-tls.h: New file. + * sysdeps/mips/libc-tls.c: New file. + * sysdeps/mips/tls-macros.h: New file. + * sysdeps/mips/bits/atomic.h: New file. + * sysdeps/mips/bits/setjmp.h: Protect against multiple inclusion. + * sysdeps/mips/elf/configure.in: New file. + * sysdeps/mips/elf/configure: Generated. + * sysdeps/mips/sys/asm.h: New file. + * sysdeps/unix/sysv/linux/mips/vfork.S: New file. + * sysdeps/unix/sysv/linux/mips/clone.S: Add NPTL and five-argument + clone support. + * sysdeps/unix/sysv/linux/mips/mips32/sysdep.h + (INTERNAL_SYSCALL_NCS): New. + (INTERNAL_SYSCALL): Update for non-constant support. + (internal_syscall0): Likewise. + (internal_syscall1): Likewise. + (internal_syscall2): Likewise. + (internal_syscall3): Likewise. + (internal_syscall4): Likewise. + (internal_syscall5): Likewise. + (internal_syscall6): Likewise. + (internal_syscall7): Likewise. + * sysdeps/unix/sysv/linux/mips/bits/siginfo.h (SIGEV_THREAD): + Update to match the kernel. + (SIGEV_CALLBACK): Likewise. + (SIGEV_THREAD_ID): Likewise. + 2005-03-28 Daniel Jacobowitz [BZ #783] diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog index bf842818d7..dfecefc9ac 100644 --- a/linuxthreads/ChangeLog +++ b/linuxthreads/ChangeLog @@ -1,3 +1,8 @@ +2005-03-28 Daniel Jacobowitz + + * sysdeps/mips/tls.h: New file. + * sysdeps/unix/sysv/linux/mips/vfork.S: New file. + 2005-03-21 GOTO Masanori * linuxthreads/sysdeps/m68k/Makefile: Remove to delete diff --git a/linuxthreads/sysdeps/mips/tls.h b/linuxthreads/sysdeps/mips/tls.h new file mode 100644 index 0000000000..be4478db43 --- /dev/null +++ b/linuxthreads/sysdeps/mips/tls.h @@ -0,0 +1,170 @@ +/* Definitions for thread-local data handling. linuxthreads/MIPS version. + Copyright (C) 2005 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. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ + +# include +# include +# include + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +# define READ_THREAD_POINTER() \ + ({ void *__result; \ + asm volatile (".set\tpush\n\t.set\tmips32r2\n\t" \ + "rdhwr\t%0, $29\n\t.set\tpop" : "=v" (__result)); \ + __result; }) + +#else /* __ASSEMBLER__ */ +# include + +/* Note: rd must be $v1 to be ABI-conformant. */ +# define READ_THREAD_POINTER(rd) \ + .set push; \ + .set mips32r2; \ + rdhwr rd, $29; \ + .set pop +#endif /* __ASSEMBLER__ */ + +/* LinuxThreads can only use TLS if both floating stacks (in the MIPS case, + that means support for "rdhwr") and support from the tools are available. + + We have to define USE_TLS consistently, or ldsodefs.h will lay out types + differently between an NPTL build and a LinuxThreads build. It can be set + for libc.so and not libpthread.so, but only if we provide appropriate padding + in the _pthread_descr_struct. + + Currently nothing defines FLOATING_STACKS. We could assume this based on + kernel version once the TLS patches are available in kernel.org, but + it hardly seems worth it. Use NPTL if you can. + + To avoid bothering with the TLS support code at all, use configure + --without-tls. */ + +#if defined HAVE_TLS_SUPPORT \ + && (defined FLOATING_STACKS || !defined IS_IN_libpthread) + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +/* Include padding in _pthread_descr_struct so that libc can find p_errno, + if libpthread will only include the padding because of the !IS_IN_libpthread + check. */ +#ifndef FLOATING_STACKS +# define INCLUDE_TLS_PADDING 1 +#endif + +# ifndef __ASSEMBLER__ + +/* This layout is actually wholly private and not affected by the ABI. + Nor does it overlap the pthread data structure, so we need nothing + extra here at all. */ +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE 0 + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE 0 + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE \ + (sizeof (struct _pthread_descr_struct) \ + + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) + +/* The thread pointer (in hardware register $29) points to the end of + the TCB + 0x7000, as for PowerPC. The pthread_descr structure is + immediately in front of the TCB. */ +#define TLS_TCB_OFFSET 0x7000 + +/* The DTV is allocated at the TP; the TCB is placed elsewhere. */ +/* This is not really true for powerpc64. We are following alpha + where the DTV pointer is first doubleword in the TCB. */ +# define TLS_DTV_AT_TP 1 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(TCBP, DTVP) \ + (((tcbhead_t *) (TCBP))[-1].dtv = (DTVP) + 1) + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(DTV) (THREAD_DTV() = (DTV)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(TCBP) (((tcbhead_t *) (TCBP))[-1].dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + ({ INTERNAL_SYSCALL_DECL (err); \ + long result_var; \ + result_var = INTERNAL_SYSCALL (set_thread_area, err, 1, \ + (char *) (tcbp) + TLS_TCB_OFFSET); \ + INTERNAL_SYSCALL_ERROR_P (result_var, err) \ + ? "unknown error" : NULL; }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv) + +/* Return the thread descriptor for the current thread. */ +# undef THREAD_SELF +# define THREAD_SELF \ + ((pthread_descr) (READ_THREAD_POINTER () \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) + +/* Get the thread descriptor definition. */ +# include + +/* l_tls_offset == 0 is perfectly valid on MIPS, so we have to use some + different value to mean unset l_tls_offset. */ +# define NO_TLS_OFFSET -1 + +/* Initializing the thread pointer requires a syscall which may not be + available, so don't do it if we don't need to. */ +# define TLS_INIT_TP_EXPENSIVE 1 + +# endif /* __ASSEMBLER__ */ + +#endif /* HAVE_TLS_SUPPORT */ + +#endif /* tls.h */ diff --git a/linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S new file mode 100644 index 0000000000..bf541439b5 --- /dev/null +++ b/linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S @@ -0,0 +1,104 @@ +/* Copyright (C) 2005 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. */ + +/* vfork() is just a special case of clone(). */ + +#include +#include +#include + +/* int vfork() */ + + .text +LOCALSZ= 1 +FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK +GPOFF= FRAMESZ-(1*SZREG) +NESTED(__vfork,FRAMESZ,sp) +#ifdef __PIC__ + SETUP_GP +#endif + PTR_SUBU sp, FRAMESZ + SETUP_GP64 (a5, __vfork) +#ifdef __PIC__ + SAVE_GP (GPOFF) +#endif +#ifdef PROF +# if (_MIPS_SIM != _ABIO32) + PTR_S a5, GPOFF(sp) +# endif + .set noat + move $1, ra +# if (_MIPS_SIM == _ABIO32) + subu sp,sp,8 +# endif + jal _mcount + .set at +# if (_MIPS_SIM != _ABIO32) + PTR_L a5, GPOFF(sp) +# endif +#endif + + /* If libpthread is loaded, we need to call fork instead. */ +#ifdef SHARED + PTR_L a0, __libc_pthread_functions +#else + .weak pthread_create + PTR_LA a0, pthread_create +#endif + + PTR_ADDU sp, FRAMESZ + + bnez a0, L(call_fork) + + li a0, 0x4112 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ + move a1, sp + + /* Do the system call */ + li v0,__NR_clone + syscall + + bnez a3,L(error) + + /* Successful return from the parent or child. */ + RESTORE_GP64 + ret + + /* Something bad happened -- no child created. */ +L(error): +#ifdef __PIC__ + PTR_LA t9, __syscall_error + RESTORE_GP64 + jr t9 +#else + RESTORE_GP64 + j __syscall_error +#endif + +L(call_fork): +#ifdef __PIC__ + PTR_LA t9, fork + RESTORE_GP64 + jr t9 +#else + RESTORE_GP64 + j fork +#endif + END(__vfork) + +libc_hidden_def(__vfork) +weak_alias(__vfork, vfork) diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 23b0f51a0f..82895d4785 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,24 @@ +2005-03-28 Daniel Jacobowitz + + * sysdeps/mips/Makefile: New file. + * sysdeps/mips/nptl-sysdep.S: New file. + * sysdeps/mips/tcb-offsets.sym: New file. + * sysdeps/mips/pthread_spin_lock.S: New file. + * sysdeps/mips/pthread_spin_trylock.S: New file. + * sysdeps/mips/pthreaddef.h: New file. + * sysdeps/mips/tls.h: New file. + * sysdeps/mips/jmpbuf-unwind.h: New file. + * sysdeps/unix/sysv/linux/mips/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/mips/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/mips/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/mips/fork.c: New file. + * sysdeps/unix/sysv/linux/mips/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/mips/vfork.S: New file. + * sysdeps/unix/sysv/linux/mips/clone.S: New file. + * sysdeps/unix/sysv/linux/mips/createthread.c: New file. + * sysdeps/unix/sysv/linux/mips/sysdep-cancel.h: New file. + 2005-03-23 Ulrich Drepper * pthread_create.c (__pthread_create_2_1): Rename syscall error diff --git a/nptl/sysdeps/mips/Makefile b/nptl/sysdeps/mips/Makefile new file mode 100644 index 0000000000..d0c59a5091 --- /dev/null +++ b/nptl/sysdeps/mips/Makefile @@ -0,0 +1,25 @@ +# Copyright (C) 2005 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. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif + +ifeq ($(subdir),nptl) +libpthread-sysdep_routines += nptl-sysdep +endif diff --git a/nptl/sysdeps/mips/jmpbuf-unwind.h b/nptl/sysdeps/mips/jmpbuf-unwind.h new file mode 100644 index 0000000000..67cc969663 --- /dev/null +++ b/nptl/sysdeps/mips/jmpbuf-unwind.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2003, 2005 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 +#include +#include + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[0].__sp - (_adj)) + +/* We use the normal longjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/nptl/sysdeps/mips/nptl-sysdep.S b/nptl/sysdeps/mips/nptl-sysdep.S new file mode 100644 index 0000000000..3f5c2a364a --- /dev/null +++ b/nptl/sysdeps/mips/nptl-sysdep.S @@ -0,0 +1,2 @@ +/* Pull in __syscall_error. */ +#include diff --git a/nptl/sysdeps/mips/pthread_spin_lock.S b/nptl/sysdeps/mips/pthread_spin_lock.S new file mode 100644 index 0000000000..d5f2a72340 --- /dev/null +++ b/nptl/sysdeps/mips/pthread_spin_lock.S @@ -0,0 +1,37 @@ +/* Copyright (C) 2005 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 +#include +#include + +ENTRY (pthread_spin_lock) + .set push +#if _MIPS_SIM == _ABIO32 + .set mips2 +#endif +1: ll a2, 0(a0) + li a1, 1 + bnez a2, 1b + sc a1, 0(a0) + beqz a1, 1b + MIPS_SYNC + .set pop + li v0, 0 + ret +PSEUDO_END (pthread_spin_lock) diff --git a/nptl/sysdeps/mips/pthread_spin_trylock.S b/nptl/sysdeps/mips/pthread_spin_trylock.S new file mode 100644 index 0000000000..9c6e740f0f --- /dev/null +++ b/nptl/sysdeps/mips/pthread_spin_trylock.S @@ -0,0 +1,41 @@ +/* Copyright (C) 2005 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 +#include +#define _ERRNO_H 1 +#include +#include + +ENTRY (pthread_spin_trylock) + .set push +#if _MIPS_SIM == _ABIO32 + .set mips2 +#endif + ll a2, 0(a0) + li a1, 1 + bnez a2, 1f + sc a1, 0(a0) + beqz a1, 1f + MIPS_SYNC + .set pop + li v0, 0 + ret +1: li v0, EBUSY + ret +PSEUDO_END (pthread_spin_trylock) diff --git a/nptl/sysdeps/mips/pthreaddef.h b/nptl/sysdeps/mips/pthreaddef.h new file mode 100644 index 0000000000..e72b4bc58d --- /dev/null +++ b/nptl/sysdeps/mips/pthreaddef.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002, 2003, 2005 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. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ + +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/nptl/sysdeps/mips/tcb-offsets.sym b/nptl/sysdeps/mips/tcb-offsets.sym new file mode 100644 index 0000000000..e0e71dc430 --- /dev/null +++ b/nptl/sysdeps/mips/tcb-offsets.sym @@ -0,0 +1,11 @@ +#include +#include + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +#define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + +MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +PID_OFFSET thread_offsetof (pid) +TID_OFFSET thread_offsetof (tid) diff --git a/nptl/sysdeps/mips/tls.h b/nptl/sysdeps/mips/tls.h new file mode 100644 index 0000000000..1cef161010 --- /dev/null +++ b/nptl/sysdeps/mips/tls.h @@ -0,0 +1,161 @@ +/* Definition for thread-local data handling. NPTL/MIPS version. + Copyright (C) 2005 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. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#include + +#ifndef __ASSEMBLER__ +# include +# include +# include + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +/* Note: rd must be $v1 to be ABI-conformant. */ +# define READ_THREAD_POINTER() \ + ({ void *__result; \ + asm volatile (".set\tpush\n\t.set\tmips32r2\n\t" \ + "rdhwr\t%0, $29\n\t.set\tpop" : "=v" (__result)); \ + __result; }) + +#else /* __ASSEMBLER__ */ +# include + +# define READ_THREAD_POINTER(rd) \ + .set push; \ + .set mips32r2; \ + rdhwr rd, $29; \ + .set pop +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#ifndef HAVE_TLS_SUPPORT +# error "TLS support is required." +#endif + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include + +/* The TP points to the start of the thread blocks. */ +# define TLS_DTV_AT_TP 1 + +/* Get the thread descriptor definition. */ +# include + +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +/* This is the size of the initial TCB. Because our TCB is before the thread + pointer, we don't need this. */ +# define TLS_INIT_TCB_SIZE 0 + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. Because our TCB is before the thread + pointer, we don't need this. */ +# define TLS_TCB_SIZE 0 + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size we need before TCB - actually, it includes the TCB. */ +# define TLS_PRE_TCB_SIZE \ + (sizeof (struct pthread) \ + + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) + +/* The thread pointer (in hardware register $29) points to the end of + the TCB + 0x7000, as for PowerPC. The pthread_descr structure is + immediately in front of the TCB. */ +# define TLS_TCB_OFFSET 0x7000 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1) + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))[-1].dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + ({ INTERNAL_SYSCALL_DECL (err); \ + long result_var; \ + result_var = INTERNAL_SYSCALL (set_thread_area, err, 1, \ + (char *) (tcbp) + TLS_TCB_OFFSET); \ + INTERNAL_SYSCALL_ERROR_P (result_var, err) \ + ? "unknown error" : NULL; }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv) + +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF \ + ((struct pthread *) (READ_THREAD_POINTER () \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Access to data in the thread descriptor is easy. */ +# define THREAD_GETMEM(descr, member) \ + descr->member +# define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] +# define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +/* l_tls_offset == 0 is perfectly valid on MIPS, so we have to use some + different value to mean unset l_tls_offset. */ +# define NO_TLS_OFFSET -1 + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h b/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h new file mode 100644 index 0000000000..c4440f9e9e --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2002, 2005 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. */ + +#ifndef _SEMAPHORE_H +# error "Never use directly; include instead." +#endif + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_SEM_T 32 +#else +# define __SIZEOF_SEM_T 16 +#endif + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/nptl/sysdeps/unix/sysv/linux/mips/clone.S b/nptl/sysdeps/unix/sysv/linux/mips/clone.S new file mode 100644 index 0000000000..80c265bf6c --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/mips/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include diff --git a/nptl/sysdeps/unix/sysv/linux/mips/createthread.c b/nptl/sysdeps/unix/sysv/linux/mips/createthread.c new file mode 100644 index 0000000000..5b2234f470 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/mips/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2005 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. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE ((void *) (pd) \ + + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Get the real implementation. */ +#include diff --git a/nptl/sysdeps/unix/sysv/linux/mips/fork.c b/nptl/sysdeps/unix/sysv/linux/mips/fork.c new file mode 100644 index 0000000000..06b7e1c69f --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/mips/fork.c @@ -0,0 +1 @@ +#include "../i386/fork.c" diff --git a/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h new file mode 100644 index 0000000000..7edb28794f --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h @@ -0,0 +1,216 @@ +/* Copyright (C) 2003, 2004, 2005 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. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include +#include +#include +#include +#include + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), (timespec)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAKE, (nr), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ + (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock(int *futex) +{ + return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_mutex_trylock(lock) __lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock(int *futex) +{ + return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_mutex_cond_trylock(lock) __lll_mutex_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock(int *futex) +{ + if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) + __lll_lock_wait (futex); +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ + if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0) + __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) + attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) + result = __lll_timedlock_wait (futex, abstime); + return result; +} +#define lll_mutex_timedlock(futex, abstime) \ + __lll_mutex_timedlock (&(futex), abstime) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ + (void) atomic_exchange_rel (futex, 0); + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible + mutex implementation. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + >1 - taken by more users */ + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + attribute_hidden; + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S b/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S new file mode 100644 index 0000000000..fe2b81bc1f --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S @@ -0,0 +1,37 @@ +/* Copyright (C) 2005 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 + +/* 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. */ \ + 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. */ \ + sw a2, PID_OFFSET(v1); /* Restore the PID. */ \ +1: + +#include <../sysdeps/unix/sysv/linux/mips/vfork.S> diff --git a/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c b/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c new file mode 100644 index 0000000000..649b752f54 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2003. + + 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 "pthreadP.h" +#include + + +unsigned long int __fork_generation attribute_hidden; + + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + + +int +__pthread_once (once_control, init_routine) + pthread_once_t *once_control; + void (*init_routine) (void); +{ + while (1) + { + int oldval, val, newval; + + val = *once_control; + do + { + /* Check if the initialized has already been done. */ + if ((val & 2) != 0) + return 0; + + oldval = val; + newval = (oldval & 3) | __fork_generation | 1; + val = atomic_compare_and_exchange_val_acq (once_control, newval, + oldval); + } + while (__builtin_expect (val != oldval, 0)); + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) != 0) + { + /* Check whether the initializer execution was interrupted + by a fork. */ + if (((oldval ^ newval) & -4) == 0) + { + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, newval); + continue; + } + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + + /* Add one to *once_control. */ + atomic_increment (once_control); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + break; + } + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h b/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h new file mode 100644 index 0000000000..02508e2155 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h @@ -0,0 +1,170 @@ +/* Copyright (C) 2003, 2004, 2005 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 +#include +#include +#ifndef __ASSEMBLER__ +# include +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +#ifdef __PIC__ +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .align 2; \ + L(pseudo_start): \ + cfi_startproc; \ + 99: la t9,__syscall_error; \ + jr t9; \ + .type __##syscall_name##_nocancel, @function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + .set noreorder; \ + .cpload t9; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + ret; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + ENTRY (name) \ + .set noreorder; \ + .cpload t9; \ + .set reorder; \ + SINGLE_THREAD_P(v1); \ + bne zero, v1, L(pseudo_cancel); \ + .set noreorder; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + ret; \ + L(pseudo_cancel): \ + SAVESTK_##args; \ + sw ra, 28(sp); \ + cfi_rel_offset (ra, 28); \ + sw gp, 32(sp); \ + cfi_rel_offset (gp, 32); \ + PUSHARGS_##args; /* save syscall args */ \ + CENABLE; \ + lw gp, 32(sp); \ + sw v0, 44(sp); /* save mask */ \ + POPARGS_##args; /* restore syscall args */ \ + .set noreorder; \ + li v0, SYS_ify (syscall_name); \ + syscall; \ + .set reorder; \ + sw v0, 36(sp); /* save syscall result */ \ + sw a3, 40(sp); /* save syscall error flag */ \ + lw a0, 44(sp); /* pass mask as arg1 */ \ + CDISABLE; \ + lw gp, 32(sp); \ + lw v0, 36(sp); /* restore syscall result */ \ + lw a3, 40(sp); /* restore syscall error flag */ \ + lw ra, 28(sp); /* restore return address */ \ + .set noreorder; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + RESTORESTK; \ + L(pseudo_end): \ + .set reorder; + +# undef PSEUDO_END +# define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym + +#endif + +# define PUSHARGS_0 /* nothing to do */ +# define PUSHARGS_1 PUSHARGS_0 sw a0, 0(sp); cfi_rel_offset (a0, 0); +# define PUSHARGS_2 PUSHARGS_1 sw a1, 4(sp); cfi_rel_offset (a1, 4); +# define PUSHARGS_3 PUSHARGS_2 sw a2, 8(sp); cfi_rel_offset (a2, 8); +# define PUSHARGS_4 PUSHARGS_3 sw a3, 12(sp); cfi_rel_offset (a3, 12); +# define PUSHARGS_5 PUSHARGS_4 /* handled by SAVESTK_## */ +# define PUSHARGS_6 PUSHARGS_5 +# define PUSHARGS_7 PUSHARGS_6 + +# define POPARGS_0 /* nothing to do */ +# define POPARGS_1 POPARGS_0 lw a0, 0(sp); +# define POPARGS_2 POPARGS_1 lw a1, 4(sp); +# define POPARGS_3 POPARGS_2 lw a2, 8(sp); +# define POPARGS_4 POPARGS_3 lw a3, 12(sp); +# define POPARGS_5 POPARGS_4 /* args already in new stackframe */ +# define POPARGS_6 POPARGS_5 +# define POPARGS_7 POPARGS_6 + + +# define STKSPACE 48 +# define SAVESTK_0 subu sp, STKSPACE; cfi_adjust_cfa_offset(STKSPACE) +# define SAVESTK_1 SAVESTK_0 +# define SAVESTK_2 SAVESTK_1 +# define SAVESTK_3 SAVESTK_2 +# define SAVESTK_4 SAVESTK_3 +# define SAVESTK_5 lw t0, 16(sp); \ + SAVESTK_0; \ + sw t0, 16(sp) + +# define SAVESTK_6 lw t0, 16(sp); \ + lw t1, 20(sp); \ + SAVESTK_0; \ + sw t0, 16(sp); \ + sw t1, 20(sp) + +# define SAVESTK_7 lw t0, 16(sp); \ + lw t1, 20(sp); \ + lw t2, 24(sp); \ + SAVESTK_0; \ + sw t0, 16(sp); \ + sw t1, 20(sp); \ + sw t2, 24(sp) + +# define RESTORESTK addu sp, STKSPACE; cfi_adjust_cfa_offset(-STKSPACE) + + +/* We use jalr rather than jal. This means that the assembler will not + automatically restore $gp (in case libc has multiple GOTs) so we must + do it manually - which we have to do anyway since we don't use .cprestore. + It also shuts up the assembler warning about not using .cprestore. */ +# ifdef IS_IN_libpthread +# define CENABLE la t9, __pthread_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __pthread_disable_asynccancel; jalr t9; +# elif defined IS_IN_librt +# define CENABLE la t9, __librt_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __librt_disable_asynccancel; jalr t9; +# else +# define CENABLE la t9, __libc_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __libc_disable_asynccancel; jalr t9; +# endif + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) \ + == 0, 1) +# else +# define SINGLE_THREAD_P(reg) \ + READ_THREAD_POINTER(reg); \ + lw reg, MULTIPLE_THREADS_OFFSET(reg) +#endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P 1 +# define NO_CANCELLATION 1 + +#endif diff --git a/nptl/sysdeps/unix/sysv/linux/mips/vfork.S b/nptl/sysdeps/unix/sysv/linux/mips/vfork.S new file mode 100644 index 0000000000..874a2e2bf4 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/mips/vfork.S @@ -0,0 +1,42 @@ +/* Copyright (C) 2005 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 + +/* 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 <../sysdeps/unix/sysv/linux/mips/vfork.S> diff --git a/sysdeps/mips/atomicity.h b/sysdeps/mips/atomicity.h deleted file mode 100644 index 7380e1000c..0000000000 --- a/sysdeps/mips/atomicity.h +++ /dev/null @@ -1,113 +0,0 @@ -/* Low-level functions for atomic operations. Mips version. - Copyright (C) 2001, 2002, 2003, 2004 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. */ - -#ifndef _MIPS_ATOMICITY_H -#define _MIPS_ATOMICITY_H 1 - -#include -#include - -static inline int -__attribute__ ((unused)) -exchange_and_add (volatile uint32_t *mem, int val) -{ - int result, tmp; - - __asm__ __volatile__ - ("/* Inline exchange & add */\n" - "1:\n\t" - ".set push\n\t" -#if _MIPS_SIM == _ABIO32 - ".set mips2\n\t" -#endif - "ll %0,%3\n\t" - "addu %1,%4,%0\n\t" - "sc %1,%2\n\t" - ".set pop\n\t" - "beqz %1,1b\n\t" - "/* End exchange & add */" - : "=&r"(result), "=&r"(tmp), "=m"(*mem) - : "m" (*mem), "r"(val) - : "memory"); - - return result; -} - -static inline void -__attribute__ ((unused)) -atomic_add (volatile uint32_t *mem, int val) -{ - int result; - - __asm__ __volatile__ - ("/* Inline atomic add */\n" - "1:\n\t" - ".set push\n\t" -#if _MIPS_SIM == _ABIO32 - ".set mips2\n\t" -#endif - "ll %0,%2\n\t" - "addu %0,%3,%0\n\t" - "sc %0,%1\n\t" - ".set pop\n\t" - "beqz %0,1b\n\t" - "/* End atomic add */" - : "=&r"(result), "=m"(*mem) - : "m" (*mem), "r"(val) - : "memory"); -} - -static inline int -__attribute__ ((unused)) -compare_and_swap (volatile long int *p, long int oldval, long int newval) -{ - long int ret, temp; - - __asm__ __volatile__ - ("/* Inline compare & swap */\n" - "1:\n\t" - ".set push\n\t" -#if _MIPS_SIM == _ABIO32 - ".set mips2\n\t" -#endif -#if _MIPS_SIM == _ABI64 - "lld %1,%5\n\t" -#else - "ll %1,%5\n\t" -#endif - "move %0,$0\n\t" - "bne %1,%3,2f\n\t" - "move %0,%4\n\t" -#if _MIPS_SIM == _ABI64 - "scd %0,%2\n\t" -#else - "sc %0,%2\n\t" -#endif - ".set pop\n\t" - "beqz %0,1b\n" - "2:\n\t" - "/* End compare & swap */" - : "=&r" (ret), "=&r" (temp), "=m" (*p) - : "r" (oldval), "r" (newval), "m" (*p) - : "memory"); - - return ret; -} - -#endif /* atomicity.h */ diff --git a/sysdeps/mips/bits/atomic.h b/sysdeps/mips/bits/atomic.h new file mode 100644 index 0000000000..167d9a59c8 --- /dev/null +++ b/sysdeps/mips/bits/atomic.h @@ -0,0 +1,303 @@ +/* Low-level functions for atomic operations. Mips version. + Copyright (C) 2005 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. */ + +#ifndef _MIPS_BITS_ATOMIC_H +#define _MIPS_BITS_ATOMIC_H 1 + +#include +#include + +typedef int32_t atomic32_t; +typedef uint32_t uatomic32_t; +typedef int_fast32_t atomic_fast32_t; +typedef uint_fast32_t uatomic_fast32_t; + +typedef int64_t atomic64_t; +typedef uint64_t uatomic64_t; +typedef int_fast64_t atomic_fast64_t; +typedef uint_fast64_t uatomic_fast64_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + +#if _MIPS_SIM == _ABIO32 +#define MIPS_PUSH_MIPS2 ".set mips2\n\t" +#else +#define MIPS_PUSH_MIPS2 +#endif + +/* See the comments in about the use of the sync instruction. */ +#ifndef MIPS_SYNC +# define MIPS_SYNC sync +#endif + +#define MIPS_SYNC_STR_2(X) #X +#define MIPS_SYNC_STR_1(X) MIPS_SYNC_STR_2(X) +#define MIPS_SYNC_STR MIPS_SYNC_STR_1(MIPS_SYNC) + +/* Compare and exchange. For all of the "xxx" routines, we expect a + "__prev" and a "__cmp" variable to be provided by the enclosing scope, + in which values are returned. */ + +#define __arch_compare_and_exchange_xxx_8_int(mem, newval, oldval, rel, acq) \ + (abort (), __prev = __cmp = 0) + +#define __arch_compare_and_exchange_xxx_16_int(mem, newval, oldval, rel, acq) \ + (abort (), __prev = __cmp = 0) + +#define __arch_compare_and_exchange_xxx_32_int(mem, newval, oldval, rel, acq) \ + __asm__ __volatile__ ( \ + ".set push\n\t" \ + MIPS_PUSH_MIPS2 \ + rel "\n" \ + "1:\t" \ + "ll %0,%4\n\t" \ + "move %1,$0\n\t" \ + "bne %0,%2,2f\n\t" \ + "move %1,%3\n\t" \ + "sc %1,%4\n\t" \ + "beqz %1,1b\n" \ + acq "\n\t" \ + ".set pop\n" \ + "2:\n\t" \ + : "=&r" (__prev), "=&r" (__cmp) \ + : "r" (oldval), "r" (newval), "m" (*mem) \ + : "memory") + +#if _MIPS_SIM == _ABIO32 +/* We can't do an atomic 64-bit operation in O32. */ +#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \ + (abort (), __prev = __cmp = 0) +#else +#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \ + __asm__ __volatile__ ("\n" \ + ".set push\n\t" \ + MIPS_PUSH_MIPS2 \ + rel "\n" \ + "1:\t" \ + "lld %0,%4\n\t" \ + "move %1,$0\n\t" \ + "bne %0,%2,2f\n\t" \ + "move %1,%3\n\t" \ + "scd %1,%4\n\t" \ + "beqz %1,1b\n" \ + acq "\n\t" \ + ".set pop\n" \ + "2:\n\t" \ + : "=&r" (__prev), "=&r" (__cmp) \ + : "r" (oldval), "r" (newval), "m" (*mem) \ + : "memory") +#endif + +/* For all "bool" routines, we return FALSE if exchange succesful. */ + +#define __arch_compare_and_exchange_bool_8_int(mem, new, old, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq); \ + !__cmp; }) + +#define __arch_compare_and_exchange_bool_16_int(mem, new, old, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq); \ + !__cmp; }) + +#define __arch_compare_and_exchange_bool_32_int(mem, new, old, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq); \ + !__cmp; }) + +#define __arch_compare_and_exchange_bool_64_int(mem, new, old, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq); \ + !__cmp; }) + +/* For all "val" routines, return the old value whether exchange + successful or not. */ + +#define __arch_compare_and_exchange_val_8_int(mem, new, old, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq); \ + (typeof (*mem))__prev; }) + +#define __arch_compare_and_exchange_val_16_int(mem, new, old, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq); \ + (typeof (*mem))__prev; }) + +#define __arch_compare_and_exchange_val_32_int(mem, new, old, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq); \ + (typeof (*mem))__prev; }) + +#define __arch_compare_and_exchange_val_64_int(mem, new, old, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq); \ + (typeof (*mem))__prev; }) + +/* Compare and exchange with "acquire" semantics, ie barrier after. */ + +#define atomic_compare_and_exchange_bool_acq(mem, new, old) \ + __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \ + mem, new, old, "", MIPS_SYNC_STR) + +#define atomic_compare_and_exchange_val_acq(mem, new, old) \ + __atomic_val_bysize (__arch_compare_and_exchange_val, int, \ + mem, new, old, "", MIPS_SYNC_STR) + +/* Compare and exchange with "release" semantics, ie barrier before. */ + +#define atomic_compare_and_exchange_bool_rel(mem, new, old) \ + __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \ + mem, new, old, MIPS_SYNC_STR, "") + +#define atomic_compare_and_exchange_val_rel(mem, new, old) \ + __atomic_val_bysize (__arch_compare_and_exchange_val, int, \ + mem, new, old, MIPS_SYNC_STR, "") + + + +/* Atomic exchange (without compare). */ + +#define __arch_exchange_xxx_8_int(mem, newval, rel, acq) \ + (abort (), 0) + +#define __arch_exchange_xxx_16_int(mem, newval, rel, acq) \ + (abort (), 0) + +#define __arch_exchange_xxx_32_int(mem, newval, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __asm__ __volatile__ ("\n" \ + ".set push\n\t" \ + MIPS_PUSH_MIPS2 \ + rel "\n" \ + "1:\t" \ + "ll %0,%3\n\t" \ + "move %1,%2\n\t" \ + "sc %1,%3\n\t" \ + "beqz %1,1b\n" \ + acq "\n\t" \ + ".set pop\n" \ + "2:\n\t" \ + : "=&r" (__prev), "=&r" (__cmp) \ + : "r" (newval), "m" (*mem) \ + : "memory"); \ + __prev; }) + +#if _MIPS_SIM == _ABIO32 +/* We can't do an atomic 64-bit operation in O32. */ +#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \ + (abort (), 0) +#else +#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __asm__ __volatile__ ("\n" \ + ".set push\n\t" \ + MIPS_PUSH_MIPS2 \ + rel "\n" \ + "1:\n" \ + "lld %0,%3\n\t" \ + "move %1,%2\n\t" \ + "scd %1,%3\n\t" \ + "beqz %1,1b\n" \ + acq "\n\t" \ + ".set pop\n" \ + "2:\n\t" \ + : "=&r" (__prev), "=&r" (__cmp) \ + : "r" (newval), "m" (*mem) \ + : "memory"); \ + __prev; }) +#endif + +#define atomic_exchange_acq(mem, value) \ + __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, "", MIPS_SYNC_STR) + +#define atomic_exchange_rel(mem, value) \ + __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, MIPS_SYNC_STR, "") + + +/* Atomically add value and return the previous (unincremented) value. */ + +#define __arch_exchange_and_add_8_int(mem, newval, rel, acq) \ + (abort (), (typeof(*mem)) 0) + +#define __arch_exchange_and_add_16_int(mem, newval, rel, acq) \ + (abort (), (typeof(*mem)) 0) + +#define __arch_exchange_and_add_32_int(mem, value, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __asm__ __volatile__ ("\n" \ + ".set push\n\t" \ + MIPS_PUSH_MIPS2 \ + rel "\n" \ + "1:\t" \ + "ll %0,%3\n\t" \ + "addu %1,%0,%2\n\t" \ + "sc %1,%3\n\t" \ + "beqz %1,1b\n" \ + acq "\n\t" \ + ".set pop\n" \ + "2:\n\t" \ + : "=&r" (__prev), "=&r" (__cmp) \ + : "r" (value), "m" (*mem) \ + : "memory"); \ + __prev; }) + +#if _MIPS_SIM == _ABIO32 +/* We can't do an atomic 64-bit operation in O32. */ +#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \ + (abort (), (typeof(*mem)) 0) +#else +#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \ +({ typeof (*mem) __prev; int __cmp; \ + __asm__ __volatile__ ( \ + ".set push\n\t" \ + MIPS_PUSH_MIPS2 \ + rel "\n" \ + "1:\t" \ + "lld %0,%3\n\t" \ + "daddu %1,%0,%2\n\t" \ + "scd %1,%3\n\t" \ + "beqz %1,1b\n" \ + acq "\n\t" \ + ".set pop\n" \ + "2:\n\t" \ + : "=&r" (__prev), "=&r" (__cmp) \ + : "r" (value), "m" (*mem) \ + : "memory"); \ + __prev; }) +#endif + +/* ??? Barrier semantics for atomic_exchange_and_add appear to be + undefined. Use full barrier for now, as that's safe. */ +#define atomic_exchange_and_add(mem, value) \ + __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, \ + MIPS_SYNC_STR, MIPS_SYNC_STR) + +/* TODO: More atomic operations could be implemented efficiently; only the + basic requirements are done. */ + +#define atomic_full_barrier() \ + __asm__ __volatile__ (".set push\n\t" \ + MIPS_PUSH_MIPS2 \ + MIPS_SYNC_STR "\n\t" \ + ".set pop" : : : "memory") + +#endif /* bits/atomic.h */ diff --git a/sysdeps/mips/dl-tls.h b/sysdeps/mips/dl-tls.h new file mode 100644 index 0000000000..6d3ed6f5a4 --- /dev/null +++ b/sysdeps/mips/dl-tls.h @@ -0,0 +1,46 @@ +/* Thread-local storage handling in the ELF dynamic linker. MIPS version. + Copyright (C) 2005 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. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + +/* The thread pointer points 0x7000 past the first static TLS block. */ +#define TLS_TP_OFFSET 0x7000 + +/* Dynamic thread vector pointers point 0x8000 past the start of each + TLS block. */ +#define TLS_DTV_OFFSET 0x8000 + +/* Compute the value for a GOTTPREL reloc. */ +#define TLS_TPREL_VALUE(sym_map, sym) \ + ((sym_map)->l_tls_offset + (sym)->st_value - TLS_TP_OFFSET) + +/* Compute the value for a DTPREL reloc. */ +#define TLS_DTPREL_VALUE(sym) \ + ((sym)->st_value - TLS_DTV_OFFSET) + +extern void *__tls_get_addr (tls_index *ti); + +# define GET_ADDR_OFFSET (ti->ti_offset + TLS_DTV_OFFSET) +# define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET) diff --git a/sysdeps/mips/dl-trampoline.c b/sysdeps/mips/dl-trampoline.c index c5ea59cdb2..459adf9a8e 100644 --- a/sysdeps/mips/dl-trampoline.c +++ b/sysdeps/mips/dl-trampoline.c @@ -153,7 +153,7 @@ __dl_runtime_resolve (ElfW(Word) sym_index, if (version->hash != 0) { - sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l, + sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope, version, ELF_RTYPE_CLASS_PLT, 0, 0); break; diff --git a/sysdeps/mips/elf/configure b/sysdeps/mips/elf/configure new file mode 100644 index 0000000000..3d90a1e420 --- /dev/null +++ b/sysdeps/mips/elf/configure @@ -0,0 +1,46 @@ +# This file is generated from configure.in by Autoconf. DO NOT EDIT! + # Local configure fragment for sysdeps/mips/elf. + +if test "$usetls" != no; then +# Check for support of thread-local storage handling in assembler and +# linker. +echo "$as_me:$LINENO: checking for MIPS TLS support" >&5 +echo $ECHO_N "checking for MIPS TLS support... $ECHO_C" >&6 +if test "${libc_cv_mips_tls+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat > conftest.s <<\EOF + .section ".tdata", "awT", %progbits + .globl foo +foo: .long 1 + .section ".tbss", "awT", %nobits + .globl bar +bar: .skip 4 + .text + + lw $25, %call16(__tls_get_addr)($28) + jalr $25 + addiu $4, $28, %tlsgd(x) +EOF +if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + libc_cv_mips_tls=yes +else + libc_cv_mips_tls=no +fi +rm -f conftest* +fi +echo "$as_me:$LINENO: result: $libc_cv_mips_tls" >&5 +echo "${ECHO_T}$libc_cv_mips_tls" >&6 +if test $libc_cv_mips_tls = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_TLS_SUPPORT 1 +_ACEOF + +fi +fi + diff --git a/sysdeps/mips/elf/configure.in b/sysdeps/mips/elf/configure.in new file mode 100644 index 0000000000..ecb9108c12 --- /dev/null +++ b/sysdeps/mips/elf/configure.in @@ -0,0 +1,35 @@ +GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory. +# Local configure fragment for sysdeps/mips/elf. + +if test "$usetls" != no; then +# Check for support of thread-local storage handling in assembler and +# linker. +AC_CACHE_CHECK(for MIPS TLS support, libc_cv_mips_tls, [dnl +cat > conftest.s <<\EOF + .section ".tdata", "awT", %progbits + .globl foo +foo: .long 1 + .section ".tbss", "awT", %nobits + .globl bar +bar: .skip 4 + .text + + lw $25, %call16(__tls_get_addr)($28) + jalr $25 + addiu $4, $28, %tlsgd(x) +EOF +dnl +if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS conftest.s 1>&AS_MESSAGE_LOG_FD); then + libc_cv_mips_tls=yes +else + libc_cv_mips_tls=no +fi +rm -f conftest*]) +if test $libc_cv_mips_tls = yes; then + AC_DEFINE(HAVE_TLS_SUPPORT) +fi +fi + +dnl No MIPS GCC supports accessing static and hidden symbols in an +dnl position independent way. +dnl AC_DEFINE(PI_STATIC_AND_HIDDEN) diff --git a/sysdeps/mips/libc-tls.c b/sysdeps/mips/libc-tls.c new file mode 100644 index 0000000000..157ba3389a --- /dev/null +++ b/sysdeps/mips/libc-tls.c @@ -0,0 +1,37 @@ +/* Thread-local storage handling in the ELF dynamic linker. MIPS version. + Copyright (C) 2005 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 +#include + +#if USE_TLS + +/* On MIPS, linker optimizations are not required, so __tls_get_addr + can be called even in statically linked binaries. In this case module + must be always 1 and PT_TLS segment exist in the binary, otherwise it + would not link. */ + +void * +__tls_get_addr (tls_index *ti) +{ + dtv_t *dtv = THREAD_DTV (); + return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET; +} + +#endif diff --git a/sysdeps/mips/sys/asm.h b/sysdeps/mips/sys/asm.h index b04c36ba5e..b590802fd9 100644 --- a/sysdeps/mips/sys/asm.h +++ b/sysdeps/mips/sys/asm.h @@ -1,4 +1,5 @@ -/* Copyright (C) 1997, 1998, 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1997, 1998, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ralf Baechle . @@ -470,4 +471,20 @@ symbol = value # define MTC0 dmtc0 #endif +/* The MIPS archtectures do not have a uniform memory model. Particular + platforms may provide additional guarantees - for instance, the R4000 + LL and SC instructions implicitly perform a SYNC, and the 4K promises + strong ordering. + + However, in the absence of those guarantees, we must assume weak ordering + and SYNC explicitly where necessary. + + Some obsolete MIPS processors may not support the SYNC instruction. This + applies to "true" MIPS I processors; most of the processors which compile + using MIPS I implement parts of MIPS II. */ + +#ifndef MIPS_SYNC +# define MIPS_SYNC sync +#endif + #endif /* sys/asm.h */ diff --git a/sysdeps/mips/tls-macros.h b/sysdeps/mips/tls-macros.h new file mode 100644 index 0000000000..2d0516b3e4 --- /dev/null +++ b/sysdeps/mips/tls-macros.h @@ -0,0 +1,88 @@ +/* Macros to support TLS testing in times of missing compiler support. */ + +#if _MIPS_SIM != _ABI64 + +/* These versions are for o32 and n32. */ + +# define TLS_GD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + asm ("addiu %0, $28, %%tlsgd(" #x ")" \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) +#else +# define TLS_GD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + asm ("daddiu %0, $28, %%tlsgd(" #x ")" \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) +#endif + +#if _MIPS_SIM != _ABI64 +# define TLS_LD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + asm ("addiu %0, $28, %%tlsldm(" #x ")" \ + : "=r" (__result)); \ + __result = __tls_get_addr (__result); \ + asm ("lui $3,%%dtprel_hi(" #x ")\n\t" \ + "addiu $3,$3,%%dtprel_lo(" #x ")\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_IE(x) \ + ({ void *__result; \ + asm (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + asm ("lw $3,%%gottprel(" #x ")($28)\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_LE(x) \ + ({ void *__result; \ + asm (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + asm ("lui $3,%%tprel_hi(" #x ")\n\t" \ + "addiu $3,$3,%%tprel_lo(" #x ")\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) + +#else + +/* These versions are for n64. */ + +# define TLS_LD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + asm ("daddiu %0, $28, %%tlsldm(" #x ")" \ + : "=r" (__result)); \ + __result = __tls_get_addr (__result); \ + asm ("lui $3,%%dtprel_hi(" #x ")\n\t" \ + "daddiu $3,$3,%%dtprel_lo(" #x ")\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_IE(x) \ + ({ void *__result; \ + asm (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + asm ("ld $3,%%gottprel(" #x ")($28)\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_LE(x) \ + ({ void *__result; \ + asm (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + asm ("lui $3,%%tprel_hi(" #x ")\n\t" \ + "daddiu $3,$3,%%tprel_lo(" #x ")\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +#endif diff --git a/sysdeps/unix/sysv/linux/mips/bits/siginfo.h b/sysdeps/unix/sysv/linux/mips/bits/siginfo.h index 54eba41d6e..787e365139 100644 --- a/sysdeps/unix/sysv/linux/mips/bits/siginfo.h +++ b/sysdeps/unix/sysv/linux/mips/bits/siginfo.h @@ -1,5 +1,5 @@ /* siginfo_t, sigevent and constants. Linux/MIPS version. - Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004 + Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -300,10 +300,11 @@ enum # define SIGEV_SIGNAL SIGEV_SIGNAL SIGEV_NONE, /* Other notification: meaningless. */ # define SIGEV_NONE SIGEV_NONE - SIGEV_CALLBACK, /* Deliver via thread creation. */ -# define SIGEV_CALLBACK SIGEV_CALLBACK - SIGEV_THREAD /* Deliver via thread creation. */ + SIGEV_THREAD, /* Deliver via thread creation. */ # define SIGEV_THREAD SIGEV_THREAD + + SIGEV_THREAD_ID = 4 /* Send signal to specific thread. */ +#define SIGEV_THREAD_ID SIGEV_THREAD_ID }; #endif /* have _SIGNAL_H. */ diff --git a/sysdeps/unix/sysv/linux/mips/clone.S b/sysdeps/unix/sysv/linux/mips/clone.S index 043f5921cb..8b8e0072f5 100644 --- a/sysdeps/unix/sysv/linux/mips/clone.S +++ b/sysdeps/unix/sysv/linux/mips/clone.S @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 1997, 2000, 2003 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 , 1996. @@ -24,11 +24,23 @@ #include #define _ERRNO_H 1 #include +#ifdef RESET_PID +#include +#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 -LOCALSZ= 1 +#if _MIPS_SIM == _ABIO32 +# define EXTRA_LOCALS 1 +#else +# define EXTRA_LOCALS 0 +#endif +LOCALSZ= 4 FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK GPOFF= FRAMESZ-(1*SZREG) NESTED(__clone,4*SZREG,sp) @@ -56,10 +68,26 @@ NESTED(__clone,4*SZREG,sp) 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 @@ -94,6 +122,15 @@ L(thread_start): /* cp is already loaded. */ 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. */ @@ -109,6 +146,21 @@ L(thread_start): #else jal _exit #endif + +#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) diff --git a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h index 682ec3d6aa..3da2412259 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h +++ b/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2000, 2002, 2003, 2004, 2005 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 @@ -48,12 +48,12 @@ #undef INLINE_SYSCALL #define INLINE_SYSCALL(name, nr, args...) \ ({ INTERNAL_SYSCALL_DECL(err); \ - long result_var = INTERNAL_SYSCALL (name, err, nr, args); \ - if ( INTERNAL_SYSCALL_ERROR_P (result_var, err) ) \ - { \ - __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, err)); \ - result_var = -1L; \ - } \ + long result_var = INTERNAL_SYSCALL (name, err, nr, args); \ + if ( INTERNAL_SYSCALL_ERROR_P (result_var, err) ) \ + { \ + __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, err)); \ + result_var = -1L; \ + } \ result_var; }) #undef INTERNAL_SYSCALL_DECL @@ -66,203 +66,218 @@ #define INTERNAL_SYSCALL_ERRNO(val, err) (val) #undef INTERNAL_SYSCALL -#define INTERNAL_SYSCALL(name, err, nr, args...) internal_syscall##nr(name, err, args) +#define INTERNAL_SYSCALL(name, err, nr, args...) \ + internal_syscall##nr (, "li\t$2, %2\t\t\t# " #name "\n\t", \ + "i" (SYS_ify (name)), err, args) -#define internal_syscall0(name, err, dummy...) \ -({ \ +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ + internal_syscall##nr (= number, , "r" (__v0), err, args) + +#define internal_syscall0(ncs_init, cs_init, input, err, dummy...) \ +({ \ long _sys_result; \ \ { \ - register long __v0 asm("$2"); \ - register long __a3 asm("$7"); \ - __asm__ volatile ( \ - ".set\tnoreorder\n\t" \ - "li\t$2, %2\t\t\t# " #name "\n\t" \ - "syscall\n\t" \ - ".set reorder" \ - : "=r" (__v0), "=r" (__a3) \ - : "i" (SYS_ify(name)) \ - : __SYSCALL_CLOBBERS); \ + register long __v0 asm("$2") ncs_init; \ + register long __a3 asm("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set reorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input \ + : __SYSCALL_CLOBBERS); \ err = __a3; \ _sys_result = __v0; \ } \ _sys_result; \ }) -#define internal_syscall1(name, err, arg1) \ -({ \ +#define internal_syscall1(ncs_init, cs_init, input, err, arg1) \ +({ \ long _sys_result; \ \ { \ - register long __v0 asm("$2"); \ - register long __a0 asm("$4") = (long) arg1; \ - register long __a3 asm("$7"); \ - __asm__ volatile ( \ - ".set\tnoreorder\n\t" \ - "li\t$2, %3\t\t\t# " #name "\n\t" \ - "syscall\n\t" \ - ".set reorder" \ - : "=r" (__v0), "=r" (__a3) \ - : "r" (__a0), "i" (SYS_ify(name)) \ - : __SYSCALL_CLOBBERS); \ + register long __v0 asm("$2") ncs_init; \ + register long __a0 asm("$4") = (long) arg1; \ + register long __a3 asm("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set reorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input, "r" (__a0) \ + : __SYSCALL_CLOBBERS); \ err = __a3; \ _sys_result = __v0; \ } \ _sys_result; \ }) -#define internal_syscall2(name, err, arg1, arg2) \ -({ \ +#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2) \ +({ \ long _sys_result; \ \ { \ - register long __v0 asm("$2"); \ - register long __a0 asm("$4") = (long) arg1; \ - register long __a1 asm("$5") = (long) arg2; \ - register long __a3 asm("$7"); \ - __asm__ volatile ( \ - ".set\tnoreorder\n\t" \ - "li\t$2, %4\t\t\t# " #name "\n\t" \ - "syscall\n\t" \ - ".set\treorder" \ - : "=r" (__v0), "=r" (__a3) \ - : "r" (__a0), "r" (__a1), "i" (SYS_ify(name)) \ - : __SYSCALL_CLOBBERS); \ + register long __v0 asm("$2") ncs_init; \ + register long __a0 asm("$4") = (long) arg1; \ + register long __a1 asm("$5") = (long) arg2; \ + register long __a3 asm("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input, "r" (__a0), "r" (__a1) \ + : __SYSCALL_CLOBBERS); \ err = __a3; \ _sys_result = __v0; \ } \ _sys_result; \ }) -#define internal_syscall3(name, err, arg1, arg2, arg3) \ -({ \ +#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3)\ +({ \ long _sys_result; \ \ { \ - register long __v0 asm("$2"); \ - register long __a0 asm("$4") = (long) arg1; \ - register long __a1 asm("$5") = (long) arg2; \ - register long __a2 asm("$6") = (long) arg3; \ - register long __a3 asm("$7"); \ - __asm__ volatile ( \ - ".set\tnoreorder\n\t" \ - "li\t$2, %5\t\t\t# " #name "\n\t" \ - "syscall\n\t" \ - ".set\treorder" \ - : "=r" (__v0), "=r" (__a3) \ - : "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name)) \ - : __SYSCALL_CLOBBERS); \ + register long __v0 asm("$2") ncs_init; \ + register long __a0 asm("$4") = (long) arg1; \ + register long __a1 asm("$5") = (long) arg2; \ + register long __a2 asm("$6") = (long) arg3; \ + register long __a3 asm("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2) \ + : __SYSCALL_CLOBBERS); \ err = __a3; \ _sys_result = __v0; \ } \ _sys_result; \ }) -#define internal_syscall4(name, err, arg1, arg2, arg3, arg4) \ -({ \ +#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4)\ +({ \ long _sys_result; \ \ { \ - register long __v0 asm("$2"); \ - register long __a0 asm("$4") = (long) arg1; \ - register long __a1 asm("$5") = (long) arg2; \ - register long __a2 asm("$6") = (long) arg3; \ - register long __a3 asm("$7") = (long) arg4; \ - __asm__ volatile ( \ - ".set\tnoreorder\n\t" \ - "li\t$2, %5\t\t\t# " #name "\n\t" \ - "syscall\n\t" \ - ".set\treorder" \ - : "=r" (__v0), "+r" (__a3) \ - : "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name)) \ - : __SYSCALL_CLOBBERS); \ + register long __v0 asm("$2") ncs_init; \ + register long __a0 asm("$4") = (long) arg1; \ + register long __a1 asm("$5") = (long) arg2; \ + register long __a2 asm("$6") = (long) arg3; \ + register long __a3 asm("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2) \ + : __SYSCALL_CLOBBERS); \ err = __a3; \ _sys_result = __v0; \ } \ _sys_result; \ }) -#define internal_syscall5(name, err, arg1, arg2, arg3, arg4, arg5) \ -({ \ +/* We need to use a frame pointer for the functions in which we + adjust $sp around the syscall, or debug information and unwind + information will be $sp relative and thus wrong during the syscall. As + of GCC 3.4.3, this is sufficient. */ +#define FORCE_FRAME_POINTER alloca (4) + +#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5)\ +({ \ long _sys_result; \ \ + FORCE_FRAME_POINTER; \ { \ - register long __v0 asm("$2"); \ - register long __a0 asm("$4") = (long) arg1; \ - register long __a1 asm("$5") = (long) arg2; \ - register long __a2 asm("$6") = (long) arg3; \ - register long __a3 asm("$7") = (long) arg4; \ - __asm__ volatile ( \ - ".set\tnoreorder\n\t" \ - "subu\t$29, 32\n\t" \ - "sw\t%6, 16($29)\n\t" \ - "li\t$2, %5\t\t\t# " #name "\n\t" \ - "syscall\n\t" \ - "addiu\t$29, 32\n\t" \ - ".set\treorder" \ - : "=r" (__v0), "+r" (__a3) \ - : "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name)), \ - "r" ((long)arg5) \ - : __SYSCALL_CLOBBERS); \ + register long __v0 asm("$2") ncs_init; \ + register long __a0 asm("$4") = (long) arg1; \ + register long __a1 asm("$5") = (long) arg2; \ + register long __a2 asm("$6") = (long) arg3; \ + register long __a3 asm("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t%6, 16($29)\n\t" \ + cs_init \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2), \ + "r" ((long)arg5) \ + : __SYSCALL_CLOBBERS); \ err = __a3; \ _sys_result = __v0; \ } \ _sys_result; \ }) -#define internal_syscall6(name, err, arg1, arg2, arg3, arg4, arg5, arg6)\ -({ \ +#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6)\ +({ \ long _sys_result; \ \ + FORCE_FRAME_POINTER; \ { \ - register long __v0 asm("$2"); \ - register long __a0 asm("$4") = (long) arg1; \ - register long __a1 asm("$5") = (long) arg2; \ - register long __a2 asm("$6") = (long) arg3; \ - register long __a3 asm("$7") = (long) arg4; \ - __asm__ volatile ( \ - ".set\tnoreorder\n\t" \ - "subu\t$29, 32\n\t" \ - "sw\t%6, 16($29)\n\t" \ - "sw\t%7, 20($29)\n\t" \ - "li\t$2, %5\t\t\t# " #name "\n\t" \ - "syscall\n\t" \ - "addiu\t$29, 32\n\t" \ - ".set\treorder" \ - : "=r" (__v0), "+r" (__a3) \ - : "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name)), \ + register long __v0 asm("$2") ncs_init; \ + register long __a0 asm("$4") = (long) arg1; \ + register long __a1 asm("$5") = (long) arg2; \ + register long __a2 asm("$6") = (long) arg3; \ + register long __a3 asm("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t%6, 16($29)\n\t" \ + "sw\t%7, 20($29)\n\t" \ + cs_init \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2), \ "r" ((long)arg5), "r" ((long)arg6) \ - : __SYSCALL_CLOBBERS); \ + : __SYSCALL_CLOBBERS); \ err = __a3; \ _sys_result = __v0; \ } \ _sys_result; \ }) -#define internal_syscall7(name, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ -({ \ +#define internal_syscall7(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ +({ \ long _sys_result; \ \ + FORCE_FRAME_POINTER; \ { \ - register long __v0 asm("$2"); \ - register long __a0 asm("$4") = (long) arg1; \ - register long __a1 asm("$5") = (long) arg2; \ - register long __a2 asm("$6") = (long) arg3; \ - register long __a3 asm("$7") = (long) arg4; \ - __asm__ volatile ( \ - ".set\tnoreorder\n\t" \ - "subu\t$29, 32\n\t" \ - "sw\t%6, 16($29)\n\t" \ - "sw\t%7, 20($29)\n\t" \ - "sw\t%8, 24($29)\n\t" \ - "li\t$2, %5\t\t\t# " #name "\n\t" \ - "syscall\n\t" \ - "addiu\t$29, 32\n\t" \ - ".set\treorder" \ - : "=r" (__v0), "+r" (__a3) \ - : "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name)), \ + register long __v0 asm("$2") ncs_init; \ + register long __a0 asm("$4") = (long) arg1; \ + register long __a1 asm("$5") = (long) arg2; \ + register long __a2 asm("$6") = (long) arg3; \ + register long __a3 asm("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t%6, 16($29)\n\t" \ + "sw\t%7, 20($29)\n\t" \ + "sw\t%8, 24($29)\n\t" \ + cs_init \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2), \ "r" ((long)arg5), "r" ((long)arg6), "r" ((long)arg7) \ - : __SYSCALL_CLOBBERS); \ + : __SYSCALL_CLOBBERS); \ err = __a3; \ _sys_result = __v0; \ } \ diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S new file mode 100644 index 0000000000..1383ddc6a7 --- /dev/null +++ b/sysdeps/unix/sysv/linux/mips/vfork.S @@ -0,0 +1,98 @@ +/* Copyright (C) 2005 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. */ + +/* vfork() is just a special case of clone(). */ + +#include +#include +#include +#include + +#ifndef SAVE_PID +#define SAVE_PID +#endif + +#ifndef RESTORE_PID +#define RESTORE_PID +#endif + + +/* int vfork() */ + + .text +LOCALSZ= 1 +FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK +GPOFF= FRAMESZ-(1*SZREG) +NESTED(__vfork,FRAMESZ,sp) +#ifdef __PIC__ + SETUP_GP +#endif + PTR_SUBU sp, FRAMESZ + SETUP_GP64 (a5, __vfork) +#ifdef __PIC__ + SAVE_GP (GPOFF) +#endif +#ifdef PROF +# if (_MIPS_SIM != _ABIO32) + PTR_S a5, GPOFF(sp) +# endif + .set noat + move $1, ra +# if (_MIPS_SIM == _ABIO32) + subu sp,sp,8 +# endif + jal _mcount + .set at +# if (_MIPS_SIM != _ABIO32) + PTR_L a5, GPOFF(sp) +# endif +#endif + + PTR_ADDU sp, FRAMESZ + + SAVE_PID + + li a0, 0x4112 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ + move a1, sp + + /* Do the system call */ + li v0,__NR_clone + syscall + + RESTORE_PID + + bnez a3,L(error) + + /* Successful return from the parent or child. */ + RESTORE_GP64 + ret + + /* Something bad happened -- no child created. */ +L(error): +#ifdef __PIC__ + PTR_LA t9, __syscall_error + RESTORE_GP64 + jr t9 +#else + RESTORE_GP64 + j __syscall_error +#endif + END(__vfork) + +libc_hidden_def(__vfork) +weak_alias(__vfork, vfork)