diff mbox

[8/8] nptl: ppc32: Fix Race conditions in pthread cancellation, (BZ#12683)

Message ID 5435AD8E.7080801@linux.vnet.ibm.com
State Dropped
Headers show

Commit Message

Adhemerval Zanella Netto Oct. 8, 2014, 9:33 p.m. UTC
This patches adds the ppc32 modification required for the BZ#12683
fix.

--

	* sysdeps/powerpc/nptl/pthreaddef.h (__pthread_get_ip): Add powerpc32
	support.
	* sysdeps/unix/sysv/linux/i386/fcntl.c (__fcntl_nocancel): Remove calls
	to enable/disable asynchronous cancellation and use call cancellable
	syscall entrypoint when required.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/socket.S (__socket):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
	[SYSCALL_CANCEL_ERROR]: New macro.
	[SYSCALL_CANCEL_ERRNO]: New macro.

---
diff mbox

Patch

diff --git a/sysdeps/powerpc/nptl/pthreaddef.h b/sysdeps/powerpc/nptl/pthreaddef.h
index 5fe1cdb..5402154 100644
--- a/sysdeps/powerpc/nptl/pthreaddef.h
+++ b/sysdeps/powerpc/nptl/pthreaddef.h
@@ -38,7 +38,11 @@ 
 static inline
 const char * __pthread_get_ip (const ucontext_t *uc)
 {
+# ifdef __powerpc64__
   return (char *)uc->uc_mcontext.gp_regs[PT_NIP];
+# else
+  return (char *)uc->uc_mcontext.uc_regs->gregs[PT_NIP];
+# endif
 }
 
 #endif
diff --git a/sysdeps/unix/sysv/linux/i386/fcntl.c b/sysdeps/unix/sysv/linux/i386/fcntl.c
index 570ed4d..b59aa5b 100644
--- a/sysdeps/unix/sysv/linux/i386/fcntl.c
+++ b/sysdeps/unix/sysv/linux/i386/fcntl.c
@@ -23,7 +23,7 @@ 
 
 #include <sys/syscall.h>
 
-#ifndef NO_CANCELLATION
+#ifndef IS_IN_rtld
 int
 __fcntl_nocancel (int fd, int cmd, ...)
 {
@@ -36,7 +36,7 @@  __fcntl_nocancel (int fd, int cmd, ...)
 
   return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
 }
-#endif /* NO_CANCELLATION */
+#endif
 
 
 int
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/socket.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/socket.S
index 2261484..787d53c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/socket.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/socket.S
@@ -40,7 +40,7 @@ 
 
 /* 0(r1) and 4(r1) are reserved by the ABI, 8(r1), 12(r1), 16(r1) are used
    for temp saves.  44(r1) is used to save r30.  */
-#define stackblock 20
+#define STACKBLOCK 20
 
 #ifndef __socket
 # ifndef NO_WEAK_ALIAS
@@ -55,63 +55,58 @@  ENTRY(__socket)
 	stwu r1,-48(r1)
 	cfi_adjust_cfa_offset(48)
 #if NARGS >= 1
-	stw  r3,stackblock(r1)
+	stw  r3,STACKBLOCK(r1)
 #endif
 #if NARGS >= 2
-	stw  r4,4+stackblock(r1)
+	stw  r4,4+STACKBLOCK(r1)
 #endif
 #if NARGS >= 3
-	stw  r5,8+stackblock(r1)
+	stw  r5,8+STACKBLOCK(r1)
 #endif
 #if NARGS >= 4
-	stw  r6,12+stackblock(r1)
+	stw  r6,12+STACKBLOCK(r1)
 #endif
 #if NARGS >= 5
-	stw  r7,16+stackblock(r1)
+	stw  r7,16+STACKBLOCK(r1)
 #endif
 #if NARGS >= 6
-	stw  r8,20+stackblock(r1)
+	stw  r8,20+STACKBLOCK(r1)
 #endif
 #if NARGS >= 7
 #error too many arguments!
 #endif
 
-#if defined NEED_CANCELLATION && defined CENABLE
+#ifdef NEED_CANCELLATION
 	SINGLE_THREAD_P
-	bne-	.Lsocket_cancel
+	bne-	L(socket_cancel)
 #endif
 
-	li	r3,P(SOCKOP_,socket)
-	addi	r4,r1,stackblock
-	DO_CALL(SYS_ify(socketcall))
-	addi	r1,r1,48
-	PSEUDO_RET
-
-#if defined NEED_CANCELLATION && defined CENABLE
-.Lsocket_cancel:
+#ifndef NEED_CANCELLATION
+        li      r3,P(SOCKOP_,socket)
+        addi    r4,r1,STACKBLOCK
+        DO_CALL(SYS_ify(socketcall))
+        addi    r1,r1,48
+	bnslr+
+	b	__syscall_error@local
+#else
+L(socket_cancel):
 	mflr	r9
+	SETUP_PIC;
 	stw	r9,52(r1)
 	cfi_offset (lr, 4)
-	CENABLE
-	stw	r3,16(r1)
-	li	r3,P(SOCKOP_,socket)
-	addi	r4,r1,stackblock
-	DO_CALL(SYS_ify(socketcall))
-	mfcr	r0
-	stw	r3,8(r1)
-	stw	r0,12(r1)
-	lwz	r3,16(r1)
-	CDISABLE
-	lwz	r4,52(r1)
-	lwz	r0,12(r1)
-	lwz	r3,8(r1)
-	mtlr	r4
-	mtcr	r0
+
+	li	r3,SYS_ify(socketcall)
+	li	r4,P(SOCKOP_,socket)
+	addi	r5,r1,STACKBLOCK
+	CANCEL_JUMPTARGET
+	lwz	r9,52(r1)
 	addi	r1,r1,48
-	PSEUDO_RET
+	cfi_adjust_cfa_offset(-48)
+	mtlr	r9
+	cfi_restore(lr)
+	b	__syscall_cancel_error@local;
 #endif
-
-PSEUDO_END (__socket)
+END (__socket)
 
 #ifndef NO_WEAK_ALIAS
 weak_alias (__socket, socket)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
index b6eedcb..4015d998 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
@@ -25,90 +25,73 @@ 
 
 #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
 
+# ifdef NOT_IN_libc
+#  define SETUP_PIC							\
+    bcl     20,31,got_label;						\
+got_label:
+
+#  define CANCEL_JUMPTARGET						\
+    stw   r30,8(r1);							\
+    mflr  r30;								\
+    addis r30,r30,_GLOBAL_OFFSET_TABLE_-got_label@ha;			\
+    addi  r30,r30,_GLOBAL_OFFSET_TABLE_-got_label@l;			\
+    bl    __syscall_cancel@plt;						\
+    lwz   r30,8(r1)
+# else
+#  define SETUP_PIC
+#  if defined SHARED && defined PIC
+#   define CANCEL_JUMPTARGET						\
+    bl    __GI___syscall_cancel@locaL
+#  else
+#   define CANCEL_JUMPTARGET						\
+    bl    __syscall_cancel
+#  endif
+# endif
+
 # undef PSEUDO
 # define PSEUDO(name, syscall_name, args)				\
   .section ".text";							\
   ENTRY (name)								\
     SINGLE_THREAD_P;							\
-    bne- .Lpseudo_cancel;						\
-  .type __##syscall_name##_nocancel,@function;				\
-  .globl __##syscall_name##_nocancel;					\
-  __##syscall_name##_nocancel:						\
+    bne- L(pseudo_cancel);						\
     DO_CALL (SYS_ify (syscall_name));					\
-    PSEUDO_RET;								\
-  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	\
-  .Lpseudo_cancel:							\
-    stwu 1,-48(1);							\
-    cfi_adjust_cfa_offset (48);						\
-    mflr 9;								\
-    stw 9,52(1);							\
+    bnslr+;								\
+    b __syscall_error@local;						\
+  L(pseudo_cancel):							\
+    stwu r1,-16(r1);							\
+    cfi_adjust_cfa_offset (16);						\
+    mflr r0;								\
+    SETUP_PIC;								\
+    stw  r0,20(r1);							\
     cfi_offset (lr, 4);							\
-    DOCARGS_##args;	/* save syscall args around CENABLE.  */	\
-    CENABLE;								\
-    stw 3,16(1);	/* store CENABLE return value (MASK).  */	\
-    UNDOCARGS_##args;	/* restore syscall args.  */			\
-    DO_CALL (SYS_ify (syscall_name));					\
-    mfcr 0;		/* save CR/R3 around CDISABLE.  */		\
-    stw 3,8(1);								\
-    stw 0,12(1);							\
-    lwz 3,16(1);	/* pass MASK to CDISABLE.  */			\
-    CDISABLE;								\
-    lwz 4,52(1);							\
-    lwz 0,12(1);	/* restore CR/R3. */				\
-    lwz 3,8(1);								\
-    mtlr 4;								\
-    mtcr 0;								\
-    addi 1,1,48;
-
-# define DOCARGS_0
-# define UNDOCARGS_0
-
-# define DOCARGS_1	stw 3,20(1); DOCARGS_0
-# define UNDOCARGS_1	lwz 3,20(1); UNDOCARGS_0
-
-# define DOCARGS_2	stw 4,24(1); DOCARGS_1
-# define UNDOCARGS_2	lwz 4,24(1); UNDOCARGS_1
-
-# define DOCARGS_3	stw 5,28(1); DOCARGS_2
-# define UNDOCARGS_3	lwz 5,28(1); UNDOCARGS_2
-
-# define DOCARGS_4	stw 6,32(1); DOCARGS_3
-# define UNDOCARGS_4	lwz 6,32(1); UNDOCARGS_3
-
-# define DOCARGS_5	stw 7,36(1); DOCARGS_4
-# define UNDOCARGS_5	lwz 7,36(1); UNDOCARGS_4
-
-# define DOCARGS_6	stw 8,40(1); DOCARGS_5
-# define UNDOCARGS_6	lwz 8,40(1); UNDOCARGS_5
-
-# ifdef IS_IN_libpthread
-#  define CENABLE	bl __pthread_enable_asynccancel@local
-#  define CDISABLE	bl __pthread_disable_asynccancel@local
-# elif !defined NOT_IN_libc
-#  define CENABLE	bl __libc_enable_asynccancel@local
-#  define CDISABLE	bl __libc_disable_asynccancel@local
-# elif defined IS_IN_librt
-#  define CENABLE	bl __librt_enable_asynccancel@local
-#  define CDISABLE	bl __librt_disable_asynccancel@local
-# else
-#  error Unsupported library
-# endif
+    mr   r9,r8;								\
+    mr   r8,r7;								\
+    mr   r7,r6;								\
+    mr   r6,r5;								\
+    mr   r5,r4;								\
+    mr   r4,r3;								\
+    li   r3,SYS_ify (syscall_name);					\
+    CANCEL_JUMPTARGET;							\
+    lwz  r0,20(r1);							\
+    addi r1,r1,16;							\
+    cfi_adjust_cfa_offset (-16);					\
+    mtlr r0;								\
+    cfi_restore (lr);							\
+    b    __syscall_cancel_error@local;
+
+# 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(2);					\
+#  define SINGLE_THREAD_P                                               \
+  lwz 10,MULTIPLE_THREADS_OFFSET(2);                                    \
   cmpwi 10,0
 # endif
 
-#elif !defined __ASSEMBLER__
-
-# define SINGLE_THREAD_P (1)
-# define NO_CANCELLATION 1
-
 #endif
 
 #ifndef __ASSEMBLER__
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
index 1a5e37a..7701d66 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
@@ -168,6 +168,14 @@ 
     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.