diff mbox

[12/13] nptl: s390: Fix Race conditions in pthread cancellation (BZ#12683)

Message ID 1444234995-9542-13-git-send-email-adhemerval.zanella@linaro.com
State New
Headers show

Commit Message

Adhemerval Zanella Netto Oct. 7, 2015, 4:23 p.m. UTC
This patch adds the s390 modifications required for the BZ#12683 fix.
It basically removes the enable_asynccancel/disable_asynccancel function
usage on code, provide a arch-specific symbol that contains global
markers to be used in SIGCANCEL handler.

Checked on s390 (thanks to Stefan Liebler <stli@linux.vnet.ibm.com>).

    * sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S: New file.
    * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Redefine
    to call __syscall_cancel function for cancellable syscalls.
    (__pthread_get_ip): Add implementation.
    * sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h (SYSCALL_CANCEL_ERROR): Add
    definition.
    (SYSCALL_CANCEL_ERRNO): Likewise.
---
 ChangeLog                                          |  11 ++
 .../unix/sysv/linux/s390/s390-32/syscall_cancel.S  |  85 ++++++++++++++
 .../unix/sysv/linux/s390/s390-32/sysdep-cancel.h   | 128 ++++++++++-----------
 sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h      |   8 ++
 4 files changed, 168 insertions(+), 64 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S
diff mbox

Patch

diff --git a/ChangeLog b/ChangeLog
index f922fa0..cdb4190 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,15 @@ 
 2015-10-07  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+	    Stefan Liebler  <stli@linux.vnet.ibm.com>
+
+	* sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S: New file.
+	* sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Redefine
+	to call __syscall_cancel function for cancellable syscalls.
+	(__pthread_get_ip): Add implementation.
+	* sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h (SYSCALL_CANCEL_ERROR): Add
+	definition.
+	(SYSCALL_CANCEL_ERRNO): Likewise.
+
+2015-10-07  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
 
 	* sysdeps/unix/sysv/linux/arm/syscall_cancel.S: New file.
 	* sysdeps/unix/sysv/linux/arm/sysdep-cancel.h (PSEUDO): Redefine
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S b/sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S
new file mode 100644
index 0000000..bf90acd
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S
@@ -0,0 +1,85 @@ 
+/* Cancellable syscall wrapper - s390 version.
+   Copyright (C) 2015 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 [r2] __syscall_cancel_arch (int *cancelhandling [r2],
+					long int nr   [r3],
+					long int arg1 [r4],
+					long int arg2 [r5],
+					long int arg3 [r6],
+					long int arg4 [SP+96],
+					long int arg5 [SP+100],
+					long int arg6 [SP+104])  */
+
+ENTRY (__syscall_cancel_arch)
+	/* Save registers and setup stack.  */
+	stm     %r6,%r15,24(%r15)	/* Save registers */
+	cfi_offset (%r15, -36)
+	cfi_offset (%r14, -40)
+	cfi_offset (%r13, -44)
+	cfi_offset (%r12, -48)
+	cfi_offset (%r11, -52)
+	cfi_offset (%r10, -56)
+	cfi_offset (%r9, -60)
+	cfi_offset (%r8, -64)
+	cfi_offset (%r7, -68)
+	cfi_offset (%r6, -72)
+	lr      %r1,%r15
+	l       %r0,4(0,%r15)		/* Load eos */
+	ahi     %r15,-96		/* Buy stack space */
+	cfi_adjust_cfa_offset (96)
+	st      %r1,0(0,%r15)		/* Store back chain */
+	st      %r0,4(0,%r15)		/* Store eos */
+
+	.globl __syscall_cancel_arch_start
+	.type  __syscall_cancel_arch_start,@function
+__syscall_cancel_arch_start:
+
+	/* if (*cancelhandling & CANCELED_BITMASK)
+	     __syscall_do_cancel()  */
+	tm	3(%r2),4
+	jne	1f
+
+	/* Issue a 6 argument syscall  */
+	lr	%r1,%r3			/* Move syscall number.  */
+	lr	%r2,%r4			/* First parameter.  */
+	lr	%r3,%r5			/* Second parameter.  */
+	lr	%r4,%r6			/* Third parameter.  */
+	l	%r5,192(%r15)		/* Fourth parameter.  */
+	l	%r6,196(%r15)		/* Fifth parameter.  */
+	l	%r7,200(%r15)		/* Sixth parameter.  */
+
+	svc	0			/* svc number is always in r1.  */
+	.globl __syscall_cancel_arch_end
+	.type  __syscall_cancel_arch_end,@function
+__syscall_cancel_arch_end:
+	l	%r15,0(%r15)		/* Load back chain.  */
+	cfi_adjust_cfa_offset (-96)
+	lm	%r6,15,24(%r15)		/* Load registers.  */
+
+	br	%r14
+
+	/* Branch to __syscall_do_cancel  */
+1:
+	l	%r15,0(%r15)		/* Load back chain.  */
+	cfi_adjust_cfa_offset (-96)
+	lm	%r6,%r15,24(%r15)	/* Load registers.  */
+	jg	__syscall_do_cancel
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
index 17b7aaa..1ed57f0 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
@@ -24,97 +24,90 @@ 
 
 #if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt)
 
+# if IS_IN (libc)
+#  define PREPARE_CALL
+#  define PREPARE_GOT
+#  define JMP_SYSCALL_CANCEL HIDDEN_JUMPTARGET(__syscall_cancel)
+# else
+#  define PREPARE_CALL l %r12,2f-0b(%r13);			\
+  la %r12,0(%r12,%r13);
+#  define PREPARE_GOT 2: .long _GLOBAL_OFFSET_TABLE_-0b;
+#  define JMP_SYSCALL_CANCEL __syscall_cancel@plt
+# endif
+
+# define STORE_0 /* Nothing */
+# define STORE_1 /* Nothing */
+# define STORE_2 /* Nothing */
+# define STORE_3 /* Nothing */
+# define STORE_4 st %r6,24(%r15);		\
+ cfi_offset (%r6,-72);
+# define STORE_5 STORE_4
+# define STORE_6 STORE_4
+
+# define LOAD_0 /* Nothing */
+# define LOAD_1 /* Nothing */
+# define LOAD_2 /* Nothing */
+# define LOAD_3 /* Nothing */
+# define LOAD_4 l %r6,24(%r15);
+# define LOAD_5 LOAD_4
+# define LOAD_6 LOAD_4
+
+# define MOVE_ARGS_0
+# define MOVE_ARGS_1 lr %r3,%r2;		\
+	 MOVE_ARGS_0
+# define MOVE_ARGS_2 lr %r4,%r3;		\
+	 MOVE_ARGS_1
+# define MOVE_ARGS_3 lr %r5,%r4;		\
+	 MOVE_ARGS_2
+# define MOVE_ARGS_4 lr %r6,%r5;		\
+	 MOVE_ARGS_3
+# define MOVE_ARGS_5 st %r6,96(%r15);		\
+	 MOVE_ARGS_4
+# define MOVE_ARGS_6 l %r14,96(%r14);		\
+	 st %r14,100(%r15);			\
+	 MOVE_ARGS_5
+
 # undef PSEUDO
 # define PSEUDO(name, syscall_name, args)				      \
 	.text;								      \
 L(pseudo_cancel):							      \
 	cfi_startproc;							      \
-	STM_##args							      \
 	stm	%r12,%r15,48(%r15);					      \
 	cfi_offset (%r15, -36);						      \
 	cfi_offset (%r14, -40);						      \
 	cfi_offset (%r13, -44);						      \
 	cfi_offset (%r12, -48);						      \
+	STORE_##args							      \
 	lr	%r14,%r15;						      \
-	ahi	%r15,-96;						      \
-	cfi_adjust_cfa_offset (96);					      \
+	ahi	%r15,-104;						      \
+	cfi_adjust_cfa_offset (104);					      \
 	st	%r14,0(%r15);						      \
+	MOVE_ARGS_##args						      \
+	lhi	%r2,SYS_ify (syscall_name);				      \
 	basr    %r13,0;							      \
 0:	l	%r1,1f-0b(%r13);					      \
+	PREPARE_CALL							      \
 	bas	%r14,0(%r1,%r13);					      \
-	lr	%r0,%r2;						      \
-	LM_##args							      \
-	.if SYS_ify (syscall_name) < 256;				      \
-	svc SYS_ify (syscall_name);					      \
-	.else;								      \
-	lhi %r1,SYS_ify (syscall_name);					      \
-	svc 0;								      \
-	.endif;								      \
-	LR7_##args							      \
-	l	%r1,2f-0b(%r13);					      \
-	lr	%r12,%r2;						      \
-	lr	%r2,%r0;						      \
-	bas	%r14,0(%r1,%r13);					      \
-	lr	%r2,%r12;						      \
-	lm	%r12,%r15,48+96(%r15);					      \
+	lm	%r12,%r15,48+104(%r15);					      \
+	cfi_restore (%r12);						      \
+	cfi_restore (%r13);						      \
+	cfi_restore (%r14);						      \
+	cfi_restore (%r15);						      \
+	LOAD_##args							      \
 	cfi_endproc;							      \
 	j	L(pseudo_check);					      \
-1:	.long	CENABLE-0b;						      \
-2:	.long	CDISABLE-0b;						      \
+1:	.long	JMP_SYSCALL_CANCEL-0b;					      \
+	PREPARE_GOT							      \
 ENTRY(name)								      \
 	SINGLE_THREAD_P(%r1)						      \
 	jne	L(pseudo_cancel);					      \
-.type	__##syscall_name##_nocancel,@function;				      \
-.globl	__##syscall_name##_nocancel;					      \
-__##syscall_name##_nocancel:						      \
 	DO_CALL(syscall_name, args);					      \
 L(pseudo_check):							      \
 	lhi	%r4,-4095;						      \
 	clr	%r2,%r4;						      \
 	jnl	SYSCALL_ERROR_LABEL;					      \
-.size	__##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \
 L(pseudo_end):
 
-# if IS_IN (libpthread)
-#  define CENABLE	__pthread_enable_asynccancel
-#  define CDISABLE	__pthread_disable_asynccancel
-# elif IS_IN (libc)
-#  define CENABLE	__libc_enable_asynccancel
-#  define CDISABLE	__libc_disable_asynccancel
-# elif IS_IN (librt)
-#  define CENABLE	__librt_enable_asynccancel
-#  define CDISABLE	__librt_disable_asynccancel
-# else
-#  error Unsupported library
-# endif
-
-#define STM_0		/* Nothing */
-#define STM_1		st %r2,8(%r15);
-#define STM_2		stm %r2,%r3,8(%r15);
-#define STM_3		stm %r2,%r4,8(%r15);
-#define STM_4		stm %r2,%r5,8(%r15);
-#define STM_5		stm %r2,%r5,8(%r15);
-#define STM_6		stm %r2,%r7,8(%r15);
-
-#define LM_0		/* Nothing */
-#define LM_1		l %r2,8+96(%r15);
-#define LM_2		lm %r2,%r3,8+96(%r15);
-#define LM_3		lm %r2,%r4,8+96(%r15);
-#define LM_4		lm %r2,%r5,8+96(%r15);
-#define LM_5		lm %r2,%r5,8+96(%r15);
-#define LM_6		lm %r2,%r5,8+96(%r15); \
-			cfi_offset (%r7, -68); \
-			l %r7,96+96(%r15);
-
-#define LR7_0		/* Nothing */
-#define LR7_1		/* Nothing */
-#define LR7_2		/* Nothing */
-#define LR7_3		/* Nothing */
-#define LR7_4		/* Nothing */
-#define LR7_5		/* Nothing */
-#define LR7_6		l %r7,28+96(%r15); \
-			cfi_restore (%r7);
-
 # ifndef __ASSEMBLER__
 #  define SINGLE_THREAD_P \
   __builtin_expect (THREAD_GETMEM (THREAD_SELF,				      \
@@ -136,4 +129,11 @@  L(pseudo_end):
 # define RTLD_SINGLE_THREAD_P \
   __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
 				   header.multiple_threads) == 0, 1)
+
+static inline
+long int __pthread_get_ip (const struct ucontext *uc)
+{
+  /* We have 31bit addresses, remove bit 0.  */
+  return uc->uc_mcontext.psw.addr & 0x7FFFFFFF;
+}
 #endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h
index c768df1..08e2be4 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h
@@ -243,6 +243,14 @@ 
 #undef INTERNAL_SYSCALL_ERRNO
 #define INTERNAL_SYSCALL_ERRNO(val, err)	(-(val))
 
+#undef SYSCALL_CANCEL_ERROR
+#define SYSCALL_CANCEL_ERROR(__val) \
+  ((unsigned int) (__val) >= 0xfffff001u)
+
+#undef SYSCALL_CANCEL_ERRNO
+#define SYSCALL_CANCEL_ERRNO(__val) \
+  (-(__val))
+
 #define DECLARGS_0()
 #define DECLARGS_1(arg1) \
 	register unsigned long gpr2 asm ("2") = (unsigned long)(arg1);