This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH 05/13] nptl: powerpc64: Fix Race conditions in pthread cancellation (BZ#12683)
- From: Adhemerval Zanella <adhemerval dot zanella at linaro dot org>
- To: libc-alpha at sourceware dot org
- Cc: Adhemerval Zanella <adhemerval dot zanella at linaro dot org>
- Date: Wed, 7 Oct 2015 13:23:07 -0300
- Subject: [PATCH 05/13] nptl: powerpc64: Fix Race conditions in pthread cancellation (BZ#12683)
- Authentication-results: sourceware.org; auth=none
- References: <1444234995-9542-1-git-send-email-adhemerval dot zanella at linaro dot com>
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
This patches adds the powerpc64 modification required for the BZ#12683 fix.
It basically removes the enable_asynccancel/disable_asynccancel function
usage on code used on powerpc64, and provide a arch-specific symbol that
contains global markers to be used in SIGCANCEL handler.
Checked on powerpc64 and powerpc64le.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c (__libc_fnctl):
Remove CANCEL_ASYNC/CANCEL_RESET usage.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO):
Likewise.
(PSEUDO_RET): Likewise.
(__pthread_get_ip): Add implementation.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
(SYSCALL_CANCEL_ERROR): New define.
(SYSCALL_CANCEL_ERRNO): New define.
* sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S: New file:
cancellable syscall.
* sysdeps/unix/sysv/linux/powerpc/sysdep.c (__syscall_cancel_error):
New symbol: cancellable syscall error handler.
---
ChangeLog | 14 +++
sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c | 4 +-
.../sysv/linux/powerpc/powerpc64/sysdep-cancel.h | 137 +++++++--------------
sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h | 9 ++
sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S | 63 ++++++++++
sysdeps/unix/sysv/linux/powerpc/sysdep.c | 11 ++
6 files changed, 141 insertions(+), 97 deletions(-)
create mode 100644 sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
diff --git a/ChangeLog b/ChangeLog
index 303de33..059e20f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
2015-10-07 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c (__libc_fnctl):
+ Remove CANCEL_ASYNC/CANCEL_RESET usage.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO):
+ Likewise.
+ (PSEUDO_RET): Likewise.
+ (__pthread_get_ip): Add implementation.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
+ (SYSCALL_CANCEL_ERROR): New define.
+ (SYSCALL_CANCEL_ERRNO): New define.
+ * sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S: New file:
+ cancellable syscall.
+ * sysdeps/unix/sysv/linux/powerpc/sysdep.c (__syscall_cancel_error):
+ New symbol: cancellable syscall error handler.
+
* nptl/Makefile [routines]: Add syscall_cancel object.
[libpthread-routines]: Remove cancellation object.
(CFLAGS-cancellation.c): Remove -fasynchronous-unwind-tables.
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c
index 69031ba..3a10d16 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c
@@ -23,8 +23,7 @@
#include <sys/syscall.h>
-
-#ifndef NO_CANCELLATION
+#if !IS_IN (rtld)
int
__fcntl_nocancel (int fd, int cmd, ...)
{
@@ -39,7 +38,6 @@ __fcntl_nocancel (int fd, int cmd, ...)
}
#endif
-
int
__libc_fcntl (int fd, int cmd, ...)
{
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
index 5cd7ddb..9381bfc 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
@@ -27,121 +27,70 @@
# define DASHDASHPFX(str) __##str
-#if _CALL_ELF == 2
-#define CANCEL_FRAMESIZE (FRAME_MIN_SIZE+16+48)
-#define CANCEL_PARM_SAVE (FRAME_MIN_SIZE+16)
-#else
-#define CANCEL_FRAMESIZE (FRAME_MIN_SIZE+16)
-#define CANCEL_PARM_SAVE (CANCEL_FRAMESIZE+FRAME_PARM_SAVE)
-#endif
+# if !IS_IN (libc)
+# undef HIDDEN_JUMPTARGET
+# define HIDDEN_JUMPTARGET(__symbol) __symbol
+# endif
+
+#define CANCEL_FRAMESIZE (FRAME_MIN_SIZE)
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.section ".text"; \
ENTRY (name) \
SINGLE_THREAD_P; \
- bne- .Lpseudo_cancel; \
- .type DASHDASHPFX(syscall_name##_nocancel),@function; \
- .globl DASHDASHPFX(syscall_name##_nocancel); \
- DASHDASHPFX(syscall_name##_nocancel): \
+ bne- L(pseudo_cancel); \
DO_CALL (SYS_ify (syscall_name)); \
- PSEUDO_RET; \
- .size DASHDASHPFX(syscall_name##_nocancel),.-DASHDASHPFX(syscall_name##_nocancel); \
- .Lpseudo_cancel: \
- stdu 1,-CANCEL_FRAMESIZE(1); \
- cfi_adjust_cfa_offset (CANCEL_FRAMESIZE); \
- mflr 9; \
- std 9,CANCEL_FRAMESIZE+FRAME_LR_SAVE(1); \
+ bnslr+; \
+ TAIL_CALL_SYSCALL_ERROR; \
+ L(pseudo_cancel): \
+ mflr r0; \
+ std r0,FRAME_LR_SAVE(r1); \
cfi_offset (lr, FRAME_LR_SAVE); \
- DOCARGS_##args; /* save syscall args around CENABLE. */ \
- CENABLE; \
- std 3,FRAME_MIN_SIZE(1); /* store CENABLE return value (MASK). */ \
- UNDOCARGS_##args; /* restore syscall args. */ \
- DO_CALL (SYS_ify (syscall_name)); \
- mfcr 0; /* save CR/R3 around CDISABLE. */ \
- std 3,FRAME_MIN_SIZE+8(1); \
- std 0,CANCEL_FRAMESIZE+FRAME_CR_SAVE(1); \
- cfi_offset (cr, FRAME_CR_SAVE); \
- ld 3,FRAME_MIN_SIZE(1); /* pass MASK to CDISABLE. */ \
- CDISABLE; \
- ld 9,CANCEL_FRAMESIZE+FRAME_LR_SAVE(1); \
- ld 0,CANCEL_FRAMESIZE+FRAME_CR_SAVE(1); /* restore CR/R3. */ \
- ld 3,FRAME_MIN_SIZE+8(1); \
- mtlr 9; \
- mtcr 0; \
- addi 1,1,CANCEL_FRAMESIZE; \
+ stdu r1,-CANCEL_FRAMESIZE(r1); \
+ cfi_adjust_cfa_offset (CANCEL_FRAMESIZE); \
+ mr r9,r8; \
+ mr r8,r7; \
+ mr r7,r6; \
+ mr r6,r5; \
+ mr r5,r4; \
+ mr r4,r3; \
+ li r3,SYS_ify (syscall_name); \
+ bl HIDDEN_JUMPTARGET(__syscall_cancel); \
+ nop; \
+ bl JUMPTARGET(__syscall_cancel_error); \
+ nop; \
+ addi r1,r1,CANCEL_FRAMESIZE; \
cfi_adjust_cfa_offset (-CANCEL_FRAMESIZE); \
+ ld r0,FRAME_LR_SAVE(r1); \
+ mtlr r0; \
cfi_restore (lr); \
- cfi_restore (cr)
-
-# define DOCARGS_0
-# define UNDOCARGS_0
-
-# define DOCARGS_1 std 3,CANCEL_PARM_SAVE(1); DOCARGS_0
-# define UNDOCARGS_1 ld 3,CANCEL_PARM_SAVE(1); UNDOCARGS_0
-
-# define DOCARGS_2 std 4,CANCEL_PARM_SAVE+8(1); DOCARGS_1
-# define UNDOCARGS_2 ld 4,CANCEL_PARM_SAVE+8(1); UNDOCARGS_1
-
-# define DOCARGS_3 std 5,CANCEL_PARM_SAVE+16(1); DOCARGS_2
-# define UNDOCARGS_3 ld 5,CANCEL_PARM_SAVE+16(1); UNDOCARGS_2
+ blr
-# define DOCARGS_4 std 6,CANCEL_PARM_SAVE+24(1); DOCARGS_3
-# define UNDOCARGS_4 ld 6,CANCEL_PARM_SAVE+24(1); UNDOCARGS_3
-
-# define DOCARGS_5 std 7,CANCEL_PARM_SAVE+32(1); DOCARGS_4
-# define UNDOCARGS_5 ld 7,CANCEL_PARM_SAVE+32(1); UNDOCARGS_4
-
-# define DOCARGS_6 std 8,CANCEL_PARM_SAVE+40(1); DOCARGS_5
-# define UNDOCARGS_6 ld 8,CANCEL_PARM_SAVE+40(1); UNDOCARGS_5
-
-# if IS_IN (libpthread)
-# ifdef SHARED
-# define CENABLE bl JUMPTARGET(__pthread_enable_asynccancel)
-# define CDISABLE bl JUMPTARGET(__pthread_disable_asynccancel)
-# else
-# define CENABLE bl JUMPTARGET(__pthread_enable_asynccancel); nop
-# define CDISABLE bl JUMPTARGET(__pthread_disable_asynccancel); nop
-# endif
-# elif IS_IN (libc)
-# ifdef SHARED
-# define CENABLE bl JUMPTARGET(__libc_enable_asynccancel)
-# define CDISABLE bl JUMPTARGET(__libc_disable_asynccancel)
-# else
-# define CENABLE bl JUMPTARGET(__libc_enable_asynccancel); nop
-# define CDISABLE bl JUMPTARGET(__libc_disable_asynccancel); nop
-# endif
-# elif IS_IN (librt)
-# ifdef SHARED
-# define CENABLE bl JUMPTARGET(__librt_enable_asynccancel)
-# define CDISABLE bl JUMPTARGET(__librt_disable_asynccancel)
-# else
-# define CENABLE bl JUMPTARGET(__librt_enable_asynccancel); nop
-# define CDISABLE bl JUMPTARGET(__librt_disable_asynccancel); nop
-# endif
-# else
-# error Unsupported library
-# endif
+# undef PSEUDO_RET
+# define PSEUDO_RET
# ifndef __ASSEMBLER__
-# define SINGLE_THREAD_P \
- __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
- header.multiple_threads) == 0, 1)
+# define SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
# else
-# define SINGLE_THREAD_P \
- lwz 10,MULTIPLE_THREADS_OFFSET(13); \
+# define SINGLE_THREAD_P \
+ lwz 10,MULTIPLE_THREADS_OFFSET(13); \
cmpwi 10,0
# endif
-#elif !defined __ASSEMBLER__
-
-# define SINGLE_THREAD_P (1)
-# define NO_CANCELLATION 1
-
#endif
#ifndef __ASSEMBLER__
# define RTLD_SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
+
+static inline
+const char * __pthread_get_ip (const ucontext_t *uc)
+{
+ return (char *)uc->uc_mcontext.gp_regs[PT_NIP];
+}
+
#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
index e2014cc..8a941f81 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
@@ -131,6 +131,15 @@
sc_ret; \
})
+#undef SYSCALL_CANCEL_ERROR
+#define SYSCALL_CANCEL_ERROR(err) \
+ (err > 0xfffffffffffff000UL)
+
+#undef SYSCALL_CANCEL_ERRNO
+#define SYSCALL_CANCEL_ERRNO(err) \
+ (-err)
+
+
/* Define a macro which expands inline into the wrapper code for a system
call. This use is for internal calls that do not need to handle errors
normally. It will never touch errno. This returns just what the kernel
diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S b/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
new file mode 100644
index 0000000..c7068d3
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
@@ -0,0 +1,63 @@
+/* Cancellable syscall wrapper - powerpc version.
+ Copyright (C) 2014 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>
+
+/* long int [r3] __syscall_cancel_arch (int *cancelhandling [r3],
+ long int nr [r4],
+ long int arg1 [r5],
+ long int arg2 [r6],
+ long int arg3 [r7],
+ long int arg4 [r8],
+ long int arg5 [r9],
+ long int arg6 [r10]) */
+
+ENTRY (__syscall_cancel_arch)
+
+ .globl __syscall_cancel_arch_start
+ .type __syscall_cancel_arch_start,@function
+__syscall_cancel_arch_start:
+
+ /* if (*cancelhandling & CANCELED_BITMASK)
+ __syscall_do_cancel() */
+ lwz r0,0(r3)
+ rldicl. r0,r0,62,63
+ beq 1f
+ b __syscall_do_cancel
+ nop
+1:
+ /* Issue a 6 argument syscall, the nr [r4] being the syscall
+ number. */
+ mr r0,r4
+ mr r3,r5
+ mr r4,r6
+ mr r5,r7
+ mr r6,r8
+ mr r7,r9
+ mr r8,r10
+ sc
+
+ .globl __syscall_cancel_arch_end
+ .type __syscall_cancel_arch_end,@function
+__syscall_cancel_arch_end:
+
+ bnslr+
+ neg r3,r3
+ blr
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
diff --git a/sysdeps/unix/sysv/linux/powerpc/sysdep.c b/sysdeps/unix/sysv/linux/powerpc/sysdep.c
index 6dc6737..8d58fd0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/sysdep.c
+++ b/sysdeps/unix/sysv/linux/powerpc/sysdep.c
@@ -26,3 +26,14 @@ __syscall_error (int err_no)
__set_errno (err_no);
return -1;
}
+
+long int
+__syscall_cancel_error (unsigned long err)
+{
+ if (__glibc_unlikely ((err) & (1 << 28)))
+ {
+ __set_errno (-err);
+ return -1;
+ }
+ return err;
+}
--
1.9.1