@@ -25,7 +25,7 @@ long int
__syscall_cancel (__syscall_arg_t nr, __syscall_arg_t a1,
__syscall_arg_t a2, __syscall_arg_t a3,
__syscall_arg_t a4, __syscall_arg_t a5,
- __syscall_arg_t a6)
+ __syscall_arg_t a6 __SYSCALL_CANCEL7_ARG_DEF)
{
pthread_t self = (pthread_t) THREAD_SELF;
volatile struct pthread *pd = (volatile struct pthread *) self;
@@ -35,7 +35,8 @@ __syscall_cancel (__syscall_arg_t nr, __syscall_arg_t a1,
if (pd->cancelhandling & CANCELSTATE_BITMASK)
{
INTERNAL_SYSCALL_DECL (err);
- result = INTERNAL_SYSCALL_NCS_CALL (nr, err, a1, a2, a3, a4, a5, a6);
+ result = INTERNAL_SYSCALL_NCS_CALL (nr, err, a1, a2, a3, a4, a5, a6
+ __SYSCALL_CANCEL7_ARG7);
if (INTERNAL_SYSCALL_ERROR_P (result, err))
return -INTERNAL_SYSCALL_ERRNO (result, err);
return result;
@@ -44,7 +45,7 @@ __syscall_cancel (__syscall_arg_t nr, __syscall_arg_t a1,
/* Call the arch-specific entry points that contains the globals markers
to be checked by SIGCANCEL handler. */
result = __syscall_cancel_arch (&pd->cancelhandling, nr, a1, a2, a3, a4, a5,
- a6);
+ a6 __SYSCALL_CANCEL7_ARG7);
if ((result == -EINTR)
&& (pd->cancelhandling & CANCELED_BITMASK)
@@ -317,7 +317,8 @@ __do_cancel (void)
extern long int __syscall_cancel_arch (volatile int *, __syscall_arg_t nr,
__syscall_arg_t arg1, __syscall_arg_t arg2, __syscall_arg_t arg3,
- __syscall_arg_t arg4, __syscall_arg_t arg5, __syscall_arg_t arg6);
+ __syscall_arg_t arg4, __syscall_arg_t arg5, __syscall_arg_t arg6
+ __SYSCALL_CANCEL7_ARG_DEF);
libc_hidden_proto (__syscall_cancel_arch);
extern void __syscall_do_cancel (void)
@@ -35,7 +35,7 @@
# define READ_THREAD_POINTER() (__builtin_thread_pointer ())
#else
/* Note: rd must be $v1 to be ABI-conformant. */
-# if __mips_isa_rev >= 2
+# if defined __mips_isa_rev && __mips_isa_rev >= 2
# define READ_THREAD_POINTER() \
({ void *__result; \
asm volatile ("rdhwr\t%0, $29" : "=v" (__result)); \
@@ -121,29 +121,51 @@ typedef long int __syscall_arg_t;
# define __SSC(__x) ((__syscall_arg_t) (__x))
#endif
+/* Adjust both the __syscall_cancel and the SYSCALL_CANCEL macro to support
+ 7 arguments instead of default 6 (for some architectures like mip32).
+ We need it because using 7 arguments for all architecture would require
+ then to implement both {INTERNAL,INLINE}_SYSCALL and __syscall_cancel_arch
+ to accept 7 arguments. */
+#ifdef HAVE_CANCELABLE_SYSCALL_WITH_7_ARGS
+# define __SYSCALL_CANCEL7_ARG_DEF , __syscall_arg_t arg7
+# define __SYSCALL_CANCEL7_ARG , 0
+# define __SYSCALL_CANCEL7_ARG7 , arg7
+#else
+# define __SYSCALL_CANCEL7_ARG_DEF
+# define __SYSCALL_CANCEL7_ARG
+# define __SYSCALL_CANCEL7_ARG7
+#endif
+
long int __syscall_cancel (__syscall_arg_t nr, __syscall_arg_t arg1,
__syscall_arg_t arg2, __syscall_arg_t arg3,
__syscall_arg_t arg4, __syscall_arg_t arg5,
- __syscall_arg_t arg6);
+ __syscall_arg_t arg6 __SYSCALL_CANCEL7_ARG_DEF);
libc_hidden_proto (__syscall_cancel);
#define __SYSCALL_CANCEL0(name) \
- (__syscall_cancel)(__NR_##name, 0, 0, 0, 0, 0, 0)
+ (__syscall_cancel)(__NR_##name, 0, 0, 0, 0, 0, 0 \
+ __SYSCALL_CANCEL7_ARG)
#define __SYSCALL_CANCEL1(name, a1) \
- (__syscall_cancel)(__NR_##name, __SSC(a1), 0, 0, 0, 0, 0)
+ (__syscall_cancel)(__NR_##name, __SSC(a1), 0, 0, 0, 0, 0 \
+ __SYSCALL_CANCEL7_ARG)
#define __SYSCALL_CANCEL2(name, a1, a2) \
- (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), 0, 0, 0, 0)
+ (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), 0, 0, 0, 0 \
+ __SYSCALL_CANCEL7_ARG)
#define __SYSCALL_CANCEL3(name, a1, a2, a3) \
- (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), 0, 0, 0)
+ (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), 0, 0, 0 \
+ __SYSCALL_CANCEL7_ARG)
#define __SYSCALL_CANCEL4(name, a1, a2, a3, a4) \
(__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), \
- __SSC(a4), 0, 0)
+ __SSC(a4), 0, 0 __SYSCALL_CANCEL7_ARG)
#define __SYSCALL_CANCEL5(name, a1, a2, a3, a4, a5) \
(__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), \
- __SSC(a4), __SSC(a5), 0)
+ __SSC(a4), __SSC(a5), 0 __SYSCALL_CANCEL7_ARG)
#define __SYSCALL_CANCEL6(name, a1, a2, a3, a4, a5, a6) \
(__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), \
- __SSC(a4), __SSC(a5), __SSC(a6))
+ __SSC(a4), __SSC(a5), __SSC(a6) __SYSCALL_CANCEL7_ARG)
+#define __SYSCALL_CANCEL7(name, a1, a2, a3, a4, a5, a6, a7) \
+ (__syscall_cancel)(__NR_##name, __SSC(a1), __SSC(a2), __SSC(a3), \
+ __SSC(a4), __SSC(a5), __SSC(a6), __SSC(a7))
#define __SYSCALL_CANCEL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n
#define __SYSCALL_CANCEL_NARGS(...) \
new file mode 100644
@@ -0,0 +1,128 @@
+/* Cancellable syscall wrapper. Linux/mips32 version.
+ Copyright (C) 2017 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <sys/asm.h>
+
+/* long int __syscall_cancel_arch (int *cancelhandling,
+ __syscall_arg_t nr,
+ __syscall_arg_t arg1,
+ __syscall_arg_t arg2,
+ __syscall_arg_t arg3,
+ __syscall_arg_t arg4,
+ __syscall_arg_t arg5,
+ __syscall_arg_t arg6,
+ __syscall_arg_t arg7) */
+
+#define FRAME_SIZE 56
+
+NESTED (__syscall_cancel_arch, FRAME_SIZE, fp)
+ .mask 0xc0070000,-SZREG
+ .fmask 0x00000000,0
+
+ PTR_ADDIU sp, -FRAME_SIZE
+ cfi_def_cfa_offset (FRAME_SIZE)
+
+ sw fp,48(sp)
+ sw ra,52(sp)
+ sw s2,44(sp)
+ sw s1,40(sp)
+ sw s0,36(sp)
+#ifdef __PIC__
+ .cprestore 16
+#endif
+ cfi_offset (31, -4)
+ cfi_offset (30, -8)
+ cfi_offset (18, -12)
+ cfi_offset (17, -16)
+ cfi_offset (16, -20)
+ move fp,sp
+ cfi_def_cfa_register (30)
+
+ .globl __syscall_cancel_arch_start
+ .type __syscall_cancel_arch_start, @function
+__syscall_cancel_arch_start:
+
+ lw v0,0(a0)
+ andi v0,v0,0x4
+ bne v0,zero,2f
+
+ addiu sp,sp,-16
+ addiu v0,sp,16
+ sw v0,24(fp)
+
+ move s0,a1
+ move a0,a2
+ move a1,a3
+ lw a2,72(fp)
+ lw a3,76(fp)
+ lw v0,84(fp)
+ lw s1,80(fp)
+ lw s2,88(fp)
+
+ .set noreorder
+ subu sp, 32
+ sw s1, 16(sp)
+ sw v0, 20(sp)
+ sw s2, 24(sp)
+ move v0, $16
+ syscall
+
+ .globl __syscall_cancel_arch_end
+ .type __syscall_cancel_arch_end, @function
+__syscall_cancel_arch_end:
+ addiu sp, 32
+ .set reorder
+
+ beq a3,zero,1f
+ subu v0,zero,v0
+1:
+ move sp,fp
+ cfi_remember_state
+ cfi_def_cfa_register (29)
+ lw ra,52(fp)
+ lw fp,48(sp)
+ lw s2,44(sp)
+ lw s1,40(sp)
+ lw s0,36(sp)
+ .set noreorder
+ .set nomacro
+ jr ra
+ addiu sp,sp,FRAME_SIZE
+
+ .set macro
+ .set reorder
+
+ cfi_def_cfa_offset (0)
+ cfi_restore (16)
+ cfi_restore (17)
+ cfi_restore (18)
+ cfi_restore (30)
+ cfi_restore (31)
+
+2:
+ cfi_restore_state
+#ifdef __PIC__
+ PTR_LA t9, __syscall_do_cancel
+ jalr t9
+#else
+ jal __syscall_do_cancel
+#endif
+
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
@@ -18,6 +18,10 @@
#ifndef _LINUX_MIPS_MIPS32_SYSDEP_H
#define _LINUX_MIPS_MIPS32_SYSDEP_H 1
+/* mips32 have cancelable syscalls with 7 arguments (currently only
+ sync_file_range). */
+#define HAVE_CANCELABLE_SYSCALL_WITH_7_ARGS 1
+
/* There is some commonality. */
#include <sysdeps/unix/sysv/linux/sysdep.h>
#include <sysdeps/unix/mips/mips32/sysdep.h>
@@ -16,7 +16,10 @@
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
+#ifndef _SIGCONTEXTINFO_H
+#define _SIGCONTEXTINFO_H
+#include <stdint.h>
#include <sgidefs.h>
#if _MIPS_SIM == _ABIO32
@@ -39,4 +42,12 @@
#define CALL_SIGHANDLER(handler, signo, ctx) \
(handler)((signo), SIGCONTEXT_EXTRA_ARGS (ctx))
-#endif
+#endif /* _MIPS_SIM == _ABIO32 */
+
+static inline uintptr_t
+ucontext_get_pc (const ucontext_t *uc)
+{
+ return uc->uc_mcontext.pc;
+}
+
+#endif /* _SIGCONTEXTINFO_H */
@@ -45,14 +45,16 @@ long int
__syscall_cancel_arch (volatile int *ch, __syscall_arg_t nr,
__syscall_arg_t a1, __syscall_arg_t a2,
__syscall_arg_t a3, __syscall_arg_t a4,
- __syscall_arg_t a5, __syscall_arg_t a6)
+ __syscall_arg_t a5, __syscall_arg_t a6
+ __SYSCALL_CANCEL7_ARG_DEF)
{
ADD_LABEL ("__syscall_cancel_arch_start");
if (__glibc_unlikely (*ch & CANCELED_BITMASK))
__syscall_do_cancel();
INTERNAL_SYSCALL_DECL(err);
- long int result = INTERNAL_SYSCALL_NCS (nr, err, 6, a1, a2, a3, a4, a5, a6);
+ long int result = INTERNAL_SYSCALL_NCS_CALL (nr, err, a1, a2, a3, a4, a5,
+ a6 __SYSCALL_CANCEL7_ARG7);
ADD_LABEL ("__syscall_cancel_arch_end");
if (INTERNAL_SYSCALL_ERROR_P (result, err))
return -INTERNAL_SYSCALL_ERRNO (result, err);
This patch adds the mips modifications required for the BZ#12683. It adds the required ucontext_get_pc function, a mips32 cancellable syscall wrapper and 7 argument cancellable syscall support. To avoid code pessimization and add a requirement on all architectures to support {INLINE,INTERNAL)_SYSCALL with 7 argument, its support is added through a flag, HAVE_CANCELABLE_SYSCALL_WITH_7_ARGS, which changes the signature and prototype of the requires macros and functions (SYSCALL_CANCEL, __syscall_cancel and __syscall_cancel_arch). As default 6 arguments cancellable syscalls are use. MIPS o32 requires an arch-specific implementation because INTERNAL_SYSCALL_NCS adds an 'addiu' just after the syscall instruction which invalidates the checks on sigcancel_handler. Checked against a build and make check run-built-tests=no for mips-gnu-linux, mips64-linux-gnu, mips64-n32-linux-gnu. I also ran some basic o32 and n64 cancellation tests on a simulated mips64 qemu system. * nptl/libc-cancellation.c (__syscall_cancel): Define and use 7 argument syscall if architecture requires it. * nptl/pthreadP.h (__syscall_cancel_arch): Likewise. * sysdeps/unix/sysdep.h (__syscall_cancel, __SYSCALL_CANCEL*): Define with 7 argument if architecture requires it. (__SYSCALL_CANCEL7_ARG_DEF): New macro. (__SYSCALL_CANCEL7_ARG): Likewise. (__SYSCALL_CANCEL7_ARG7): Likewise. * sysdeps/unix/sysv/linux/syscall_cancel.c (__syscall_cancel_arch): Likewise. * sysdeps/mips/nptl/tls.h (READ_THREAD_POINTER): Check __mips_isa_rev existance for macro definition. * sysdeps/unix/sysv/linux/mips/sigcontextinfo.h (ucontext_get_pc): New function. * sysdeps/unix/sysv/linux/mips/mips32/syscall_cancel.S: New file. * sysdeps/unix/sysv/linux/mips/mips32/sysdep.h (HAVE_CANCELABLE_SYSCALL_WITH_7_ARGS): Define. Signed-off-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> --- ChangeLog | 18 +++ nptl/libc-cancellation.c | 7 +- nptl/pthreadP.h | 3 +- sysdeps/mips/nptl/tls.h | 2 +- sysdeps/unix/sysdep.h | 38 ++++-- .../unix/sysv/linux/mips/mips32/syscall_cancel.S | 128 +++++++++++++++++++++ sysdeps/unix/sysv/linux/mips/mips32/sysdep.h | 4 + sysdeps/unix/sysv/linux/mips/sigcontextinfo.h | 13 ++- sysdeps/unix/sysv/linux/syscall_cancel.c | 6 +- 9 files changed, 203 insertions(+), 16 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/mips/mips32/syscall_cancel.S -- 2.7.4