mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-25 22:40:05 +00:00
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 <dan@codesourcery.com>
This commit is contained in:
parent
abc85e9fea
commit
f850220be6
31
ChangeLog
31
ChangeLog
@ -1,3 +1,34 @@
|
||||
2005-03-28 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* 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 <dan@codesourcery.com>
|
||||
|
||||
[BZ #783]
|
||||
|
@ -1,3 +1,8 @@
|
||||
2005-03-28 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* sysdeps/mips/tls.h: New file.
|
||||
* sysdeps/unix/sysv/linux/mips/vfork.S: New file.
|
||||
|
||||
2005-03-21 GOTO Masanori <gotom@debian.or.jp>
|
||||
|
||||
* linuxthreads/sysdeps/m68k/Makefile: Remove to delete
|
||||
|
170
linuxthreads/sysdeps/mips/tls.h
Normal file
170
linuxthreads/sysdeps/mips/tls.h
Normal file
@ -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 <stdbool.h>
|
||||
# include <pt-machine.h>
|
||||
# include <stddef.h>
|
||||
|
||||
/* 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 <tcb-offsets.h>
|
||||
|
||||
/* 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 <linuxthreads/descr.h>
|
||||
|
||||
/* 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 */
|
104
linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S
Normal file
104
linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S
Normal file
@ -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 <sys/asm.h>
|
||||
#include <sysdep.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
/* 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)
|
@ -1,3 +1,24 @@
|
||||
2005-03-28 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* 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 <drepper@redhat.com>
|
||||
|
||||
* pthread_create.c (__pthread_create_2_1): Rename syscall error
|
||||
|
25
nptl/sysdeps/mips/Makefile
Normal file
25
nptl/sysdeps/mips/Makefile
Normal file
@ -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
|
30
nptl/sysdeps/mips/jmpbuf-unwind.h
Normal file
30
nptl/sysdeps/mips/jmpbuf-unwind.h
Normal file
@ -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 <setjmp.h>
|
||||
#include <stdint.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#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)
|
2
nptl/sysdeps/mips/nptl-sysdep.S
Normal file
2
nptl/sysdeps/mips/nptl-sysdep.S
Normal file
@ -0,0 +1,2 @@
|
||||
/* Pull in __syscall_error. */
|
||||
#include <sysdep.S>
|
37
nptl/sysdeps/mips/pthread_spin_lock.S
Normal file
37
nptl/sysdeps/mips/pthread_spin_lock.S
Normal file
@ -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 <sys/asm.h>
|
||||
#include <sysdep.h>
|
||||
#include <sgidefs.h>
|
||||
|
||||
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)
|
41
nptl/sysdeps/mips/pthread_spin_trylock.S
Normal file
41
nptl/sysdeps/mips/pthread_spin_trylock.S
Normal file
@ -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 <sys/asm.h>
|
||||
#include <sysdep.h>
|
||||
#define _ERRNO_H 1
|
||||
#include <bits/errno.h>
|
||||
#include <sgidefs.h>
|
||||
|
||||
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)
|
39
nptl/sysdeps/mips/pthreaddef.h
Normal file
39
nptl/sysdeps/mips/pthreaddef.h
Normal file
@ -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))
|
11
nptl/sysdeps/mips/tcb-offsets.sym
Normal file
11
nptl/sysdeps/mips/tcb-offsets.sym
Normal file
@ -0,0 +1,11 @@
|
||||
#include <sysdep.h>
|
||||
#include <tls.h>
|
||||
|
||||
--
|
||||
|
||||
-- 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)
|
161
nptl/sysdeps/mips/tls.h
Normal file
161
nptl/sysdeps/mips/tls.h
Normal file
@ -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 <dl-sysdep.h>
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
|
||||
/* 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 <tcb-offsets.h>
|
||||
|
||||
# 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 <sysdep.h>
|
||||
|
||||
/* The TP points to the start of the thread blocks. */
|
||||
# define TLS_DTV_AT_TP 1
|
||||
|
||||
/* Get the thread descriptor definition. */
|
||||
# include <nptl/descr.h>
|
||||
|
||||
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 */
|
40
nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h
Normal file
40
nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h
Normal file
@ -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 <bits/semaphore.h> directly; include <semaphore.h> 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;
|
2
nptl/sysdeps/unix/sysv/linux/mips/clone.S
Normal file
2
nptl/sysdeps/unix/sysv/linux/mips/clone.S
Normal file
@ -0,0 +1,2 @@
|
||||
#define RESET_PID
|
||||
#include <sysdeps/unix/sysv/linux/mips/clone.S>
|
24
nptl/sysdeps/unix/sysv/linux/mips/createthread.c
Normal file
24
nptl/sysdeps/unix/sysv/linux/mips/createthread.c
Normal file
@ -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 <nptl/sysdeps/pthread/createthread.c>
|
1
nptl/sysdeps/unix/sysv/linux/mips/fork.c
Normal file
1
nptl/sysdeps/unix/sysv/linux/mips/fork.c
Normal file
@ -0,0 +1 @@
|
||||
#include "../i386/fork.c"
|
216
nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h
Normal file
216
nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h
Normal file
@ -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 <time.h>
|
||||
#include <sys/param.h>
|
||||
#include <bits/pthreadtypes.h>
|
||||
#include <atomic.h>
|
||||
#include <sysdep.h>
|
||||
|
||||
|
||||
#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 */
|
37
nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S
Normal file
37
nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S
Normal file
@ -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 <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. */ \
|
||||
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>
|
94
nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c
Normal file
94
nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c
Normal file
@ -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 <jakub@redhat.com>, 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 <lowlevellock.h>
|
||||
|
||||
|
||||
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)
|
170
nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h
Normal file
170
nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h
Normal file
@ -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 <sysdep.h>
|
||||
#include <sysdeps/generic/sysdep.h>
|
||||
#include <tls.h>
|
||||
#ifndef __ASSEMBLER__
|
||||
# include <nptl/pthreadP.h>
|
||||
#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
|
42
nptl/sysdeps/unix/sysv/linux/mips/vfork.S
Normal file
42
nptl/sysdeps/unix/sysv/linux/mips/vfork.S
Normal file
@ -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 <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 <../sysdeps/unix/sysv/linux/mips/vfork.S>
|
@ -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 <inttypes.h>
|
||||
#include <sgidefs.h>
|
||||
|
||||
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 */
|
303
sysdeps/mips/bits/atomic.h
Normal file
303
sysdeps/mips/bits/atomic.h
Normal file
@ -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 <inttypes.h>
|
||||
#include <sgidefs.h>
|
||||
|
||||
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 <sys/asm.h> 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 */
|
46
sysdeps/mips/dl-tls.h
Normal file
46
sysdeps/mips/dl-tls.h
Normal file
@ -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)
|
46
sysdeps/mips/elf/configure
vendored
Normal file
46
sysdeps/mips/elf/configure
vendored
Normal file
@ -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
|
||||
|
35
sysdeps/mips/elf/configure.in
Normal file
35
sysdeps/mips/elf/configure.in
Normal file
@ -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)
|
37
sysdeps/mips/libc-tls.c
Normal file
37
sysdeps/mips/libc-tls.c
Normal file
@ -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 <sysdeps/generic/libc-tls.c>
|
||||
#include <dl-tls.h>
|
||||
|
||||
#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
|
@ -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 <ralf@gnu.org>.
|
||||
|
||||
@ -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 */
|
||||
|
88
sysdeps/mips/tls-macros.h
Normal file
88
sysdeps/mips/tls-macros.h
Normal file
@ -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
|
@ -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. */
|
||||
|
@ -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 <ralf@linux-mips.org>, 1996.
|
||||
|
||||
@ -24,11 +24,23 @@
|
||||
#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
|
||||
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)
|
||||
|
@ -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
|
||||
@ -66,22 +66,28 @@
|
||||
#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 __v0 asm("$2") ncs_init; \
|
||||
register long __a3 asm("$7"); \
|
||||
__asm__ volatile ( \
|
||||
".set\tnoreorder\n\t" \
|
||||
"li\t$2, %2\t\t\t# " #name "\n\t" \
|
||||
cs_init \
|
||||
"syscall\n\t" \
|
||||
".set reorder" \
|
||||
: "=r" (__v0), "=r" (__a3) \
|
||||
: "i" (SYS_ify(name)) \
|
||||
: input \
|
||||
: __SYSCALL_CLOBBERS); \
|
||||
err = __a3; \
|
||||
_sys_result = __v0; \
|
||||
@ -89,21 +95,21 @@
|
||||
_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 __v0 asm("$2") ncs_init; \
|
||||
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" \
|
||||
cs_init \
|
||||
"syscall\n\t" \
|
||||
".set reorder" \
|
||||
: "=r" (__v0), "=r" (__a3) \
|
||||
: "r" (__a0), "i" (SYS_ify(name)) \
|
||||
: input, "r" (__a0) \
|
||||
: __SYSCALL_CLOBBERS); \
|
||||
err = __a3; \
|
||||
_sys_result = __v0; \
|
||||
@ -111,22 +117,22 @@
|
||||
_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 __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" \
|
||||
"li\t$2, %4\t\t\t# " #name "\n\t" \
|
||||
cs_init \
|
||||
"syscall\n\t" \
|
||||
".set\treorder" \
|
||||
: "=r" (__v0), "=r" (__a3) \
|
||||
: "r" (__a0), "r" (__a1), "i" (SYS_ify(name)) \
|
||||
: input, "r" (__a0), "r" (__a1) \
|
||||
: __SYSCALL_CLOBBERS); \
|
||||
err = __a3; \
|
||||
_sys_result = __v0; \
|
||||
@ -134,23 +140,23 @@
|
||||
_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 __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" \
|
||||
"li\t$2, %5\t\t\t# " #name "\n\t" \
|
||||
cs_init \
|
||||
"syscall\n\t" \
|
||||
".set\treorder" \
|
||||
: "=r" (__v0), "=r" (__a3) \
|
||||
: "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name)) \
|
||||
: input, "r" (__a0), "r" (__a1), "r" (__a2) \
|
||||
: __SYSCALL_CLOBBERS); \
|
||||
err = __a3; \
|
||||
_sys_result = __v0; \
|
||||
@ -158,23 +164,23 @@
|
||||
_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 __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" \
|
||||
"li\t$2, %5\t\t\t# " #name "\n\t" \
|
||||
cs_init \
|
||||
"syscall\n\t" \
|
||||
".set\treorder" \
|
||||
: "=r" (__v0), "+r" (__a3) \
|
||||
: "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name)) \
|
||||
: input, "r" (__a0), "r" (__a1), "r" (__a2) \
|
||||
: __SYSCALL_CLOBBERS); \
|
||||
err = __a3; \
|
||||
_sys_result = __v0; \
|
||||
@ -182,12 +188,19 @@
|
||||
_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 __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; \
|
||||
@ -196,12 +209,12 @@
|
||||
".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" \
|
||||
cs_init \
|
||||
"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)), \
|
||||
: input, "r" (__a0), "r" (__a1), "r" (__a2), \
|
||||
"r" ((long)arg5) \
|
||||
: __SYSCALL_CLOBBERS); \
|
||||
err = __a3; \
|
||||
@ -210,12 +223,13 @@
|
||||
_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 __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; \
|
||||
@ -225,12 +239,12 @@
|
||||
"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" \
|
||||
cs_init \
|
||||
"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)), \
|
||||
: input, "r" (__a0), "r" (__a1), "r" (__a2), \
|
||||
"r" ((long)arg5), "r" ((long)arg6) \
|
||||
: __SYSCALL_CLOBBERS); \
|
||||
err = __a3; \
|
||||
@ -239,12 +253,13 @@
|
||||
_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 __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; \
|
||||
@ -255,12 +270,12 @@
|
||||
"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" \
|
||||
cs_init \
|
||||
"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)), \
|
||||
: input, "r" (__a0), "r" (__a1), "r" (__a2), \
|
||||
"r" ((long)arg5), "r" ((long)arg6), "r" ((long)arg7) \
|
||||
: __SYSCALL_CLOBBERS); \
|
||||
err = __a3; \
|
||||
|
98
sysdeps/unix/sysv/linux/mips/vfork.S
Normal file
98
sysdeps/unix/sysv/linux/mips/vfork.S
Normal file
@ -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 <sys/asm.h>
|
||||
#include <sysdep.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <sgidefs.h>
|
||||
|
||||
#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)
|
Loading…
Reference in New Issue
Block a user