[6/7] nptl: x86_64: Fix Race conditions in pthread cancellation, (BZ#12683)

Message ID 5425C34F.5070703@linux.vnet.ibm.com
State Superseded
Headers

Commit Message

Adhemerval Zanella Netto Sept. 26, 2014, 7:49 p.m. UTC
  This patches adds the x86_64 modification required for the BZ#12683 fix.
It basically removes the enable_asynccancel/disable_asynccancel function
usage on code used on x86_64, provide a arch-specific symbol that
contains global markers to be used in SIGCANCEL handler, and remove
x86_64 assembly pthread conditional and semaphore code to use default
one (that already contains the cancel call fixes).

Tested on x86_64 and powerpc64.

--

	* sysdeps/unix/sysv/linux/fcntl.c (__fcntl_nocancel): Rewrite to use
	new cancellation mechanism.
	* sysdeps/unix/sysv/linux/x86_64/cancellation.S: Remove file.
	* sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S: Remove file.
	* sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S: Remove file.
	* sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
	(lll_futex_wait_cancel): New define: cancellable futex wait
	call.
	(lll_futex_wake_unlock): New define: futex wake unlock call.
	(lll_wait_tid): Using cancellable futex wait call.
	* sysdeps/unix/sysv/linux/x86_64/recv.c (__libc_recv): Remove calls
	to enable/disable asynchronous cancellation and use call to
	cancellable syscall entrypoint when required.
	* sysdeps/unix/sysv/linux/x86_64/send.c (__libc_send): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (PSEUDO): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S: New file:
	cancellable syscall entrypoint.
	* sysdeps/unix/sysv/linux/x86_64/sysdep.h (SYSCALL_CANCEL_ERROR): New
	define.
	(SYSCALL_CANCEL_ERRNO): New define.
	* sysdeps/x64_64/nptl/pthreaddef.h (__pthread_get_ip): New
	function:
	return ucontext_t instruction point address.
	* sysdeps/x86_64/nptl/tcb-offsets.sym [TCB_CANCELING_BITMASK]:
	Remove.
	* sysdeps/x86_64/nptl/tls.h (THREAD_ATOMIC_BIT_SET): Remove
	define.

---
  

Patch

diff --git a/sysdeps/unix/sysv/linux/fcntl.c b/sysdeps/unix/sysv/linux/fcntl.c
index c1d33da..6b095c8 100644
--- a/sysdeps/unix/sysv/linux/fcntl.c
+++ b/sysdeps/unix/sysv/linux/fcntl.c
@@ -23,9 +23,8 @@ 
 
 #include <sys/syscall.h>
 
-
-static int
-do_fcntl (int fd, int cmd, void *arg)
+static inline int
+__fcntl_common_nocancel (int fd, int cmd, void *arg)
 {
   if (cmd != F_GETOWN)
     return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
@@ -40,8 +39,22 @@  do_fcntl (int fd, int cmd, void *arg)
   return -1;
 }
 
+static inline int
+__fcntl_common_cancel (int fd, int cmd, void *arg)
+{
+  if (cmd != F_GETOWN)
+    return SYSCALL_CANCEL (fcntl, fd, cmd, arg);
 
-#ifndef NO_CANCELLATION
+  struct f_owner_ex fex;
+  int res = SYSCALL_CANCEL_NCS (fcntl, fd, F_GETOWN_EX, &fex);
+  if (!SYSCALL_CANCEL_ERROR (res))
+    return fex.type == F_OWNER_GID ? -fex.pid : fex.pid;
+
+  __set_errno (SYSCALL_CANCEL_ERRNO (res));
+  return -1;
+}
+
+#ifndef IS_IN_rtld
 int
 __fcntl_nocancel (int fd, int cmd, ...)
 {
@@ -52,11 +65,10 @@  __fcntl_nocancel (int fd, int cmd, ...)
   arg = va_arg (ap, void *);
   va_end (ap);
 
-  return do_fcntl (fd, cmd, arg);
+  return __fcntl_common_nocancel (fd, cmd, arg);
 }
 #endif
 
-
 int
 __libc_fcntl (int fd, int cmd, ...)
 {
@@ -67,16 +79,10 @@  __libc_fcntl (int fd, int cmd, ...)
   arg = va_arg (ap, void *);
   va_end (ap);
 
-  if (SINGLE_THREAD_P || cmd != F_SETLKW)
-    return do_fcntl (fd, cmd, arg);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = do_fcntl (fd, cmd, arg);
-
-  LIBC_CANCEL_RESET (oldtype);
+  if (cmd != F_SETLKW)
+    return __fcntl_common_nocancel (fd, cmd, arg);
 
-  return result;
+  return __fcntl_common_cancel (fd, cmd, arg);
 }
 libc_hidden_def (__libc_fcntl)
 
diff --git a/sysdeps/unix/sysv/linux/x86_64/cancellation.S b/sysdeps/unix/sysv/linux/x86_64/cancellation.S
deleted file mode 100644
index 89fda5e..0000000
--- a/sysdeps/unix/sysv/linux/x86_64/cancellation.S
+++ /dev/null
@@ -1,117 +0,0 @@ 
-/* Copyright (C) 2009-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
-
-   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 <tcb-offsets.h>
-#include <kernel-features.h>
-#include "lowlevellock.h"
-
-#ifdef IS_IN_libpthread
-# if defined SHARED && !defined NO_HIDDEN
-#  define __pthread_unwind __GI___pthread_unwind
-# endif
-#else
-# ifndef SHARED
-	.weak __pthread_unwind
-# endif
-#endif
-
-
-#ifdef __ASSUME_PRIVATE_FUTEX
-# define LOAD_PRIVATE_FUTEX_WAIT(reg) \
-	movl	$(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
-#else
-# if FUTEX_WAIT == 0
-#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
-	movl	%fs:PRIVATE_FUTEX, reg
-# else
-#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \
-	movl	%fs:PRIVATE_FUTEX, reg ; \
-	orl	$FUTEX_WAIT, reg
-# endif
-#endif
-
-/* It is crucial that the functions in this file don't modify registers
-   other than %rax and %r11.  The syscall wrapper code depends on this
-   because it doesn't explicitly save the other registers which hold
-   relevant values.  */
-	.text
-
-	.hidden __pthread_enable_asynccancel
-ENTRY(__pthread_enable_asynccancel)
-	movl	%fs:CANCELHANDLING, %eax
-2:	movl	%eax, %r11d
-	orl	$TCB_CANCELTYPE_BITMASK, %r11d
-	cmpl	%eax, %r11d
-	je	1f
-
-	lock
-	cmpxchgl %r11d, %fs:CANCELHANDLING
-	jnz	2b
-
-	andl	$(TCB_CANCELSTATE_BITMASK|TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK|TCB_EXITING_BITMASK|TCB_CANCEL_RESTMASK|TCB_TERMINATED_BITMASK), %r11d
-	cmpl	$(TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK), %r11d
-	je	3f
-
-1:	ret
-
-3:	subq	$8, %rsp
-	cfi_adjust_cfa_offset(8)
-	LP_OP(mov) $TCB_PTHREAD_CANCELED, %fs:RESULT
-	lock
-	orl	$TCB_EXITING_BITMASK, %fs:CANCELHANDLING
-	mov	%fs:CLEANUP_JMP_BUF, %RDI_LP
-#ifdef SHARED
-	call	__pthread_unwind@PLT
-#else
-	call	__pthread_unwind
-#endif
-	hlt
-END(__pthread_enable_asynccancel)
-
-
-	.hidden __pthread_disable_asynccancel
-ENTRY(__pthread_disable_asynccancel)
-	testl	$TCB_CANCELTYPE_BITMASK, %edi
-	jnz	1f
-
-	movl	%fs:CANCELHANDLING, %eax
-2:	movl	%eax, %r11d
-	andl	$~TCB_CANCELTYPE_BITMASK, %r11d
-	lock
-	cmpxchgl %r11d, %fs:CANCELHANDLING
-	jnz	2b
-
-	movl	%r11d, %eax
-3:	andl	$(TCB_CANCELING_BITMASK|TCB_CANCELED_BITMASK), %eax
-	cmpl	$TCB_CANCELING_BITMASK, %eax
-	je	4f
-1:	ret
-
-	/* Performance doesn't matter in this loop.  We will
-	   delay until the thread is canceled.  And we will unlikely
-	   enter the loop twice.  */
-4:	mov	%fs:0, %RDI_LP
-	movl	$__NR_futex, %eax
-	xorq	%r10, %r10
-	addq	$CANCELHANDLING, %rdi
-	LOAD_PRIVATE_FUTEX_WAIT (%esi)
-	syscall
-	movl	%fs:CANCELHANDLING, %eax
-	jmp	3b
-END(__pthread_disable_asynccancel)
diff --git a/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S b/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S
deleted file mode 100644
index 019e22f..0000000
--- a/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S
+++ /dev/null
@@ -1,21 +0,0 @@ 
-/* Copyright (C) 2009-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
-
-   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/>.  */
-
-#define __pthread_enable_asynccancel __libc_enable_asynccancel
-#define __pthread_disable_asynccancel __libc_disable_asynccancel
-#include "cancellation.S"
diff --git a/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S b/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S
deleted file mode 100644
index 02892ef..0000000
--- a/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S
+++ /dev/null
@@ -1,21 +0,0 @@ 
-/* Copyright (C) 2009-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
-
-   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/>.  */
-
-#define __pthread_enable_asynccancel __librt_enable_asynccancel
-#define __pthread_disable_asynccancel __librt_disable_asynccancel
-#include "cancellation.S"
diff --git a/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h b/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
index 55b4e16..4857d4e 100644
--- a/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
+++ b/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
@@ -124,6 +124,20 @@ 
     __status;								      \
   })
 
+#define lll_futex_wait_cancel(futexp, val, private) \
+  lll_futex_timed_wait_cancel (futexp, val, NULL, private)
+
+#define lll_futex_timed_wait_cancel(futexp, val, timespec, private)	      \
+  ({									      \
+    long int __ret;							      \
+    int __op = FUTEX_WAIT;						      \
+                                                                              \
+    __ret = __syscall_cancel (__NR_futex, (long int) (futexp),		      \
+			      (long int)__lll_private_flag (__op, private),   \
+			      (long int)(val), (long int)(timespec), 0, 0);   \
+    __ret;								      \
+  })
+
 
 #define lll_futex_wake(futex, nr, private) \
   ({									      \
@@ -139,6 +153,18 @@ 
     __status;								      \
   })
 
+#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+									      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAKE_OP, private),    \
+			      (nr_wake), (nr_wake2), (futexp2),		      \
+			      FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);		      \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);				      \
+  })
+
 
 /* NB: in the lll_trylock macro we simply return the value in %eax
    after the cmpxchg instruction.  In case the operation succeded this
@@ -405,18 +431,9 @@  extern int __lll_timedlock_elision (int *futex, short *adapt_count,
    The macro parameter must not have any side effect.  */
 #define lll_wait_tid(tid) \
   do {									      \
-    int __ignore;							      \
-    register __typeof (tid) _tid asm ("edx") = (tid);			      \
-    if (_tid != 0)							      \
-      __asm __volatile ("xorq %%r10, %%r10\n\t"				      \
-			"1:\tmovq %2, %%rax\n\t"			      \
-			"syscall\n\t"					      \
-			"cmpl $0, (%%rdi)\n\t"				      \
-			"jne 1b"					      \
-			: "=&a" (__ignore)				      \
-			: "S" (FUTEX_WAIT), "i" (SYS_futex), "D" (&tid),      \
-			  "d" (_tid)					      \
-			: "memory", "cc", "r10", "r11", "cx");		      \
+    __typeof (tid) __tid;						      \
+    while ((__tid = (tid)) != 0)					      \
+      lll_futex_wait_cancel (&(tid), __tid, LLL_SHARED);		      \
   } while (0)
 
 extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
diff --git a/sysdeps/unix/sysv/linux/x86_64/recv.c b/sysdeps/unix/sysv/linux/x86_64/recv.c
index 53c2381..10b5d3e 100644
--- a/sysdeps/unix/sysv/linux/x86_64/recv.c
+++ b/sysdeps/unix/sysv/linux/x86_64/recv.c
@@ -25,16 +25,7 @@ 
 ssize_t
 __libc_recv (int fd, void *buf, size_t n, int flags)
 {
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (recvfrom, 6, fd, buf, n, flags, NULL, NULL);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  ssize_t result = INLINE_SYSCALL (recvfrom, 6, fd, buf, n, flags, NULL, NULL);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (recvfrom, fd, buf, n, flags, NULL, NULL);
 }
 
 weak_alias (__libc_recv, __recv)
diff --git a/sysdeps/unix/sysv/linux/x86_64/send.c b/sysdeps/unix/sysv/linux/x86_64/send.c
index 36a1dfd..95f04f5 100644
--- a/sysdeps/unix/sysv/linux/x86_64/send.c
+++ b/sysdeps/unix/sysv/linux/x86_64/send.c
@@ -23,17 +23,7 @@ 
 ssize_t
 __libc_send (int fd, const void *buf, size_t n, int flags)
 {
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (sendto, 6, fd, buf, n, flags, NULL, (size_t) 0);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  ssize_t result = INLINE_SYSCALL (sendto, 6, fd, buf, n, flags, NULL,
-				   (size_t) 0);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (sendto, fd, buf, n, flags, NULL, (size_t) 0);
 }
 
 weak_alias (__libc_send, __send)
diff --git a/sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S b/sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S
new file mode 100644
index 0000000..55c48c1
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S
@@ -0,0 +1,49 @@ 
+/* 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>
+
+ENTRY (__syscall_cancel_arch)
+
+	.globl __syscall_cancel_arch_start
+	.type  __syscall_cancel_arch_start,@function
+__syscall_cancel_arch_start:
+
+        mov    (%rdi),%eax
+	testb  $4, (%rdi)
+        jne    __syscall_do_cancel
+
+        mov    %rdi,%r11
+        mov    %rsi,%rax
+        mov    %rdx,%rdi
+        mov    %rcx,%rsi
+        mov    %r8,%rdx
+        mov    %r9,%r10
+        mov    8(%rsp),%r8
+        mov    16(%rsp),%r9
+        mov    %r11,8(%rsp)
+        syscall
+
+	.globl __syscall_cancel_arch_end
+	.type  __syscall_cancel_arch_end,@function
+__syscall_cancel_arch_end:
+
+	ret
+
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h b/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
index 83cd25f..f17f1df 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
@@ -24,81 +24,30 @@ 
 
 #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
 
-/* The code to disable cancellation depends on the fact that the called
-   functions are special.  They don't modify registers other than %rax
-   and %r11 if they return.  Therefore we don't have to preserve other
-   registers around these calls.  */
+# ifndef NOT_IN_libc
+#  define JMP_SYSCALL_CANCEL HIDDEN_JUMPTARGET(__syscall_cancel)
+# else
+#  define JMP_SYSCALL_CANCEL __syscall_cancel@plt
+# endif
+
 # undef PSEUDO
 # define PSEUDO(name, syscall_name, args)				      \
   .text;								      \
   ENTRY (name)								      \
-    SINGLE_THREAD_P;							      \
-    jne L(pseudo_cancel);						      \
-  .type __##syscall_name##_nocancel,@function;				      \
-  .globl __##syscall_name##_nocancel;					      \
-  __##syscall_name##_nocancel:						      \
-    DO_CALL (syscall_name, args);					      \
-    cmpq $-4095, %rax;							      \
-    jae SYSCALL_ERROR_LABEL;						      \
-    ret;								      \
-  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \
-  L(pseudo_cancel):							      \
-    /* We always have to align the stack before calling a function.  */	      \
-    subq $8, %rsp; cfi_adjust_cfa_offset (8);				      \
-    CENABLE								      \
-    /* The return value from CENABLE is argument for CDISABLE.  */	      \
-    movq %rax, (%rsp);							      \
-    DO_CALL (syscall_name, args);					      \
-    movq (%rsp), %rdi;							      \
-    /* Save %rax since it's the error code from the syscall.  */	      \
-    movq %rax, %rdx;							      \
-    CDISABLE								      \
-    movq %rdx, %rax;							      \
-    addq $8,%rsp; cfi_adjust_cfa_offset (-8);				      \
-    cmpq $-4095, %rax;							      \
-    jae SYSCALL_ERROR_LABEL
-
-
-# ifdef IS_IN_libpthread
-#  define CENABLE	call __pthread_enable_asynccancel;
-#  define CDISABLE	call __pthread_disable_asynccancel;
-#  define __local_multiple_threads __pthread_multiple_threads
-# elif !defined NOT_IN_libc
-#  define CENABLE	call __libc_enable_asynccancel;
-#  define CDISABLE	call __libc_disable_asynccancel;
-#  define __local_multiple_threads __libc_multiple_threads
-# elif defined IS_IN_librt
-#  define CENABLE	call __librt_enable_asynccancel;
-#  define CDISABLE	call __librt_disable_asynccancel;
-# else
-#  error Unsupported library
-# endif
-
-# if defined IS_IN_libpthread || !defined NOT_IN_libc
-#  ifndef __ASSEMBLER__
-extern int __local_multiple_threads attribute_hidden;
-#   define SINGLE_THREAD_P \
-  __builtin_expect (__local_multiple_threads == 0, 1)
-#  else
-#   define SINGLE_THREAD_P cmpl $0, __local_multiple_threads(%rip)
-#  endif
-
-# else
-
-#  ifndef __ASSEMBLER__
-#   define SINGLE_THREAD_P \
-  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
-				   header.multiple_threads) == 0, 1)
-#  else
-#   define SINGLE_THREAD_P cmpl $0, %fs:MULTIPLE_THREADS_OFFSET
-#  endif
-
-# endif
-
-#elif !defined __ASSEMBLER__
-
-# define SINGLE_THREAD_P (1)
-# define NO_CANCELLATION 1
+    subq  $24, %rsp;							      \
+    cfi_def_cfa_offset (32);						      \
+    movq  %r9, (%rsp);							      \
+    movq  %r8, %r9;							      \
+    movq  %rcx, %r8;							      \
+    movq  %rdx, %rcx;							      \
+    movq  %rsi, %rdx;							      \
+    movq  %rdi, %rsi;							      \
+    lea   SYS_ify (syscall_name), %edi;					      \
+    call  JMP_SYSCALL_CANCEL;						      \
+    cfi_def_cfa_offset (8);						      \
+    addq  $24, %rsp;							      \
+    cmpq  $-4095, %rax;							      \
+    jae SYSCALL_ERROR_LABEL;
 
 #endif
 
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
index 4a619da..e41eeea 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
@@ -307,6 +307,15 @@ 
   INTERNAL_SYSCALL (name, err, nr, ##args)
 # endif
 
+# undef SYSCALL_CANCEL_ERROR
+# define SYSCALL_CANCEL_ERROR(__val)					      \
+  ((unsigned long int) (long int) (__val) >= -4095L)
+
+# undef SYSCALL_CANCEL_ERRNO
+# define SYSCALL_CANCEL_ERRNO(__val)					      \
+  (-(__val))
+
+
 # define LOAD_ARGS_0()
 # define LOAD_REGS_0
 # define ASM_ARGS_0
diff --git a/sysdeps/x86_64/nptl/pthreaddef.h b/sysdeps/x86_64/nptl/pthreaddef.h
index 485a625..2226d1a 100644
--- a/sysdeps/x86_64/nptl/pthreaddef.h
+++ b/sysdeps/x86_64/nptl/pthreaddef.h
@@ -16,6 +16,9 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#ifndef _PTHREADDEF_H
+# define _PTHREADDEF_H
+
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
@@ -42,3 +45,13 @@ 
 /* Location of current stack frame.  The frame pointer is not usable.  */
 #define CURRENT_STACK_FRAME \
   ({ register char *frame __asm__("rsp"); frame; })
+
+#ifndef __ASSEMBLER__
+static inline
+long int __pthread_get_ip (const ucontext_t *uc)
+{
+  return (long int)uc->uc_mcontext.gregs[REG_RIP];
+}
+#endif
+
+#endif
diff --git a/sysdeps/x86_64/nptl/tcb-offsets.sym b/sysdeps/x86_64/nptl/tcb-offsets.sym
index 729d1da..026c9de 100644
--- a/sysdeps/x86_64/nptl/tcb-offsets.sym
+++ b/sysdeps/x86_64/nptl/tcb-offsets.sym
@@ -21,7 +21,6 @@  RTLD_SAVESPACE_SSE	offsetof (tcbhead_t, rtld_savespace_sse)
 -- Not strictly offsets, but these values are also used in the TCB.
 TCB_CANCELSTATE_BITMASK	 CANCELSTATE_BITMASK
 TCB_CANCELTYPE_BITMASK	 CANCELTYPE_BITMASK
-TCB_CANCELING_BITMASK	 CANCELING_BITMASK
 TCB_CANCELED_BITMASK	 CANCELED_BITMASK
 TCB_EXITING_BITMASK	 EXITING_BITMASK
 TCB_CANCEL_RESTMASK	 CANCEL_RESTMASK
diff --git a/sysdeps/x86_64/nptl/tls.h b/sysdeps/x86_64/nptl/tls.h
index 3e811b6..08423f6 100644
--- a/sysdeps/x86_64/nptl/tls.h
+++ b/sysdeps/x86_64/nptl/tls.h
@@ -325,17 +325,6 @@  typedef struct
 	      abort (); })
 
 
-/* Atomic set bit.  */
-# define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
-  (void) ({ if (sizeof ((descr)->member) == 4)				      \
-	      asm volatile (LOCK_PREFIX "orl %1, %%fs:%P0"		      \
-			    :: "i" (offsetof (struct pthread, member)),	      \
-			       "ir" (1 << (bit)));			      \
-	    else							      \
-	      /* Not necessary for other sizes in the moment.  */	      \
-	      abort (); })
-
-
 # define CALL_THREAD_FCT(descr) \
   ({ void *__res;							      \
      asm volatile ("movq %%fs:%P2, %%rdi\n\t"				      \