[1/4] nptl: Fix Race conditions in pthread cancellation, (BZ#12683)
diff mbox

Message ID 541C2DC8.3010505@linux.vnet.ibm.com
State New
Headers show

Commit Message

Adhemerval Zanella Sept. 19, 2014, 1:21 p.m. UTC
This patches fixes some race conditions in NPTL cancellation code by
redefining how cancellable syscalls are defined and handled.  Current
approach is to enable asynchronous cancellation prior to making the syscall
and restore the previous cancellation type once the syscall returns.

As decribed in BZ#12683, this approach shows 2 important problems:

1. Cancellation can act after the syscall has returned from kernel, but
   before userspace saves the return value.  It might result in a resource
   leak if the syscall allocated a resource or a side effect (partial
   read/write), and there is no way to program handle it with cancellation
   handlers.

2. If a signal is handled while the thread is blocked at a cancellable
   syscall, the entire signal handler runs with asynchronous cancellation
   enabled.  This can lead to issues if the signal handler call functions
   which are async-signal-safe but not async-cancel-safe.

For cancellation to work correctly, there are 5 points at which the
cancellation signal could arrive:

1. Before the final testcancel before the syscall is made.
2. Between the testcancel and the syscall.
3. While the syscall is blocked and no side effects have yet taken place.
4. While the syscall is blocked but with some side effects already having
   taken place (e.g. a partial read or write).
5. After the syscall has returned.

And GLIBC wants to act on cancellation in cases 1, 2, and 3 but not in case
4 or 5.  The proposed solution follows:

* Handling case 1 is trivial: do a conditional branch based on whether the
  thread has received a cancellation request;
* Case 2 can be caught by the signal handler determining that the saved
  program counter (from the ucontext_t) is in some address range beginning
  just before the "testcancel" and ending with the syscall instruction.
* In this case, except for certain syscalls that ALWAYS fail with EINTR
  even for non-interrupting signals, the kernel will reset the program
  counter to point at the syscall instruction during signal handling, so
  that the syscall is restarted when the signal handler returns. So, from
  the signal handler's standpoint, this looks the same as case 2, and thus
  it's taken care of.
* In this case, the kernel cannot restart the syscall; when it's
  interrupted by a signal, the kernel must cause the syscall to return
  with whatever partial result it obtained (e.g. partial read or write).
* In this case, the saved program counter points just after the syscall
  instruction, so the signal handler won't act on cancellation.
  This one is equal to 4. since the program counter is past the syscall
  instruction already.

Another case that needs handling is syscalls that fail with EINTR even
when the signal handler is non-interrupting. In this case, the syscall
wrapper code can just check the cancellation flag when the errno result
is EINTR, and act on cancellation if it's set.

The proposed GLIBC adjustments are:

1. Remove the enable_asynccancel/disable_asynccancel function usage in
   syscall definition and instead make them call a common symbol that will
   check if cancellation is enabled, call the arch-specific cancellable
   entry-point and cancel the thread when required.
2. Provide a arch-specific symbol that contains global markers. These
   markers will be used in SIGCANCEL handler to check if the interruption
   has been called in a valid syscall and if the syscalls has been
   completed or not.
3. Rewrite SIGCANCEL asynchronous handler to check for both cancelling type
   and if current IP from signal handler falls between the global markes
   and act accordingly.
4. Adjust nptl/pthread_cancel.c to send an signal instead of acting
   directly. This avoid synchronization issues about updating the
   cancellation status and also focus the logic on signal handler and
   cancellation syscall code.
5. Adjust pthread code to replace CANCEL_ASYNC/CANCEL_RESET calls to
   appropriated cancelable futex syscalls.
6. Adjust libc code to replace LIBC_CANCEL_ASYNC/LIBC_CANCEL_RESET to
   appropriated cancelable syscalls.
7. Rewrite sysdeps/unix/sysv/linux/not-cancel.h to calls inline syscalls
   for non-cancelable versions.
8. Adjust 'lowlevellock.h' arch-specific implementations to provide
   cancelable futex calls (used in libpthread code).

This patch adds the proposed changes to NPTL and the changes required
for powerpc64.  The testcases are not yet updated, so the following ones
show failures:

FAIL: debug/tst-backtrace5
FAIL: debug/tst-backtrace6
FAIL: nptl/tst-cancel-wrappers
FAIL: nptl/tst-cancel20
FAIL: nptl/tst-cancel21
FAIL: nptl/tst-cancel21-static
FAIL: nptl/tst-cancel4
FAIL: nptl/tst-cancel5
FAIL: nptl/tst-cancelx2
FAIL: nptl/tst-cancelx20
FAIL: nptl/tst-cancelx4
FAIL: nptl/tst-cancelx5

--

	* nptl/Makefile [routines]: Add syscall_cancel object.
	[libpthread-routines]: Remove cancellation object.
	* rt/Makefile [CFLAGS-librt-cancellation.c]: Remove rule.
	* nptl/version (libc) [GLIBC_PRIVATE]: Add __syscall_cancel,
	__syscall_cancel_arch_start, and __syscall_cancel_arch_end.
	* nptl/cancellation.c: Remove file.
	* nptl/descr.h (CANCELING_BIT): Remove define.
	(CANCELING_BITMASK): Likewise.
	(CANCEL_RESTMASK): Adjust value with CANCELED_BIT remove.
	* nptl/libc-cancellation.c (__syscall_cancel): Add non-cancellable
	implementation for loader and cancellable one for libc.
	(__syscall_do_cancel): New function: cancel call for syscall wrappers.
	* nptl/lowlevellock.c (__lll_timedwait_tid): Using cancellable futex
	call.
	* nptl/sem_timedwait.c (sem_timedwait):  Likewise.
	* nptl/sem_wait.c (__new_sem_wait): Likewise.
	* sysdeps/nptl/lowlevellock.h (lll_wait_tid): Likewise.
	* nptl/nptl-init.c (sigcancel_handler): Rewrite function to avoid race
	conditions.
	* nptl/pt-system.c [LIBC_CANCEL_HANDLED]: Remove definition.
	* nptl/pthreadP.h (__do_cancel): Rewrite to both disable asynchronous
	cancellation and setting the thread as cancelled.
	(CANCEL_ASYNC): Remove definition.
	(CANCEL_RESET): Likewise.
	(LIBC_CANCEL_ASYNC): Likewise.
	(LIBC_CANCEL_RESET): Likewise.
	(LIBC_CANCEL_HANDLED): Likewise.
	(__syscall_cancel_arch): Add prototype.
	(__pthread_enable_asynccancel): Remove prototype.
	(__pthread_disable_asynccancel): Likewise.
	(__libc_enable_asynccancel): Likewise.
	(__libc_disable_asynccancel): Likewise.
	(__librt_enable_asynccancel): Likewise.
	(__librt_disable_asynccancel): Likewise.
	* nptl/pthread_cancel.c (pthread_cancel): Rewrite to just set
	CANCELLED_BIT and call __pthread_kill.
	* nptl/pthread_exit.c (pthread_exit): Rewrite to set EXITING_BIT
	before call __pthread_unwind.
	* nptl/pthread_join.c (pthread_join): Remove CANCEL_ASYNC/CANCEL_RESET
	usage.
	* nptl/pthread_timedjoin.c (pthread_timedjoin_np): Likewise.
	* nptl/pthread_cond_timedwait.c (__pthread_cond_timedwait): Remove
	calls to enable/disable asynchronous cancellation and use call to
	cancellable syscall entrypoint when required.
	* nptl/pthread_cond_wait.c (__pthread_cond_wait): Likewise.
	* nptl/pthread_create.c (start_thread): Likewise.
	* sysdeps/nptl/aio_misc.h (AIO_MISC_WAIT): Likewise.
	* sysdeps/nptl/gai_misc.h (GAI_MISC_WAIT): Likewise.
	* sysdeps/posix/sigpause.c (do_sigpause): Likewise.
	* sysdeps/posix/waitid.c (__waitid): Likewise.
	* sysdeps/unix/sysv/linux/accept4.c (accept4): Likewise.
	* sysdeps/unix/sysv/linux/clock_nanosleep.c (__clock_nanosleep):
	Likewise.
	* sysdeps/unix/sysv/linux/epoll_pwait.c (epoll_pwait): Likewise.
	* sysdeps/unix/sysv/linux/msgrcv.c (__libc_msgrcv): Likewise.
	* sysdeps/unix/sysv/linux/msgsnd.c (__libc_msgsnd): Likewise.
	* sysdeps/unix/sysv/linux/openat.c (__OPENAT): Likewise.
	* sysdeps/unix/sysv/linux/ppoll.c (ppoll): Likewise.
	* sysdeps/unix/sysv/linux/pselect.c (__pselect): Likewise.
	* sysdeps/unix/sysv/linux/readv.c (__libc_readv): Likewise.
	* sysdeps/unix/sysv/linux/recvmmsg.c (recvmmsg): Likewise.
	* sysdeps/unix/sysv/linux/sendmmsg.c (sendmmsg): Likewise.
	* sysdeps/unix/sysv/linux/sigsuspend.c (__sigsuspend): Likewise.
	* sysdeps/unix/sysv/linux/sigtimedwait.c (__sigtimedwait): Likewise.
	* sysdeps/unix/sysv/linux/sigtimedwait.c (do_sigwait): Likewise.
	(__sigwait): Likewise.
	* sysdeps/unix/sysv/linux/sigwaitinfo.c (do_sigwaitinfo): Likewise.
	* sysdeps/unix/sysv/linux/tcdrain.c (__libc_tcdrain): Likewise.
	* sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread):
	Likewise.
	* sysdeps/unix/sysv/linux/wait.c (__libc_wait): Likewise.
	* sysdeps/unix/sysv/linux/waitid.c (do_waitid): Likewise.
	* sysdeps/unix/sysv/linux/waitpid.c (__libc_waitpid): Likewise.
	* sysdeps/unix/sysv/linux/writev.c (__libc_writev): Likewise.
	* sysdeps/unix/sysv/linux/wordsize-64/fallocate.c (fallocate):
	Likewise.
	* sysdeps/unix/sysv/linux/wordsize-64/preadv.c (preadv): Likewise.
	* sysdeps/unix/sysv/linux/wordsize-64/pwritev.c (pwritev): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c (__libc_fnctl):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/pread.c (__libc_pread):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/pread64.c
	(__libc_pread64): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite.c
	(__libc_pwrite): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite64.c
	(__libc_pwrite64): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/socket.S (__socket):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/sync_file_range.c
	(sync_file_range): Likewise.
	* sysdeps/unix/sysv/linux/wordsize-64/openat.c [__openat64_nocancel]:
	Remove define.
	[__openat64_nocancel]: Remove strong aliais.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO):
	Likewise.
	* sysdeps/generic/sysdep-cancel.h (LIBC_CANCEL_ASYNC): Remove define.
	(LIBC_CANCEL_RESET): Likewise.
	(LIBC_CANCEL_HANDLED): Likewise.
	* sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): Allow
	SIGCANCEL to be sent.
	* sysdeps/nptl/Makefile [librt-sysdep_routines]: Remove rule.
	* sysdeps/nptl/librt-cancellation.c: Remove file.
	* sysdeps/powerpc/nptl/pthreaddef.h (__pthread_get_ip): New function:
	return ucontext_t instruction point address.
	* sysdeps/unix/sysdep.h (SYSCALL_CANCEL): New macro: cancelable
	syscall calls.
	(__syscall_cancel): Add prototype.
	* sysdeps/unix/sysv/linux/not-cancel.h (open_not_cancel): Rewrite to
	be an inline implementation regardless of library is built within.
	(open_not_cancel_2): Likewise.
	(__read_nocancel): Likewise.
	(__write_nocancel): Likewise.
	(openat_not_cancel): Likewise.
	(openat_not_cancel_3): Likewise.
	(openat64_not_cancel): Likewise.
	(openat64_not_cancel_3): Likewise.
	(__close_nocancel): Likewise.
	(pause_not_cancel): Likewise.
	(nanosleep_not_cancel): Likewise.
	(sigsuspend_not_cancel): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
	(lll_futex_wait_cancel): New define: cancellable futex wait.
	(lll_futex_timed_wait_cancel): New define: cancellable timed wait.
	(lll_futex_timed_wait_bitset_cancel): New define: cancellable timed
	wait bitset.
	(lll_futex_wait_requeue_pi_cancel): New define: cancellable wait
	requeue PI futex.
	(lll_futex_timed_wait_requeue_pi_cancel): New define: cancellable time
	wait requeue PI futex.
	(lll_wait_tid): Use cancellable futex wait call.
	* 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.

---

Comments

Joseph Myers Sept. 19, 2014, 4:58 p.m. UTC | #1
On Fri, 19 Sep 2014, Adhemerval Zanella wrote:

> +long int
> +__syscall_cancel (long int nr, long int arg1, long int arg2, long int arg3,
> +		  long int arg4, long int arg5, long int arg6)
> +{
> +  INTERNAL_SYSCALL_DECL (err);
> +  return INTERNAL_SYSCALL_NCS (nr, err, 6, arg1, arg2, arg3, arg4, arg5, arg6);
> +}

Avoid hardcoding "long" as syscall argument type.  It ought to be possible 
to use the same code for cases using "long long" (MIPS n32 at least) if 
you allow architectures to override the choice of type.

> diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
> index aeba1ff..810deec 100644
> --- a/nptl/pthread_cancel.c
> +++ b/nptl/pthread_cancel.c
> @@ -18,14 +18,12 @@
>  
>  #include <errno.h>
>  #include <signal.h>
> -#include "pthreadP.h"
> -#include "atomic.h"
> +#include <pthreadP.h>
> +#include <atomic.h>

Don't mix this sort of thing with substantive changes; send any patch for 
such #include style changes separately.  This will reduce the size of your 
patches....

>  #include <sysdep.h>
>  
> -
>  int
> -pthread_cancel (th)
> -     pthread_t th;
> +pthread_cancel (pthread_t th)
>  {

Likewise, send any such changes of style for function definitions 
separately.

> diff --git a/sysdeps/unix/sysv/linux/accept4.c b/sysdeps/unix/sysv/linux/accept4.c
> index a017224..a02dc35 100644
> --- a/sysdeps/unix/sysv/linux/accept4.c
> +++ b/sysdeps/unix/sysv/linux/accept4.c
> @@ -37,16 +37,8 @@
>  int
>  accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
>  {
> -  if (SINGLE_THREAD_P)
> -    return INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, flags);
> -
> -  int oldtype = LIBC_CANCEL_ASYNC ();
> -
> -  int result = INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len,
> +  int result = SYSCALL_CANCEL (accept4, fd, addr.__sockaddr__, addr_len,
>  			       flags);
> -
> -  LIBC_CANCEL_RESET (oldtype);
> -

For cases like this, it seems to me that you should be able to do a 
preliminary patch that defines SYSCALL_CANCEL in a way that expands to the 
existing code using LIBC_CANCEL_ASYNC, INLINE_SYSCALL and 
LIBC_CANCEL_RESET.  If you can define some of the new macros like that, 
then you can change most or all such code for all architectures to the new 
idiom (reasonably safely without being able to test on all the 
architectures), reducing the size of the per-architecture patches needed 
later and of the patches with the changes that actually fix the main 
issue.

> diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
> index 14f5e8b..a20aa01 100644
> --- a/sysdeps/unix/sysv/linux/not-cancel.h
> +++ b/sysdeps/unix/sysv/linux/not-cancel.h

These also look like changes that don't depend on the main changes.  
Anything not depending on the main changes should be separated out and go 
first.
Joseph Myers Sept. 19, 2014, 9:38 p.m. UTC | #2
On Fri, 19 Sep 2014, Joseph S. Myers wrote:

> For cases like this, it seems to me that you should be able to do a 
> preliminary patch that defines SYSCALL_CANCEL in a way that expands to the 
> existing code using LIBC_CANCEL_ASYNC, INLINE_SYSCALL and 
> LIBC_CANCEL_RESET.  If you can define some of the new macros like that, 
> then you can change most or all such code for all architectures to the new 
> idiom (reasonably safely without being able to test on all the 
> architectures), reducing the size of the per-architecture patches needed 
> later and of the patches with the changes that actually fix the main 
> issue.

Also, if the function in question has a "Consider moving to 
syscalls.list." comment (as in 
sysdeps/unix/sysv/linux/powerpc/powerpc64/pread.c, for example), then if 
in fact everything that C function does is equivalent to something that 
can be represented in syscalls.list, doing that move (part of bug 14138) 
would serve equally well for this purpose.  (For your patch series, of 
course only the part of bug 14138 dealing with functions with cancellation 
handling is relevant.)
Adhemerval Zanella Sept. 22, 2014, 1:14 p.m. UTC | #3
Thanks for the review, comments below.


On 19-09-2014 13:58, Joseph S. Myers wrote:
> On Fri, 19 Sep 2014, Adhemerval Zanella wrote:
>
>> +long int
>> +__syscall_cancel (long int nr, long int arg1, long int arg2, long int arg3,
>> +		  long int arg4, long int arg5, long int arg6)
>> +{
>> +  INTERNAL_SYSCALL_DECL (err);
>> +  return INTERNAL_SYSCALL_NCS (nr, err, 6, arg1, arg2, arg3, arg4, arg5, arg6);
>> +}
> Avoid hardcoding "long" as syscall argument type.  It ought to be possible 
> to use the same code for cases using "long long" (MIPS n32 at least) if 
> you allow architectures to override the choice of type.

Right, I was not aware of such ABI cases.  I will make this parametrized, defined
in arch-specific header (sysdep-cancel.h).

>
>> diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
>> index aeba1ff..810deec 100644
>> --- a/nptl/pthread_cancel.c
>> +++ b/nptl/pthread_cancel.c
>> @@ -18,14 +18,12 @@
>>  
>>  #include <errno.h>
>>  #include <signal.h>
>> -#include "pthreadP.h"
>> -#include "atomic.h"
>> +#include <pthreadP.h>
>> +#include <atomic.h>
> Don't mix this sort of thing with substantive changes; send any patch for 
> such #include style changes separately.  This will reduce the size of your 
> patches....

Thanks for catching it, I though it had cleanup all modification of such type.

>>  #include <sysdep.h>
>>  
>> -
>>  int
>> -pthread_cancel (th)
>> -     pthread_t th;
>> +pthread_cancel (pthread_t th)
>>  {
> Likewise, send any such changes of style for function definitions 
> separately.

I sincerely don't think we need *another* patch for such changes.  They are fairly
mechanical and I think is is safe to use this kinda of extensive patch set to correct
this.

>
>> diff --git a/sysdeps/unix/sysv/linux/accept4.c b/sysdeps/unix/sysv/linux/accept4.c
>> index a017224..a02dc35 100644
>> --- a/sysdeps/unix/sysv/linux/accept4.c
>> +++ b/sysdeps/unix/sysv/linux/accept4.c
>> @@ -37,16 +37,8 @@
>>  int
>>  accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
>>  {
>> -  if (SINGLE_THREAD_P)
>> -    return INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, flags);
>> -
>> -  int oldtype = LIBC_CANCEL_ASYNC ();
>> -
>> -  int result = INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len,
>> +  int result = SYSCALL_CANCEL (accept4, fd, addr.__sockaddr__, addr_len,
>>  			       flags);
>> -
>> -  LIBC_CANCEL_RESET (oldtype);
>> -
> For cases like this, it seems to me that you should be able to do a 
> preliminary patch that defines SYSCALL_CANCEL in a way that expands to the 
> existing code using LIBC_CANCEL_ASYNC, INLINE_SYSCALL and 
> LIBC_CANCEL_RESET.  If you can define some of the new macros like that, 
> then you can change most or all such code for all architectures to the new 
> idiom (reasonably safely without being able to test on all the 
> architectures), reducing the size of the per-architecture patches needed 
> later and of the patches with the changes that actually fix the main 
> issue.

I did think about it and I wasn't sure the direction required for such extensive patch:
should we correct only a subset of architecture and let other arch maintainers fix them
eventually? Or should we aim to fix all architecture at once? I latter chose on later because
it will create less permutations.

I see no problem on work to push for such patch, but it will require more work, more testing,
and more.  And I *really* would prefer to focus such efforts on enable other arches for 
this new system and on the review itself.  For instance, ppc32-fp took me just some hours 
and 16 files changed, 102 insertions(+), 340 deletions(-).

>
>> diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
>> index 14f5e8b..a20aa01 100644
>> --- a/sysdeps/unix/sysv/linux/not-cancel.h
>> +++ b/sysdeps/unix/sysv/linux/not-cancel.h
> These also look like changes that don't depend on the main changes.  
> Anything not depending on the main changes should be separated out and go 
> first.

Thanks, I'll split it.
Joseph Myers Sept. 22, 2014, 2:01 p.m. UTC | #4
On Mon, 22 Sep 2014, Adhemerval Zanella wrote:

> >>  #include <sysdep.h>
> >>  
> >> -
> >>  int
> >> -pthread_cancel (th)
> >> -     pthread_t th;
> >> +pthread_cancel (pthread_t th)
> >>  {
> > Likewise, send any such changes of style for function definitions 
> > separately.
> 
> I sincerely don't think we need *another* patch for such changes.  They 
> are fairly mechanical and I think is is safe to use this kinda of 
> extensive patch set to correct this.

The main changes - the ones that actually change how the library behaves, 
and need nontrivial architecture-specific changes, and are the trickiest 
to review - should be kept as small as possible.  That means that anything 
that can reasonably be submitted on its own as a preliminary cleanup 
should be.

> >> diff --git a/sysdeps/unix/sysv/linux/accept4.c b/sysdeps/unix/sysv/linux/accept4.c
> >> index a017224..a02dc35 100644
> >> --- a/sysdeps/unix/sysv/linux/accept4.c
> >> +++ b/sysdeps/unix/sysv/linux/accept4.c
> >> @@ -37,16 +37,8 @@
> >>  int
> >>  accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
> >>  {
> >> -  if (SINGLE_THREAD_P)
> >> -    return INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, flags);
> >> -
> >> -  int oldtype = LIBC_CANCEL_ASYNC ();
> >> -
> >> -  int result = INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len,
> >> +  int result = SYSCALL_CANCEL (accept4, fd, addr.__sockaddr__, addr_len,
> >>  			       flags);
> >> -
> >> -  LIBC_CANCEL_RESET (oldtype);
> >> -
> > For cases like this, it seems to me that you should be able to do a 
> > preliminary patch that defines SYSCALL_CANCEL in a way that expands to the 
> > existing code using LIBC_CANCEL_ASYNC, INLINE_SYSCALL and 
> > LIBC_CANCEL_RESET.  If you can define some of the new macros like that, 
> > then you can change most or all such code for all architectures to the new 
> > idiom (reasonably safely without being able to test on all the 
> > architectures), reducing the size of the per-architecture patches needed 
> > later and of the patches with the changes that actually fix the main 
> > issue.
> 
> I did think about it and I wasn't sure the direction required for such 
> extensive patch: should we correct only a subset of architecture and let 
> other arch maintainers fix them eventually? Or should we aim to fix all 
> architecture at once? I latter chose on later because it will create 
> less permutations.

The aim is to fix all architectures.  For an essentially mechanical change 
- converting to a new set of macros - that should be feasible.  It is also 
possible to do it bit by bit - because adding the macros doesn't break any 
files using the old macros, it isn't necessary to convery all files in the 
same commit, if you'd like architecture maintainers to test the 
conversions for their architectures.

> I see no problem on work to push for such patch, but it will require 
> more work, more testing, and more.  And I *really* would prefer to focus 
> such efforts on enable other arches for this new system and on the 
> review itself.  For instance, ppc32-fp took me just some hours and 16 
> files changed, 102 insertions(+), 340 deletions(-).

Again, the review is easier if as much as possible goes in preliminary 
patches that pave the way for the main changes.
Adhemerval Zanella Sept. 23, 2014, 12:49 p.m. UTC | #5
On 22-09-2014 11:01, Joseph S. Myers wrote:
> On Mon, 22 Sep 2014, Adhemerval Zanella wrote:
>
>>>>  #include <sysdep.h>
>>>>  
>>>> -
>>>>  int
>>>> -pthread_cancel (th)
>>>> -     pthread_t th;
>>>> +pthread_cancel (pthread_t th)
>>>>  {
>>> Likewise, send any such changes of style for function definitions 
>>> separately.
>> I sincerely don't think we need *another* patch for such changes.  They 
>> are fairly mechanical and I think is is safe to use this kinda of 
>> extensive patch set to correct this.
> The main changes - the ones that actually change how the library behaves, 
> and need nontrivial architecture-specific changes, and are the trickiest 
> to review - should be kept as small as possible.  That means that anything 
> that can reasonably be submitted on its own as a preliminary cleanup 
> should be.

Fair enough, I will split the function definitions change.

>>>> diff --git a/sysdeps/unix/sysv/linux/accept4.c b/sysdeps/unix/sysv/linux/accept4.c
>>>> index a017224..a02dc35 100644
>>>> --- a/sysdeps/unix/sysv/linux/accept4.c
>>>> +++ b/sysdeps/unix/sysv/linux/accept4.c
>>>> @@ -37,16 +37,8 @@
>>>>  int
>>>>  accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
>>>>  {
>>>> -  if (SINGLE_THREAD_P)
>>>> -    return INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, flags);
>>>> -
>>>> -  int oldtype = LIBC_CANCEL_ASYNC ();
>>>> -
>>>> -  int result = INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len,
>>>> +  int result = SYSCALL_CANCEL (accept4, fd, addr.__sockaddr__, addr_len,
>>>>  			       flags);
>>>> -
>>>> -  LIBC_CANCEL_RESET (oldtype);
>>>> -
>>> For cases like this, it seems to me that you should be able to do a 
>>> preliminary patch that defines SYSCALL_CANCEL in a way that expands to the 
>>> existing code using LIBC_CANCEL_ASYNC, INLINE_SYSCALL and 
>>> LIBC_CANCEL_RESET.  If you can define some of the new macros like that, 
>>> then you can change most or all such code for all architectures to the new 
>>> idiom (reasonably safely without being able to test on all the 
>>> architectures), reducing the size of the per-architecture patches needed 
>>> later and of the patches with the changes that actually fix the main 
>>> issue.
>> I did think about it and I wasn't sure the direction required for such 
>> extensive patch: should we correct only a subset of architecture and let 
>> other arch maintainers fix them eventually? Or should we aim to fix all 
>> architecture at once? I latter chose on later because it will create 
>> less permutations.
> The aim is to fix all architectures.  For an essentially mechanical change 
> - converting to a new set of macros - that should be feasible.  It is also 
> possible to do it bit by bit - because adding the macros doesn't break any 
> files using the old macros, it isn't necessary to convery all files in the 
> same commit, if you'd like architecture maintainers to test the 
> conversions for their architectures.

It is not just a mechanical change unfortunately: I get rid of *_[enable/disable]_asynccancel
symbol, rewrite the SIGCANCEL handler and some NPTL functions.  A preliminary 
patch to define SYSCALL_CANCEL to expand to current behavior would mean I would have
to conditionally compile the old code while providing the new one and adjust the
new behavior to work with old pieces (which is not the patch intended and I see
it as usefulness work, since the idea will to get rid of it eventually).

I am evaluating it using i386 as base and this generates more trouble than solutions.
I do know this is large patch and requires extensively changes over important
GLIBC parts. However, as bug described, I see this is an important issue the way
pthread cancellation is done now I don't see a way to smooth transition from one
way to another.  It does require a full rewrite, unfortunately.

>
>> I see no problem on work to push for such patch, but it will require 
>> more work, more testing, and more.  And I *really* would prefer to focus 
>> such efforts on enable other arches for this new system and on the 
>> review itself.  For instance, ppc32-fp took me just some hours and 16 
>> files changed, 102 insertions(+), 340 deletions(-).
> Again, the review is easier if as much as possible goes in preliminary 
> patches that pave the way for the main changes.
>
Joseph Myers Sept. 23, 2014, 1:03 p.m. UTC | #6
On Tue, 23 Sep 2014, Adhemerval Zanella wrote:

> > The aim is to fix all architectures.  For an essentially mechanical change 
> > - converting to a new set of macros - that should be feasible.  It is also 
> > possible to do it bit by bit - because adding the macros doesn't break any 
> > files using the old macros, it isn't necessary to convery all files in the 
> > same commit, if you'd like architecture maintainers to test the 
> > conversions for their architectures.
> 
> It is not just a mechanical change unfortunately: I get rid of 
> *_[enable/disable]_asynccancel

It's only the conversion to SYSCALL_CANCEL that I'm referring to as a 
mechanical change.

> symbol, rewrite the SIGCANCEL handler and some NPTL functions.  A 
> preliminary patch to define SYSCALL_CANCEL to expand to current behavior 
> would mean I would have to conditionally compile the old code while 
> providing the new one and adjust the new behavior to work with old 
> pieces (which is not the patch intended and I see it as usefulness work, 
> since the idea will to get rid of it eventually).

I don't see any adjustment or conditional compilation as needed.  The only 
extra intermediate step I imagine here is one architecture-independent 
definition of the SYSCALL_CANCEL macro (which would later go away); all 
the conversions to use SYSCALL_CANCEL would be in places that would need 
converting anyway.  The aim, again, is to keep the main patch as small as 
possible so it is as easy as possible to review and there is as little as 
possible that architecture maintainers need to understand to make their 
architecture-specific changes.

(But I don't know how many places would end up using SYSCALL_CANCEL if the 
approach taken is preferentially converting such places to use 
syscalls.list instead, so conversions to syscalls.list should take 
priority.)

Patch
diff mbox

diff --git a/nptl/Makefile b/nptl/Makefile
index 157fe62..968dffd 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -30,7 +30,7 @@  install-lib-ldscripts := libpthread.so
 
 routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \
 	   libc-cleanup libc_pthread_init libc_multiple_threads \
-	   register-atfork unregister-atfork
+	   register-atfork unregister-atfork syscall_cancel
 shared-only-routines = forward
 
 libpthread-routines = nptl-init vars events version \
@@ -103,7 +103,6 @@  libpthread-routines = nptl-init vars events version \
 		      cleanup cleanup_defer cleanup_compat \
 		      cleanup_defer_compat unwind \
 		      pt-longjmp pt-cleanup\
-		      cancellation \
 		      lowlevellock lowlevelrobustlock \
 		      pt-fork pt-vfork \
 		      ptw-write ptw-read ptw-close ptw-fcntl ptw-accept \
@@ -156,7 +155,6 @@  CFLAGS-pthread_setcanceltype.c = -fexceptions -fasynchronous-unwind-tables
 
 # These are internal functions which similar functionality as setcancelstate
 # and setcanceltype.
-CFLAGS-cancellation.c = -fasynchronous-unwind-tables
 CFLAGS-libc-cancellation.c = -fasynchronous-unwind-tables
 
 # Calling pthread_exit() must cause the registered cancel handlers to
diff --git a/nptl/Versions b/nptl/Versions
index b7d4a9b..4114bc9 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -36,6 +36,9 @@  libc {
     __libc_pthread_init;
     __libc_current_sigrtmin_private; __libc_current_sigrtmax_private;
     __libc_allocate_rtsig_private;
+    __syscall_cancel;
+    __syscall_cancel_arch_start;
+    __syscall_cancel_arch_end;
   }
 }
 
diff --git a/nptl/cancellation.c b/nptl/cancellation.c
deleted file mode 100644
index aaf102d..0000000
--- a/nptl/cancellation.c
+++ /dev/null
@@ -1,99 +0,0 @@ 
-/* Copyright (C) 2002-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
-
-   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 <setjmp.h>
-#include <stdlib.h>
-#include "pthreadP.h"
-
-
-/* The next two functions are similar to pthread_setcanceltype() but
-   more specialized for the use in the cancelable functions like write().
-   They do not need to check parameters etc.  */
-int
-attribute_hidden
-__pthread_enable_asynccancel (void)
-{
-  struct pthread *self = THREAD_SELF;
-  int oldval = THREAD_GETMEM (self, cancelhandling);
-
-  while (1)
-    {
-      int newval = oldval | CANCELTYPE_BITMASK;
-
-      if (newval == oldval)
-	break;
-
-      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
-					      oldval);
-      if (__glibc_likely (curval == oldval))
-	{
-	  if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
-	    {
-	      THREAD_SETMEM (self, result, PTHREAD_CANCELED);
-	      __do_cancel ();
-	    }
-
-	  break;
-	}
-
-      /* Prepare the next round.  */
-      oldval = curval;
-    }
-
-  return oldval;
-}
-
-
-void
-internal_function attribute_hidden
-__pthread_disable_asynccancel (int oldtype)
-{
-  /* If asynchronous cancellation was enabled before we do not have
-     anything to do.  */
-  if (oldtype & CANCELTYPE_BITMASK)
-    return;
-
-  struct pthread *self = THREAD_SELF;
-  int newval;
-
-  int oldval = THREAD_GETMEM (self, cancelhandling);
-
-  while (1)
-    {
-      newval = oldval & ~CANCELTYPE_BITMASK;
-
-      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
-					      oldval);
-      if (__glibc_likely (curval == oldval))
-	break;
-
-      /* Prepare the next round.  */
-      oldval = curval;
-    }
-
-  /* We cannot return when we are being canceled.  Upon return the
-     thread might be things which would have to be undone.  The
-     following loop should loop until the cancellation signal is
-     delivered.  */
-  while (__builtin_expect ((newval & (CANCELING_BITMASK | CANCELED_BITMASK))
-			   == CANCELING_BITMASK, 0))
-    {
-      lll_futex_wait (&self->cancelhandling, newval, LLL_PRIVATE);
-      newval = THREAD_GETMEM (self, cancelhandling);
-    }
-}
diff --git a/nptl/descr.h b/nptl/descr.h
index 6738591..a5b0b29 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -263,23 +263,20 @@  struct pthread
   /* Bit set if asynchronous cancellation mode is selected.  */
 #define CANCELTYPE_BIT		1
 #define CANCELTYPE_BITMASK	(0x01 << CANCELTYPE_BIT)
-  /* Bit set if canceling has been initiated.  */
-#define CANCELING_BIT		2
-#define CANCELING_BITMASK	(0x01 << CANCELING_BIT)
-  /* Bit set if canceled.  */
-#define CANCELED_BIT		3
+  /* Bit set if threads is canceled.  */
+#define CANCELED_BIT		2
 #define CANCELED_BITMASK	(0x01 << CANCELED_BIT)
   /* Bit set if thread is exiting.  */
-#define EXITING_BIT		4
+#define EXITING_BIT		3
 #define EXITING_BITMASK		(0x01 << EXITING_BIT)
   /* Bit set if thread terminated and TCB is freed.  */
-#define TERMINATED_BIT		5
+#define TERMINATED_BIT		4
 #define TERMINATED_BITMASK	(0x01 << TERMINATED_BIT)
   /* Bit set if thread is supposed to change XID.  */
-#define SETXID_BIT		6
+#define SETXID_BIT		5
 #define SETXID_BITMASK		(0x01 << SETXID_BIT)
   /* Mask for the rest.  Helps the compiler to optimize.  */
-#define CANCEL_RESTMASK		0xffffff80
+#define CANCEL_RESTMASK		0xffffffc0
 
 #define CANCEL_ENABLED_AND_CANCELED(value) \
   (((value) & (CANCELSTATE_BITMASK | CANCELED_BITMASK | EXITING_BITMASK	      \
diff --git a/nptl/libc-cancellation.c b/nptl/libc-cancellation.c
index c2c1fbb..9f41f53 100644
--- a/nptl/libc-cancellation.c
+++ b/nptl/libc-cancellation.c
@@ -16,9 +16,59 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <setjmp.h>
+#include <stdlib.h>
 #include "pthreadP.h"
 
+#ifdef IS_IN_rtld
 
-#define __pthread_enable_asynccancel __libc_enable_asynccancel
-#define __pthread_disable_asynccancel __libc_disable_asynccancel
-#include <nptl/cancellation.c>
+long int
+__syscall_cancel (long int nr, long int arg1, long int arg2, long int arg3,
+		  long int arg4, long int arg5, long int arg6)
+{
+  INTERNAL_SYSCALL_DECL (err);
+  return INTERNAL_SYSCALL_NCS (nr, err, 6, arg1, arg2, arg3, arg4, arg5, arg6);
+}
+
+#else
+
+/* Cancellation function called by all cancellable syscalls.  */
+long int
+__syscall_cancel (long int nr, long int a1, long int a2, long int a3,
+		  long int a4, long int a5, long int a6)
+{
+  pthread_t self = (pthread_t) THREAD_SELF;
+  volatile struct pthread *pd = (volatile struct pthread *) self;
+  long int result;
+
+  /* If cancellation is not enabled, call the syscall directly.  */
+  if (pd->cancelhandling & CANCELSTATE_BITMASK)
+    {
+      INTERNAL_SYSCALL_DECL (err);
+      result = INTERNAL_SYSCALL_NCS (nr, err, 6, a1, a2, a3, a4, a5, a6);
+      return INTERNAL_SYSCALL_ERROR_P (result, err) ? -result : result;
+    }
+
+  /* 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);
+
+  if ((result == -EINTR)
+      && (pd->cancelhandling & CANCELED_BITMASK)
+      && !(pd->cancelhandling & CANCELSTATE_BITMASK))
+    __do_cancel ();
+
+  return result;
+}
+libc_hidden_def (__syscall_cancel)
+
+/* Since __do_cancel is a always inline function, this creates a symbol the
+   arch-specific symbol can call to cancel the thread.  */
+void
+__syscall_do_cancel (void)
+{
+  __do_cancel ();
+}
+
+#endif
diff --git a/nptl/lowlevellock.c b/nptl/lowlevellock.c
index e198af7..0ff4ac3 100644
--- a/nptl/lowlevellock.c
+++ b/nptl/lowlevellock.c
@@ -115,7 +115,7 @@  __lll_timedwait_tid (int *tidp, const struct timespec *abstime)
 
       /* Wait until thread terminates.  The kernel so far does not use
 	 the private futex operations for this.  */
-      if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT)
+      if (lll_futex_timed_wait_cancel (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT)
 	return ETIMEDOUT;
     }
 
diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
index 9f7b20a..cad7d11 100644
--- a/nptl/nptl-init.c
+++ b/nptl/nptl-init.c
@@ -188,36 +188,41 @@  sigcancel_handler (int sig, siginfo_t *si, void *ctx)
     return;
 
   struct pthread *self = THREAD_SELF;
+  volatile struct pthread *pd = (volatile struct pthread *) self;
+  ucontext_t *uc = ctx;
+  const char *tip = (const char *)__pthread_get_ip (ctx);
 
-  int oldval = THREAD_GETMEM (self, cancelhandling);
-  while (1)
+  extern const char __syscall_cancel_arch_start[1];
+  extern const char __syscall_cancel_arch_end[1];
+
+  if (((pd->cancelhandling & (CANCELSTATE_BITMASK)) != 0)
+      || ((pd->cancelhandling & CANCELED_BITMASK) == 0))
+    return;
+
+  __sigaddset (&uc->uc_sigmask, SIGCANCEL);
+
+  /* Check if asynchronous cancellation mode is set and if interrupted
+     instruction pointer falls within the cancellable syscall code.  For
+     interruptable syscalls that might generate external side-effects (partial
+     reads or writes, for instance), the kernel will set the IP to after
+     '__syscall_cancel_arch_end', thus disabling the cancellation and allowing
+     the process to handle such conditions.  */
+  if (pd->cancelhandling & CANCELTYPE_BITMASK ||
+      (tip >= __syscall_cancel_arch_start && tip < __syscall_cancel_arch_end))
     {
-      /* We are canceled now.  When canceled by another thread this flag
-	 is already set but if the signal is directly send (internally or
-	 from another process) is has to be done here.  */
-      int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
-
-      if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
-	/* Already canceled or exiting.  */
-	break;
-
-      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
-					      oldval);
-      if (curval == oldval)
-	{
-	  /* Set the return value.  */
-	  THREAD_SETMEM (self, result, PTHREAD_CANCELED);
-
-	  /* Make sure asynchronous cancellation is still enabled.  */
-	  if ((newval & CANCELTYPE_BITMASK) != 0)
-	    /* Run the registered destructors and terminate the thread.  */
-	    __do_cancel ();
-
-	  break;
-	}
-
-      oldval = curval;
+      THREAD_ATOMIC_BIT_SET (self, cancelhandling, EXITING_BIT);
+      THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+
+      /* __pthread_sigmask removes SIGCANCEL from the set.  */
+      INTERNAL_SYSCALL_DECL (err);
+      INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIGCANCEL, &uc->uc_sigmask, 0,
+                        _NSIG / 8);
+
+      __do_cancel ();
     }
+
+  INLINE_SYSCALL (tgkill, 3, THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
+		  SIGCANCEL);
 }
 
 
@@ -375,7 +380,10 @@  __pthread_initialize_minimal_internal (void)
      it is only asynchronous cancellation which is affected.  */
   struct sigaction sa;
   sa.sa_sigaction = sigcancel_handler;
-  sa.sa_flags = SA_SIGINFO;
+  /* The signal handle should be non-interruptible to avoid the risk of
+     spurious EINTR caused by SIGCANCEL sent to process or if pthread_cancel
+     is called while cancellation is disabled in the target thread.  */
+  sa.sa_flags = SA_SIGINFO | SA_RESTART;
   __sigemptyset (&sa.sa_mask);
 
   (void) __libc_sigaction (SIGCANCEL, &sa, NULL);
diff --git a/nptl/pt-system.c b/nptl/pt-system.c
index 4fc1bf2..20d976a 100644
--- a/nptl/pt-system.c
+++ b/nptl/pt-system.c
@@ -27,6 +27,3 @@  system (const char *line)
 {
   return __libc_system (line);
 }
-
-/* __libc_system in libc.so handles cancellation.  */
-LIBC_CANCEL_HANDLED ();
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index d4415ba..74994ec 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -272,49 +272,31 @@  __do_cancel (void)
   struct pthread *self = THREAD_SELF;
 
   /* Make sure we get no more cancellations.  */
-  THREAD_ATOMIC_BIT_SET (self, cancelhandling, EXITING_BIT);
+  int oldval = THREAD_GETMEM (self, cancelhandling);
+  while (1)
+    {
+      int newval = (oldval | CANCELSTATE_BITMASK);
+      newval &= ~(CANCELTYPE_BITMASK);
+      if (oldval == newval)
+	break;
+
+      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
+					  oldval);
+      if (__glibc_likely (curval == oldval))
+	break;
+      oldval = curval;
+    }
+
+  THREAD_SETMEM (self, result, PTHREAD_CANCELED);
 
   __pthread_unwind ((__pthread_unwind_buf_t *)
 		    THREAD_GETMEM (self, cleanup_jmp_buf));
 }
 
-
-/* Set cancellation mode to asynchronous.  */
-#define CANCEL_ASYNC() \
-  __pthread_enable_asynccancel ()
-/* Reset to previous cancellation mode.  */
-#define CANCEL_RESET(oldtype) \
-  __pthread_disable_asynccancel (oldtype)
-
-#if !defined NOT_IN_libc
-/* Same as CANCEL_ASYNC, but for use in libc.so.  */
-# define LIBC_CANCEL_ASYNC() \
-  __libc_enable_asynccancel ()
-/* Same as CANCEL_RESET, but for use in libc.so.  */
-# define LIBC_CANCEL_RESET(oldtype) \
-  __libc_disable_asynccancel (oldtype)
-# define LIBC_CANCEL_HANDLED() \
-  __asm (".globl " __SYMBOL_PREFIX "__libc_enable_asynccancel"); \
-  __asm (".globl " __SYMBOL_PREFIX "__libc_disable_asynccancel")
-#elif defined IS_IN_libpthread
-# define LIBC_CANCEL_ASYNC() CANCEL_ASYNC ()
-# define LIBC_CANCEL_RESET(val) CANCEL_RESET (val)
-# define LIBC_CANCEL_HANDLED() \
-  __asm (".globl " __SYMBOL_PREFIX "__pthread_enable_asynccancel"); \
-  __asm (".globl " __SYMBOL_PREFIX "__pthread_disable_asynccancel")
-#elif defined IS_IN_librt
-# define LIBC_CANCEL_ASYNC() \
-  __librt_enable_asynccancel ()
-# define LIBC_CANCEL_RESET(val) \
-  __librt_disable_asynccancel (val)
-# define LIBC_CANCEL_HANDLED() \
-  __asm (".globl " __SYMBOL_PREFIX "__librt_enable_asynccancel"); \
-  __asm (".globl " __SYMBOL_PREFIX "__librt_disable_asynccancel")
-#else
-# define LIBC_CANCEL_ASYNC()	0 /* Just a dummy value.  */
-# define LIBC_CANCEL_RESET(val)	((void)(val)) /* Nothing, but evaluate it.  */
-# define LIBC_CANCEL_HANDLED()	/* Nothing.  */
-#endif
+extern long int __syscall_cancel_arch (volatile void *, long int nr, long int arg1,
+				       long int arg2, long int arg3, long int arg4,
+				       long int arg5, long int arg6);
+libc_hidden_proto (__syscall_cancel_arch);
 
 
 /* Internal prototypes.  */
@@ -482,9 +464,6 @@  extern int __pthread_equal (pthread_t thread1, pthread_t thread2);
 extern int __pthread_kill (pthread_t threadid, int signo);
 extern void __pthread_exit (void *value) __attribute__ ((__noreturn__));
 extern int __pthread_setcanceltype (int type, int *oldtype);
-extern int __pthread_enable_asynccancel (void) attribute_hidden;
-extern void __pthread_disable_asynccancel (int oldtype)
-     internal_function attribute_hidden;
 
 #ifdef IS_IN_libpthread
 hidden_proto (__pthread_mutex_init)
@@ -514,16 +493,6 @@  extern int __pthread_cond_wait_2_0 (pthread_cond_2_0_t *cond,
 extern int __pthread_getaffinity_np (pthread_t th, size_t cpusetsize,
 				     cpu_set_t *cpuset);
 
-/* The two functions are in libc.so and not exported.  */
-extern int __libc_enable_asynccancel (void) attribute_hidden;
-extern void __libc_disable_asynccancel (int oldtype)
-     internal_function attribute_hidden;
-
-
-/* The two functions are in librt.so and not exported.  */
-extern int __librt_enable_asynccancel (void) attribute_hidden;
-extern void __librt_disable_asynccancel (int oldtype)
-     internal_function attribute_hidden;
 
 #ifdef IS_IN_libpthread
 /* Special versions which use non-exported functions.  */
diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
index aeba1ff..810deec 100644
--- a/nptl/pthread_cancel.c
+++ b/nptl/pthread_cancel.c
@@ -18,14 +18,12 @@ 
 
 #include <errno.h>
 #include <signal.h>
-#include "pthreadP.h"
-#include "atomic.h"
+#include <pthreadP.h>
+#include <atomic.h>
 #include <sysdep.h>
 
-
 int
-pthread_cancel (th)
-     pthread_t th;
+pthread_cancel (pthread_t th)
 {
   volatile struct pthread *pd = (volatile struct pthread *) th;
 
@@ -37,67 +35,10 @@  pthread_cancel (th)
 #ifdef SHARED
   pthread_cancel_init ();
 #endif
-  int result = 0;
-  int oldval;
-  int newval;
-  do
-    {
-    again:
-      oldval = pd->cancelhandling;
-      newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
-
-      /* Avoid doing unnecessary work.  The atomic operation can
-	 potentially be expensive if the bug has to be locked and
-	 remote cache lines have to be invalidated.  */
-      if (oldval == newval)
-	break;
-
-      /* If the cancellation is handled asynchronously just send a
-	 signal.  We avoid this if possible since it's more
-	 expensive.  */
-      if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
-	{
-	  /* Mark the cancellation as "in progress".  */
-	  if (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling,
-						    oldval | CANCELING_BITMASK,
-						    oldval))
-	    goto again;
-
-	  /* The cancellation handler will take care of marking the
-	     thread as canceled.  */
-	  INTERNAL_SYSCALL_DECL (err);
 
-	  /* One comment: The PID field in the TCB can temporarily be
-	     changed (in fork).  But this must not affect this code
-	     here.  Since this function would have to be called while
-	     the thread is executing fork, it would have to happen in
-	     a signal handler.  But this is no allowed, pthread_cancel
-	     is not guaranteed to be async-safe.  */
-	  int val;
-	  val = INTERNAL_SYSCALL (tgkill, err, 3,
-				  THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
-				  SIGCANCEL);
-
-	  if (INTERNAL_SYSCALL_ERROR_P (val, err))
-	    result = INTERNAL_SYSCALL_ERRNO (val, err);
-
-	  break;
-	}
-
-	/* A single-threaded process should be able to kill itself, since there is
-	   nothing in the POSIX specification that says that it cannot.  So we set
-	   multiple_threads to true so that cancellation points get executed.  */
-	THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
-#ifndef TLS_MULTIPLE_THREADS_IN_TCB
-	__pthread_multiple_threads = *__libc_multiple_threads_ptr = 1;
-#endif
-    }
-  /* Mark the thread as canceled.  This has to be done
-     atomically since other bits could be modified as well.  */
-  while (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, newval,
-					       oldval));
+  THREAD_ATOMIC_BIT_SET (pd, cancelhandling, CANCELED_BIT);
 
-  return result;
+  return __pthread_kill (th, SIGCANCEL);
 }
 
 PTHREAD_STATIC_FN_REQUIRE (pthread_create)
diff --git a/nptl/pthread_cond_timedwait.c b/nptl/pthread_cond_timedwait.c
index 1698085..5cf0796 100644
--- a/nptl/pthread_cond_timedwait.c
+++ b/nptl/pthread_cond_timedwait.c
@@ -41,17 +41,14 @@  extern void __condvar_cleanup (void *arg)
 
 struct _condvar_cleanup_buffer
 {
-  int oldtype;
   pthread_cond_t *cond;
   pthread_mutex_t *mutex;
   unsigned int bc_seq;
 };
 
 int
-__pthread_cond_timedwait (cond, mutex, abstime)
-     pthread_cond_t *cond;
-     pthread_mutex_t *mutex;
-     const struct timespec *abstime;
+__pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
+			  const struct timespec *abstime)
 {
   struct _pthread_cleanup_buffer buffer;
   struct _condvar_cleanup_buffer cbuffer;
@@ -157,12 +154,9 @@  __pthread_cond_timedwait (cond, mutex, abstime)
       /* Prepare to wait.  Release the condvar futex.  */
       lll_unlock (cond->__data.__lock, pshared);
 
-      /* Enable asynchronous cancellation.  Required by the standard.  */
-      cbuffer.oldtype = __pthread_enable_asynccancel ();
-
 /* REQUEUE_PI was implemented after FUTEX_CLOCK_REALTIME, so it is sufficient
    to check just the former.  */
-#if (defined lll_futex_timed_wait_requeue_pi \
+#if (defined lll_futex_timed_wait_requeue_pi_cancel \
      && defined __ASSUME_REQUEUE_PI)
       /* If pi_flag remained 1 then it means that we had the lock and the mutex
 	 but a spurious waker raced ahead of us.  Give back the mutex before
@@ -178,10 +172,11 @@  __pthread_cond_timedwait (cond, mutex, abstime)
 	{
 	  unsigned int clockbit = (cond->__data.__nwaiters & 1
 				   ? 0 : FUTEX_CLOCK_REALTIME);
-	  err = lll_futex_timed_wait_requeue_pi (&cond->__data.__futex,
-						 futex_val, abstime, clockbit,
-						 &mutex->__data.__lock,
-						 pshared);
+	  err = lll_futex_timed_wait_requeue_pi_cancel (&cond->__data.__futex,
+							futex_val, abstime,
+							clockbit,
+							&mutex->__data.__lock,
+							pshared);
 	  pi_flag = (err == 0);
 	}
       else
@@ -189,21 +184,18 @@  __pthread_cond_timedwait (cond, mutex, abstime)
 
 	{
 #if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
-     || !defined lll_futex_timed_wait_bitset)
+     || !defined lll_futex_timed_wait_bitset_cancel)
 	  /* Wait until woken by signal or broadcast.  */
-	  err = lll_futex_timed_wait (&cond->__data.__futex,
-				      futex_val, &rt, pshared);
+	  err = lll_futex_timed_wait_cancel (&cond->__data.__futex,
+					     futex_val, &rt, pshared);
 #else
 	  unsigned int clockbit = (cond->__data.__nwaiters & 1
 				   ? 0 : FUTEX_CLOCK_REALTIME);
-	  err = lll_futex_timed_wait_bitset (&cond->__data.__futex, futex_val,
-					     abstime, clockbit, pshared);
+	  err = lll_futex_timed_wait_bitset_cancel (&cond->__data.__futex, futex_val,
+					            abstime, clockbit, pshared);
 #endif
 	}
 
-      /* Disable asynchronous cancellation.  */
-      __pthread_disable_asynccancel (cbuffer.oldtype);
-
       /* We are going to look at shared data again, so get the lock.  */
       lll_lock (cond->__data.__lock, pshared);
 
diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
index fc5eac4..e3052b2 100644
--- a/nptl/pthread_cond_wait.c
+++ b/nptl/pthread_cond_wait.c
@@ -29,7 +29,6 @@ 
 
 struct _condvar_cleanup_buffer
 {
-  int oldtype;
   pthread_cond_t *cond;
   pthread_mutex_t *mutex;
   unsigned int bc_seq;
@@ -98,9 +97,7 @@  __condvar_cleanup (void *arg)
 
 
 int
-__pthread_cond_wait (cond, mutex)
-     pthread_cond_t *cond;
-     pthread_mutex_t *mutex;
+__pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
   struct _pthread_cleanup_buffer buffer;
   struct _condvar_cleanup_buffer cbuffer;
@@ -159,10 +156,7 @@  __pthread_cond_wait (cond, mutex)
       /* Prepare to wait.  Release the condvar futex.  */
       lll_unlock (cond->__data.__lock, pshared);
 
-      /* Enable asynchronous cancellation.  Required by the standard.  */
-      cbuffer.oldtype = __pthread_enable_asynccancel ();
-
-#if (defined lll_futex_wait_requeue_pi \
+#if (defined lll_futex_timed_wait_bitset_cancel \
      && defined __ASSUME_REQUEUE_PI)
       /* If pi_flag remained 1 then it means that we had the lock and the mutex
 	 but a spurious waker raced ahead of us.  Give back the mutex before
@@ -176,19 +170,17 @@  __pthread_cond_wait (cond, mutex)
 
       if (pi_flag)
 	{
-	  err = lll_futex_wait_requeue_pi (&cond->__data.__futex,
-					   futex_val, &mutex->__data.__lock,
-					   pshared);
+	  err = lll_futex_wait_requeue_pi_cancel (&cond->__data.__futex,
+						  futex_val,
+						  &mutex->__data.__lock,
+						  pshared);
 
 	  pi_flag = (err == 0);
 	}
       else
 #endif
 	  /* Wait until woken by signal or broadcast.  */
-	lll_futex_wait (&cond->__data.__futex, futex_val, pshared);
-
-      /* Disable asynchronous cancellation.  */
-      __pthread_disable_asynccancel (cbuffer.oldtype);
+	lll_futex_wait_cancel (&cond->__data.__futex, futex_val, pshared);
 
       /* We are going to look at shared data again, so get the lock.  */
       lll_lock (cond->__data.__lock, pshared);
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index b9af010..8eee243 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -266,7 +266,7 @@  start_thread (void *arg)
   /* If the parent was running cancellation handlers while creating
      the thread the new thread inherited the signal mask.  Reset the
      cancellation signal mask.  */
-  if (__glibc_unlikely (pd->parent_cancelhandling & CANCELING_BITMASK))
+  if (__glibc_unlikely (pd->parent_cancelhandling & CANCELED_BITMASK))
     {
       INTERNAL_SYSCALL_DECL (err);
       sigset_t mask;
@@ -293,14 +293,10 @@  start_thread (void *arg)
 
       if (__glibc_unlikely (pd->stopped_start))
 	{
-	  int oldtype = CANCEL_ASYNC ();
-
 	  /* Get the lock the parent locked to force synchronization.  */
 	  lll_lock (pd->lock, LLL_PRIVATE);
 	  /* And give it up right away.  */
 	  lll_unlock (pd->lock, LLL_PRIVATE);
-
-	  CANCEL_RESET (oldtype);
 	}
 
       LIBC_PROBE (pthread_start, 3, (pthread_t) pd, pd->start_routine, pd->arg);
diff --git a/nptl/pthread_exit.c b/nptl/pthread_exit.c
index 33d80d6..4068bf5 100644
--- a/nptl/pthread_exit.c
+++ b/nptl/pthread_exit.c
@@ -21,12 +21,16 @@ 
 
 
 void
-__pthread_exit (value)
-     void *value;
+__pthread_exit (void *value)
 {
-  THREAD_SETMEM (THREAD_SELF, result, value);
+  struct pthread *self = THREAD_SELF;
 
-  __do_cancel ();
+  THREAD_SETMEM (self, result, value);
+
+  THREAD_ATOMIC_BIT_SET (self, cancelhandling, EXITING_BIT);
+
+  __pthread_unwind ((__pthread_unwind_buf_t *)
+		    THREAD_GETMEM (self, cleanup_jmp_buf));
 }
 strong_alias (__pthread_exit, pthread_exit)
 
diff --git a/nptl/pthread_join.c b/nptl/pthread_join.c
index 5a43182..88ae5c9 100644
--- a/nptl/pthread_join.c
+++ b/nptl/pthread_join.c
@@ -37,9 +37,7 @@  cleanup (void *arg)
 
 
 int
-pthread_join (threadid, thread_return)
-     pthread_t threadid;
-     void **thread_return;
+pthread_join (pthread_t threadid, void **thread_return)
 {
   struct pthread *pd = (struct pthread *) threadid;
 
@@ -63,13 +61,10 @@  pthread_join (threadid, thread_return)
      un-wait-ed for again.  */
   pthread_cleanup_push (cleanup, &pd->joinid);
 
-  /* Switch to asynchronous cancellation.  */
-  int oldtype = CANCEL_ASYNC ();
-
   if ((pd == self
        || (self->joinid == pd
 	   && (pd->cancelhandling
-	       & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK
+	       & (CANCELED_BITMASK | EXITING_BITMASK
 		  | TERMINATED_BITMASK)) == 0))
       && !CANCEL_ENABLED_AND_CANCELED (self->cancelhandling))
     /* This is a deadlock situation.  The threads are waiting for each
@@ -91,10 +86,6 @@  pthread_join (threadid, thread_return)
     /* Wait for the child.  */
     lll_wait_tid (pd->tid);
 
-
-  /* Restore cancellation mode.  */
-  CANCEL_RESET (oldtype);
-
   /* Remove the handler.  */
   pthread_cleanup_pop (0);
 
diff --git a/nptl/pthread_timedjoin.c b/nptl/pthread_timedjoin.c
index 2f6701b..df2a2ee 100644
--- a/nptl/pthread_timedjoin.c
+++ b/nptl/pthread_timedjoin.c
@@ -30,10 +30,8 @@  cleanup (void *arg)
 
 
 int
-pthread_timedjoin_np (threadid, thread_return, abstime)
-     pthread_t threadid;
-     void **thread_return;
-     const struct timespec *abstime;
+pthread_timedjoin_np (pthread_t threadid, void **thread_return,
+		      const struct timespec *abstime)
 {
   struct pthread *self;
   struct pthread *pd = (struct pthread *) threadid;
@@ -73,17 +71,9 @@  pthread_timedjoin_np (threadid, thread_return, abstime)
      un-wait-ed for again.  */
   pthread_cleanup_push (cleanup, &pd->joinid);
 
-  /* Switch to asynchronous cancellation.  */
-  int oldtype = CANCEL_ASYNC ();
-
-
   /* Wait for the child.  */
   result = lll_timedwait_tid (pd->tid, abstime);
 
-
-  /* Restore cancellation mode.  */
-  CANCEL_RESET (oldtype);
-
   /* Remove the handler.  */
   pthread_cleanup_pop (0);
 
diff --git a/nptl/sem_timedwait.c b/nptl/sem_timedwait.c
index 7dfe51d..5fae92f 100644
--- a/nptl/sem_timedwait.c
+++ b/nptl/sem_timedwait.c
@@ -29,22 +29,6 @@ 
 
 extern void __sem_wait_cleanup (void *arg) attribute_hidden;
 
-/* This is in a seperate function in order to make sure gcc
-   puts the call site into an exception region, and thus the
-   cleanups get properly run.  */
-static int
-__attribute__ ((noinline))
-do_futex_timed_wait (struct new_sem *isem, struct timespec *rt)
-{
-  int err, oldtype = __pthread_enable_asynccancel ();
-
-  err = lll_futex_timed_wait (&isem->value, 0, rt,
-			      isem->private ^ FUTEX_PRIVATE_FLAG);
-
-  __pthread_disable_asynccancel (oldtype);
-  return err;
-}
-
 int
 sem_timedwait (sem_t *sem, const struct timespec *abstime)
 {
@@ -93,7 +77,8 @@  sem_timedwait (sem_t *sem, const struct timespec *abstime)
       /* Do wait.  */
       rt.tv_sec = sec;
       rt.tv_nsec = nsec;
-      err = do_futex_timed_wait(isem, &rt);
+      err = lll_futex_timed_wait_cancel (&isem->value, 0, &rt,
+				         isem->private ^ FUTEX_PRIVATE_FLAG);
       if (err != 0 && err != -EWOULDBLOCK)
 	{
 	  __set_errno (-err);
diff --git a/nptl/sem_wait.c b/nptl/sem_wait.c
index b12babb..7f995c9 100644
--- a/nptl/sem_wait.c
+++ b/nptl/sem_wait.c
@@ -37,21 +37,6 @@  __sem_wait_cleanup (void *arg)
   atomic_decrement (&isem->nwaiters);
 }
 
-/* This is in a seperate function in order to make sure gcc
-   puts the call site into an exception region, and thus the
-   cleanups get properly run.  */
-static int
-__attribute__ ((noinline))
-do_futex_wait (struct new_sem *isem)
-{
-  int err, oldtype = __pthread_enable_asynccancel ();
-
-  err = lll_futex_wait (&isem->value, 0, isem->private ^ FUTEX_PRIVATE_FLAG);
-
-  __pthread_disable_asynccancel (oldtype);
-  return err;
-}
-
 int
 __new_sem_wait (sem_t *sem)
 {
@@ -67,7 +52,8 @@  __new_sem_wait (sem_t *sem)
 
   while (1)
     {
-      err = do_futex_wait(isem);
+      err = lll_futex_wait_cancel (&isem->value, 0,
+				   isem->private ^ FUTEX_PRIVATE_FLAG);
       if (err != 0 && err != -EWOULDBLOCK)
 	{
 	  __set_errno (-err);
@@ -104,14 +90,8 @@  __old_sem_wait (sem_t *sem)
       if (atomic_decrement_if_positive (futex) > 0)
 	return 0;
 
-      /* Enable asynchronous cancellation.  Required by the standard.  */
-      int oldtype = __pthread_enable_asynccancel ();
-
       /* Always assume the semaphore is shared.  */
-      err = lll_futex_wait (futex, 0, LLL_SHARED);
-
-      /* Disable asynchronous cancellation.  */
-      __pthread_disable_asynccancel (oldtype);
+      err = lll_futex_wait_cancel (futex, 0, LLL_SHARED);
     }
   while (err == 0 || err == -EWOULDBLOCK);
 
diff --git a/rt/Makefile b/rt/Makefile
index 875deb3..c9af7d8 100644
--- a/rt/Makefile
+++ b/rt/Makefile
@@ -62,7 +62,6 @@  include ../Rules
 
 CFLAGS-aio_suspend.c = -fexceptions
 CFLAGS-clock_nanosleep.c = -fexceptions -fasynchronous-unwind-tables
-CFLAGS-librt-cancellation.c = -fasynchronous-unwind-tables
 
 LDFLAGS-rt.so = -Wl,--enable-new-dtags,-z,nodelete
 
diff --git a/sysdeps/generic/sysdep-cancel.h b/sysdeps/generic/sysdep-cancel.h
index ba6a1e0..5c84b44 100644
--- a/sysdeps/generic/sysdep-cancel.h
+++ b/sysdeps/generic/sysdep-cancel.h
@@ -3,6 +3,3 @@ 
 /* No multi-thread handling enabled.  */
 #define SINGLE_THREAD_P (1)
 #define RTLD_SINGLE_THREAD_P (1)
-#define LIBC_CANCEL_ASYNC()	0 /* Just a dummy value.  */
-#define LIBC_CANCEL_RESET(val)	((void)(val)) /* Nothing, but evaluate it.  */
-#define LIBC_CANCEL_HANDLED()	/* Nothing.  */
diff --git a/sysdeps/nptl/Makefile b/sysdeps/nptl/Makefile
index bedf39b..3cdf2fd 100644
--- a/sysdeps/nptl/Makefile
+++ b/sysdeps/nptl/Makefile
@@ -21,8 +21,7 @@  libpthread-sysdep_routines += errno-loc
 endif
 
 ifeq ($(subdir),rt)
-librt-sysdep_routines += timer_routines librt-cancellation
-CFLAGS-librt-cancellation.c += -fexceptions -fasynchronous-unwind-tables
+librt-sysdep_routines += timer_routines
 
 ifeq ($(have-forced-unwind),yes)
 tests += tst-mqueue8x
diff --git a/sysdeps/nptl/aio_misc.h b/sysdeps/nptl/aio_misc.h
index c3de84b..e34c548 100644
--- a/sysdeps/nptl/aio_misc.h
+++ b/sysdeps/nptl/aio_misc.h
@@ -41,15 +41,15 @@ 
       {									      \
 	pthread_mutex_unlock (&__aio_requests_mutex);			      \
 									      \
-	int oldtype;							      \
-	if (cancel)							      \
-	  oldtype = LIBC_CANCEL_ASYNC ();				      \
-									      \
 	int status;							      \
 	do								      \
 	  {								      \
-	    status = lll_futex_timed_wait (futexaddr, oldval, timeout,	      \
-					   LLL_PRIVATE);		      \
+	    if (cancel)							      \
+	      status = lll_futex_timed_wait_cancel (futexaddr, oldval,	      \
+						    timeout, LLL_PRIVATE);    \
+	    else							      \
+	      status = lll_futex_timed_wait (futexaddr, oldval, timeout,      \
+					     LLL_PRIVATE);		      \
 	    if (status != -EWOULDBLOCK)					      \
 	      break;							      \
 									      \
@@ -57,9 +57,6 @@ 
 	  }								      \
 	while (oldval != 0);						      \
 									      \
-	if (cancel)							      \
-	  LIBC_CANCEL_RESET (oldtype);					      \
-									      \
 	if (status == -EINTR)						      \
 	  result = EINTR;						      \
 	else if (status == -ETIMEDOUT)					      \
diff --git a/sysdeps/nptl/gai_misc.h b/sysdeps/nptl/gai_misc.h
index 942f2b1..40301aa 100644
--- a/sysdeps/nptl/gai_misc.h
+++ b/sysdeps/nptl/gai_misc.h
@@ -42,15 +42,15 @@ 
       {									      \
 	pthread_mutex_unlock (&__gai_requests_mutex);			      \
 									      \
-	int oldtype;							      \
-	if (cancel)							      \
-	  oldtype = LIBC_CANCEL_ASYNC ();				      \
-									      \
 	int status;							      \
 	do								      \
 	  {								      \
-	    status = lll_futex_timed_wait (futexaddr, oldval, timeout,	      \
-					   LLL_PRIVATE);		      \
+	    if (cancel)							      \
+	      status = lll_futex_timed_wait_cancel (futexaddr, oldval,	      \
+						    timeout, LLL_PRIVATE);    \
+	    else							      \
+	      status = lll_futex_timed_wait (futexaddr, oldval, timeout,      \
+					     LLL_PRIVATE);		      \
 	    if (status != -EWOULDBLOCK)					      \
 	      break;							      \
 									      \
@@ -58,9 +58,6 @@ 
 	  }								      \
 	while (oldval != 0);						      \
 									      \
-	if (cancel)							      \
-	  LIBC_CANCEL_RESET (oldtype);					      \
-									      \
 	if (status == -EINTR)						      \
 	  result = EINTR;						      \
 	else if (status == -ETIMEDOUT)					      \
diff --git a/sysdeps/nptl/librt-cancellation.c b/sysdeps/nptl/librt-cancellation.c
deleted file mode 100644
index c0258ba..0000000
--- a/sysdeps/nptl/librt-cancellation.c
+++ /dev/null
@@ -1,24 +0,0 @@ 
-/* Copyright (C) 2002-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
-
-   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 <nptl/pthreadP.h>
-
-
-#define __pthread_enable_asynccancel __librt_enable_asynccancel
-#define __pthread_disable_asynccancel __librt_disable_asynccancel
-#include <nptl/cancellation.c>
diff --git a/sysdeps/nptl/lowlevellock.h b/sysdeps/nptl/lowlevellock.h
index 28f4ba3..abfd528 100644
--- a/sysdeps/nptl/lowlevellock.h
+++ b/sysdeps/nptl/lowlevellock.h
@@ -172,7 +172,7 @@  extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
   do {					\
     __typeof (tid) __tid;		\
     while ((__tid = (tid)) != 0)	\
-      lll_futex_wait (&(tid), __tid, LLL_SHARED);\
+      lll_futex_wait_cancel (&(tid), __tid, LLL_SHARED);\
   } while (0)
 
 extern int __lll_timedwait_tid (int *, const struct timespec *)
diff --git a/sysdeps/posix/sigpause.c b/sysdeps/posix/sigpause.c
index 3dcf86c..6210861 100644
--- a/sysdeps/posix/sigpause.c
+++ b/sysdeps/posix/sigpause.c
@@ -50,16 +50,7 @@  do_sigpause (int sig_or_mask, int is_sig)
 int
 __sigpause (int sig_or_mask, int is_sig)
 {
-  if (SINGLE_THREAD_P)
-    return do_sigpause (sig_or_mask, is_sig);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = do_sigpause (sig_or_mask, is_sig);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return do_sigpause (sig_or_mask, is_sig);
 }
 libc_hidden_def (__sigpause)
 
diff --git a/sysdeps/posix/waitid.c b/sysdeps/posix/waitid.c
index a1f8cc8..9832831 100644
--- a/sysdeps/posix/waitid.c
+++ b/sysdeps/posix/waitid.c
@@ -155,16 +155,7 @@  __waitid (idtype, id, infop, options)
      siginfo_t *infop;
      int options;
 {
-  if (SINGLE_THREAD_P)
-    return do_waitid (idtype, id, infop, options);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = do_waitid (idtype, id, infop, options);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return do_waitid (idtype, id, infop, options);
 }
 weak_alias (__waitid, waitid)
 strong_alias (__waitid, __libc_waitid)
diff --git a/sysdeps/powerpc/nptl/pthreaddef.h b/sysdeps/powerpc/nptl/pthreaddef.h
index 5c6a0cd..5fe1cdb 100644
--- a/sysdeps/powerpc/nptl/pthreaddef.h
+++ b/sysdeps/powerpc/nptl/pthreaddef.h
@@ -15,6 +15,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	(4 * 1024 * 1024)
 
@@ -31,3 +34,11 @@ 
 
 /* Location of current stack frame.  */
 #define CURRENT_STACK_FRAME	__builtin_frame_address (0)
+
+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/sysdep.h b/sysdeps/unix/sysdep.h
index 7310820..77cc35c 100644
--- a/sysdeps/unix/sysdep.h
+++ b/sysdeps/unix/sysdep.h
@@ -20,10 +20,62 @@ 
 #include <sys/syscall.h>
 #define	HAVE_SYSCALLS
 
-/* Note that using a `PASTE' macro loses.  */
+#ifndef __ASSEMBLER__
+# include <errno.h>
+
 #define	SYSCALL__(name, args)	PSEUDO (__##name, name, args)
 #define	SYSCALL(name, args)	PSEUDO (name, name, args)
 
+#define __SSC(__x) ((long int) (__x))
+#define __SYSCALL_CANCEL0(__n) \
+  (__syscall_cancel)(__n, 0, 0, 0, 0, 0, 0)
+#define __SYSCALL_CANCEL1(__n, __a) \
+  (__syscall_cancel)(__n, __SSC(__a), 0, 0, 0, 0, 0)
+#define __SYSCALL_CANCEL2(__n, __a, __b) \
+  (__syscall_cancel)(__n, __SSC(__a), __SSC(__b), 0, 0, 0, 0)
+#define __SYSCALL_CANCEL3(__n, __a, __b, __c) \
+  (__syscall_cancel)(__n, __SSC(__a), __SSC(__b), __SSC(__c), 0, 0, 0)
+#define __SYSCALL_CANCEL4(__n, __a, __b, __c, __d) \
+  (__syscall_cancel)(__n, __SSC(__a), __SSC(__b), __SSC(__c), __SSC(__d), \
+		     0, 0)
+#define __SYSCALL_CANCEL5(__n, __a, __b, __c, __d, __e) \
+  (__syscall_cancel)(__n, __SSC(__a), __SSC(__b), __SSC(__c), __SSC(__d), \
+		     __SSC(__e), 0)
+#define __SYSCALL_CANCEL6(__n, __a, __b, __c, __d, __e, __f) \
+  (__syscall_cancel)(__n, __SSC(__a), __SSC(__b), __SSC(__c), __SSC(__d), \
+		     __SSC(__e), __SSC(__f))
+
+#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n
+#define __SYSCALL_NARGS(...) \
+  __SYSCALL_NARGS_X (__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0,)
+#define __SYSCALL_CONCAT_X(__a,__b)	__a##__b
+#define __SYSCALL_CONCAT(__a,__b)	__SYSCALL_CONCAT_X (__a, __b)
+#define __SYSCALL_DISP(__b,...) \
+  __SYSCALL_CONCAT (__b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)
+
+#define __SYSCALL_CANCEL(...) __SYSCALL_DISP (__SYSCALL_CANCEL, __VA_ARGS__)
+
+#define SYSCALL_CANCEL_NCS(name, nr, args...)				\
+  __SYSCALL_CANCEL (__NR_##name, nr, args)
+
+#define SYSCALL_CANCEL(name, args...)					\
+  ({									\
+    long int sc_ret = SYSCALL_CANCEL_NCS (name, args);			\
+    if (SYSCALL_CANCEL_ERROR (sc_ret))					\
+      {									\
+        __set_errno (SYSCALL_CANCEL_ERRNO (sc_ret));			\
+        sc_ret = -1L;							\
+      }									\
+    sc_ret;								\
+  })
+
+long int __syscall_cancel (long int nr, long int arg1, long int arg2, long int arg3,
+		           long int arg4, long int arg5, long int arg6);
+libc_hidden_proto (__syscall_cancel);
+
+#endif
+
+
 /* Machine-dependent sysdep.h files are expected to define the macro
    PSEUDO (function_name, syscall_name) to emit assembly code to define the
    C-callable function FUNCTION_NAME to do system call SYSCALL_NAME.
diff --git a/sysdeps/unix/sysv/linux/accept4.c b/sysdeps/unix/sysv/linux/accept4.c
index a017224..a02dc35 100644
--- a/sysdeps/unix/sysv/linux/accept4.c
+++ b/sysdeps/unix/sysv/linux/accept4.c
@@ -37,16 +37,8 @@ 
 int
 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
 {
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, flags);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len,
+  int result = SYSCALL_CANCEL (accept4, fd, addr.__sockaddr__, addr_len,
 			       flags);
-
-  LIBC_CANCEL_RESET (oldtype);
-
   return result;
 }
 #elif defined __NR_socketcall
diff --git a/sysdeps/unix/sysv/linux/clock_nanosleep.c b/sysdeps/unix/sysv/linux/clock_nanosleep.c
index 174c0d0..1e83f63 100644
--- a/sysdeps/unix/sysv/linux/clock_nanosleep.c
+++ b/sysdeps/unix/sysv/linux/clock_nanosleep.c
@@ -28,7 +28,6 @@  int
 __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
 		   struct timespec *rem)
 {
-  INTERNAL_SYSCALL_DECL (err);
   int r;
 
   if (clock_id == CLOCK_THREAD_CPUTIME_ID)
@@ -36,19 +35,9 @@  __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
   if (clock_id == CLOCK_PROCESS_CPUTIME_ID)
     clock_id = MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED);
 
-  if (SINGLE_THREAD_P)
-    r = INTERNAL_SYSCALL (clock_nanosleep, err, 4, clock_id, flags, req, rem);
-  else
-    {
-      int oldstate = LIBC_CANCEL_ASYNC ();
+  r = SYSCALL_CANCEL_NCS (clock_nanosleep, clock_id, flags, req, rem);
 
-      r = INTERNAL_SYSCALL (clock_nanosleep, err, 4, clock_id, flags, req,
-			    rem);
-
-      LIBC_CANCEL_RESET (oldstate);
-    }
-
-  return (INTERNAL_SYSCALL_ERROR_P (r, err)
-	  ? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
+  return (SYSCALL_CANCEL_ERROR (r)
+	  ? SYSCALL_CANCEL_ERRNO (r) : 0);
 }
 weak_alias (__clock_nanosleep, clock_nanosleep)
diff --git a/sysdeps/unix/sysv/linux/epoll_pwait.c b/sysdeps/unix/sysv/linux/epoll_pwait.c
index 7d98755..bda4d6e 100644
--- a/sysdeps/unix/sysv/linux/epoll_pwait.c
+++ b/sysdeps/unix/sysv/linux/epoll_pwait.c
@@ -39,18 +39,8 @@  int epoll_pwait (int epfd, struct epoll_event *events,
 		 int maxevents, int timeout,
 		 const sigset_t *set)
 {
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (epoll_pwait, 6, epfd, events, maxevents, timeout,
-			   set, _NSIG / 8);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = INLINE_SYSCALL (epoll_pwait, 6, epfd, events, maxevents,
-			       timeout, set, _NSIG / 8);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (epoll_pwait, epfd, events, maxevents, timeout,
+			 set, _NSIG / 8);
 }
 
 #else
diff --git a/sysdeps/unix/sysv/linux/msgrcv.c b/sysdeps/unix/sysv/linux/msgrcv.c
index c62367e..72f3cf7 100644
--- a/sysdeps/unix/sysv/linux/msgrcv.c
+++ b/sysdeps/unix/sysv/linux/msgrcv.c
@@ -33,12 +33,7 @@  struct ipc_kludge
 
 
 ssize_t
-__libc_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg)
-     int msqid;
-     void *msgp;
-     size_t msgsz;
-     long int msgtyp;
-     int msgflg;
+__libc_msgrcv (int msqid, void *msgp, size_t msgsz, long int msgtyp, int msgflg)
 {
   /* The problem here is that Linux' calling convention only allows up to
      fives parameters to a system call.  */
@@ -47,16 +42,6 @@  __libc_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg)
   tmp.msgp = msgp;
   tmp.msgtyp = msgtyp;
 
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (ipc, 5, IPCOP_msgrcv, msqid, msgsz, msgflg, &tmp);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  ssize_t result = INLINE_SYSCALL (ipc, 5, IPCOP_msgrcv, msqid, msgsz, msgflg,
-				   &tmp);
-
-   LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (ipc, IPCOP_msgrcv, msqid, msgsz, msgflg, &tmp);
 }
 weak_alias (__libc_msgrcv, msgrcv)
diff --git a/sysdeps/unix/sysv/linux/msgsnd.c b/sysdeps/unix/sysv/linux/msgsnd.c
index cd397b1..5861a73 100644
--- a/sysdeps/unix/sysv/linux/msgsnd.c
+++ b/sysdeps/unix/sysv/linux/msgsnd.c
@@ -30,17 +30,7 @@  __libc_msgsnd (msqid, msgp, msgsz, msgflg)
      size_t msgsz;
      int msgflg;
 {
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (ipc, 5, IPCOP_msgsnd, msqid, msgsz,
-			   msgflg, (void *) msgp);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = INLINE_SYSCALL (ipc, 5, IPCOP_msgsnd, msqid, msgsz,
-			       msgflg, (void *) msgp);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (ipc, IPCOP_msgsnd, msqid, msgsz,
+			 msgflg, (void *) msgp);
 }
 weak_alias (__libc_msgsnd, msgsnd)
diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
index 14f5e8b..a20aa01 100644
--- a/sysdeps/unix/sysv/linux/not-cancel.h
+++ b/sysdeps/unix/sysv/linux/not-cancel.h
@@ -17,48 +17,49 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <sysdep.h>
+#ifndef NOT_CANCEL_H
+# define NOT_CANCEL_H
 
-#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
-extern int __open_nocancel (const char *, int, ...) attribute_hidden;
-extern int __close_nocancel (int) attribute_hidden;
-extern int __read_nocancel (int, void *, size_t) attribute_hidden;
-extern int __write_nocancel (int, const void *, size_t) attribute_hidden;
-extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden;
-extern int __openat_nocancel (int fd, const char *fname, int oflag,
-				mode_t mode) attribute_hidden;
-extern int __openat64_nocancel (int fd, const char *fname, int oflag,
-				  mode_t mode) attribute_hidden;
-#else
-# define __open_nocancel(name, ...) __open (name, __VA_ARGS__)
-# define __close_nocancel(fd) __close (fd)
-# define __read_nocancel(fd, buf, len) __read (fd, buf, len)
-# define __write_nocancel(fd, buf, len) __write (fd, buf, len)
-# define __waitpid_nocancel(pid, stat_loc, options) \
-  __waitpid (pid, stat_loc, options)
-# define __openat_nocancel(fd, fname, oflag, mode) \
-  openat (fd, fname, oflag, mode)
-# define __openat64_nocancel(fd, fname, oflag, mode) \
-  openat64 (fd, fname, oflag, mode)
-#endif
+#include <sysdep.h>
 
 /* Uncancelable open.  */
 #define open_not_cancel(name, flags, mode) \
-   __open_nocancel (name, flags, mode)
+  ({ int __ret = INLINE_SYSCALL (open, 3, name, flags, mode); \
+     __ret; })
 #define open_not_cancel_2(name, flags) \
-   __open_nocancel (name, flags)
+  ({ int __ret = INLINE_SYSCALL (open, 2, name, flags); \
+     __ret; })
+
+/* Uncancelable read.  */
+#define __read_nocancel(fd, buf, len) \
+  ({ ssize_t __ret = INLINE_SYSCALL (read, 3, fd, buf, len); \
+     __ret; })
+
+/* Uncancelable write.  */
+#define __write_nocancel(fd, buf, len) \
+  ({ ssize_t __ret = INLINE_SYSCALL (write, 3, fd, buf, len); \
+     __ret; })
 
 /* Uncancelable openat.  */
 #define openat_not_cancel(fd, fname, oflag, mode) \
-  __openat_nocancel (fd, fname, oflag, mode)
+  ({ int __ret = INLINE_SYSCALL (openat, 4, fd, fname, oflag, mode); \
+     __ret; })
 #define openat_not_cancel_3(fd, fname, oflag) \
-  __openat_nocancel (fd, fname, oflag, 0)
+  ({ int __ret = INLINE_SYSCALL (openat, 3, fd, fname, oflag); \
+     __ret; })
 #define openat64_not_cancel(fd, fname, oflag, mode) \
-  __openat64_nocancel (fd, fname, oflag, mode)
+  ({ int __ret = INLINE_SYSCALL (openat, 4, fd, fname, \
+				 oflag | O_LARGEFILE, mode); \
+     __ret; })
 #define openat64_not_cancel_3(fd, fname, oflag) \
-  __openat64_nocancel (fd, fname, oflag, 0)
+  ({ int __ret = INLINE_SYSCALL (openat, 3, fd, fname, \
+				 oflag | O_LARGEFILE); \
+     __ret; })
 
 /* Uncancelable close.  */
+#define __close_nocancel(fd) \
+ ({ int __ret = INLINE_SYSCALL (close, 1, fd); \
+    __ret; })
 #define close_not_cancel(fd) \
   __close_nocancel (fd)
 #define close_not_cancel_no_status(fd) \
@@ -83,17 +84,29 @@  extern int __openat64_nocancel (int fd, const char *fname, int oflag,
   __fcntl_nocancel (fd, cmd, val)
 
 /* Uncancelable waitpid.  */
-#define waitpid_not_cancel(pid, stat_loc, options) \
+#define waitpid_nocancel(pid, stat_loc, options) \
   INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL)
+#define waitpid_not_cancel(pid, stat_loc, options) \
+  waitpid_nocancel(pid, stat_loc, options)
 
 /* Uncancelable pause.  */
 #define pause_not_cancel() \
-  __pause_nocancel ()
+  ({ sigset_t set; 							     \
+     int __rc = INLINE_SYSCALL (rt_sigprocmask, 4, SIG_BLOCK, NULL, &set,    \
+				_NSIG / 8);				     \
+     if (__rc == 0)							     \
+       __rc = INLINE_SYSCALL (rt_sigsuspend, 2, &set, _NSIG / 8);	     \
+     __rc;								     \
+  })
 
 /* Uncancelable nanosleep.  */
 #define nanosleep_not_cancel(requested_time, remaining) \
-  __nanosleep_nocancel (requested_time, remaining)
+  ({ int __ret = INLINE_SYSCALL (nanosleep, 2, requested_time, remaining);   \
+     __ret; })
 
 /* Uncancelable sigsuspend.  */
 #define sigsuspend_not_cancel(set) \
-  __sigsuspend_nocancel (set)
+  ({ int __ret = INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);	     \
+     __ret; })
+
+#endif /* NOT_CANCEL_H  */
diff --git a/sysdeps/unix/sysv/linux/openat.c b/sysdeps/unix/sysv/linux/openat.c
index 36555b9..da74b68 100644
--- a/sysdeps/unix/sysv/linux/openat.c
+++ b/sysdeps/unix/sysv/linux/openat.c
@@ -31,27 +31,6 @@ 
 #endif
 
 
-#define OPENAT_NOT_CANCEL CONCAT (OPENAT)
-#define CONCAT(name) CONCAT2 (name)
-#define CONCAT2(name) __##name##_nocancel
-
-
-int
-OPENAT_NOT_CANCEL (fd, file, oflag, mode)
-     int fd;
-     const char *file;
-     int oflag;
-     mode_t mode;
-{
-
-  /* We have to add the O_LARGEFILE flag for openat64.  */
-#ifdef MORE_OFLAGS
-  oflag |= MORE_OFLAGS;
-#endif
-
-  return INLINE_SYSCALL (openat, 4, fd, file, oflag, mode);
-}
-
 #define UNDERIZE(name) UNDERIZE_1 (name)
 #define UNDERIZE_1(name) __##name
 #define __OPENAT UNDERIZE (OPENAT)
@@ -61,10 +40,7 @@  OPENAT_NOT_CANCEL (fd, file, oflag, mode)
    the directory associated with FD.  If OFLAG includes O_CREAT, a
    third argument is the file protection.  */
 int
-__OPENAT (fd, file, oflag)
-     int fd;
-     const char *file;
-     int oflag;
+__OPENAT (int fd, const char *file, int oflag, ...)
 {
   mode_t mode = 0;
   if (oflag & O_CREAT)
@@ -75,16 +51,12 @@  __OPENAT (fd, file, oflag)
       va_end (arg);
     }
 
-  if (SINGLE_THREAD_P)
-    return OPENAT_NOT_CANCEL (fd, file, oflag, mode);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int res = OPENAT_NOT_CANCEL (fd, file, oflag, mode);
-
-  LIBC_CANCEL_RESET (oldtype);
+  /* We have to add the O_LARGEFILE flag for openat64.  */
+#ifdef MORE_OFLAGS
+  oflag |= MORE_OFLAGS;
+#endif
 
-  return res;
+  return SYSCALL_CANCEL (openat, fd, file, oflag, mode);
 }
 libc_hidden_def (__OPENAT)
 weak_alias (__OPENAT, OPENAT)
diff --git a/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h b/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
index a651d23..9efebf6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
+++ b/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
@@ -103,6 +103,33 @@ 
     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \
   })
 
+#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_timed_wait_bitset_cancel(futexp, val, timespec, clockbit,   \
+					   private)			      \
+  ({                                                                          \
+    long int __ret;                                                           \
+    int __op = FUTEX_WAIT_BITSET | clockbit;                                  \
+                                                                              \
+    __ret = __syscall_cancel (__NR_futex, (long int) (futexp),		      \
+			      (long int)__lll_private_flag (__op, private),   \
+			      (long int)(val), (long int)(timespec), 0,	      \
+                              FUTEX_BITSET_MATCH_ANY);                        \
+    __ret;								      \
+  })
+
 #define lll_futex_wake(futexp, nr, private) \
   ({									      \
     INTERNAL_SYSCALL_DECL (__err);					      \
@@ -156,6 +183,22 @@ 
     INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \
   })
 
+#define lll_futex_wait_requeue_pi_cancel(futexp, val, mutex, private) \
+  lll_futex_timed_wait_requeue_pi_cancel (futexp, val, NULL, 0, mutex, private)
+
+#define lll_futex_timed_wait_requeue_pi_cancel(futexp, val, timespec, 	      \
+					       clockbit, mutex, private)      \
+  ({									      \
+    long int __ret;							      \
+    int __op = FUTEX_WAIT_REQUEUE_PI | clockbit;			      \
+									      \
+    __ret = __syscall_cancel (__NR_futex, (long int) (futexp),		      \
+			      (long int) __lll_private_flag (__op, private),  \
+			      (long int )(val), (long int) (timespec), 	      \
+			      (long int ) mutex, 0); 		      	      \
+    __ret;								      \
+  })
+
 #define lll_futex_cmp_requeue_pi(futexp, nr_wake, nr_move, mutex, val, priv)  \
   ({									      \
     INTERNAL_SYSCALL_DECL (__err);					      \
@@ -325,7 +368,7 @@  extern int __lll_robust_timedlock_wait
   do {									      \
     __typeof (tid) __tid;						      \
     while ((__tid = (tid)) != 0)					      \
-      lll_futex_wait (&(tid), __tid, LLL_SHARED);			      \
+      lll_futex_wait_cancel (&(tid), __tid, LLL_SHARED);		      \
   } while (0)
 
 extern int __lll_timedwait_tid (int *, const struct timespec *)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c
index a9252d7..a7e684c 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
+#ifndef 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, ...)
 {
@@ -53,16 +51,7 @@  __libc_fcntl (int fd, int cmd, ...)
   if (cmd >= F_GETLK64 && cmd <= F_SETLKW64)
     cmd -= F_GETLK64 - F_GETLK;
 
-  if (SINGLE_THREAD_P || cmd != F_SETLKW)
-    return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (fcntl, fd, cmd, arg);
 }
 libc_hidden_def (__libc_fcntl)
 
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pread.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pread.c
index d85ab90..1aa1057 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pread.c
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pread.c
@@ -27,28 +27,9 @@ 
 /* Consider moving to syscalls.list.  */
 
 ssize_t
-__libc_pread (fd, buf, count, offset)
-     int fd;
-     void *buf;
-     size_t count;
-     off_t offset;
+__libc_pread (int fd, void *buf, size_t count, off_t offset)
 {
-  ssize_t result;
-
-  if (SINGLE_THREAD_P)
-    {
-      result = INLINE_SYSCALL (pread, 4, fd, buf, count, offset);
-
-      return result;
-    }
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  result = INLINE_SYSCALL (pread, 4, fd, buf, count, offset);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (pread, fd, buf, count, offset);
 }
 
 strong_alias (__libc_pread, __pread)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pread64.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pread64.c
index 5bdeada..3679fa5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pread64.c
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pread64.c
@@ -26,28 +26,9 @@ 
 /* Consider moving to syscalls.list.  */
 
 ssize_t
-__libc_pread64 (fd, buf, count, offset)
-     int fd;
-     void *buf;
-     size_t count;
-     off64_t offset;
+__libc_pread64 (int fd, void *buf, size_t count, off64_t offset)
 {
-  ssize_t result;
-
-  if (SINGLE_THREAD_P)
-    {
-      result = INLINE_SYSCALL (pread, 4, fd, buf, count, offset);
-
-      return result;
-    }
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-   result = INLINE_SYSCALL (pread, 4, fd, buf, count, offset);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (pread, fd, buf, count, offset);
 }
 
 weak_alias (__libc_pread64, __pread64)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite.c
index 7577d2e..49b083e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite.c
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite.c
@@ -27,28 +27,9 @@ 
 /* Consider moving to syscalls.list.  */
 
 ssize_t
-__libc_pwrite (fd, buf, count, offset)
-     int fd;
-     const void *buf;
-     size_t count;
-     off_t offset;
+__libc_pwrite (int fd, const void *buf, size_t count, off_t offset)
 {
-  ssize_t result;
-
-  if (SINGLE_THREAD_P)
-    {
-      result = INLINE_SYSCALL (pwrite, 4, fd, buf, count, offset);
-
-      return result;
-    }
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  result = INLINE_SYSCALL (pwrite, 4, fd, buf, count, offset);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (pwrite, fd, buf, count, offset);
 }
 
 strong_alias (__libc_pwrite, __pwrite)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite64.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite64.c
index 26ea65a..6afaaa2 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite64.c
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pwrite64.c
@@ -26,28 +26,9 @@ 
 /* Consider moving to syscalls.list.  */
 
 ssize_t
-__libc_pwrite64 (fd, buf, count, offset)
-     int fd;
-     const void *buf;
-     size_t count;
-     off64_t offset;
+__libc_pwrite64 (int fd, const void *buf, size_t count, off64_t offset)
 {
-  ssize_t result;
-
-  if (SINGLE_THREAD_P)
-    {
-      result = INLINE_SYSCALL (pwrite, 4, fd, buf, count, offset);
-
-      return result;
-    }
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  result = INLINE_SYSCALL (pwrite, 4, fd, buf, count, offset);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (pwrite, fd, buf, count, offset);
 }
 
 weak_alias (__libc_pwrite64, __pwrite64)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/socket.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/socket.S
index 2a253e1..39b126d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/socket.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/socket.S
@@ -48,10 +48,10 @@ 
 
 #if _CALL_ELF == 2
 #define FRAMESIZE (FRAME_MIN_SIZE+16+64)
-#define stackblock (FRAME_MIN_SIZE+16)
+#define STACKBLOCK (FRAME_MIN_SIZE+16)
 #else
 #define FRAMESIZE (FRAME_MIN_SIZE+16)
-#define stackblock (FRAMESIZE+FRAME_PARM_SAVE) /* offset to parm save area.  */
+#define STACKBLOCK (FRAMESIZE+FRAME_PARM_SAVE) /* offset to parm save area.  */
 #endif
 
 	.text
@@ -59,75 +59,50 @@  ENTRY(__socket)
 	CALL_MCOUNT NARGS
 	stdu r1,-FRAMESIZE(r1)
 	cfi_adjust_cfa_offset(FRAMESIZE)
+
 #if NARGS >= 1
-	std  r3,stackblock(r1)
+	std  r3,STACKBLOCK(r1)
 #endif
 #if NARGS >= 2
-	std  r4,8+stackblock(r1)
+	std  r4,8+STACKBLOCK(r1)
 #endif
 #if NARGS >= 3
-	std  r5,16+stackblock(r1)
+	std  r5,16+STACKBLOCK(r1)
 #endif
 #if NARGS >= 4
-	std  r6,24+stackblock(r1)
+	std  r6,24+STACKBLOCK(r1)
 #endif
 #if NARGS >= 5
-	std  r7,32+stackblock(r1)
+	std  r7,32+STACKBLOCK(r1)
 #endif
 #if NARGS >= 6
-	std  r8,40+stackblock(r1)
+	std  r8,40+STACKBLOCK(r1)
 #endif
 #if NARGS >= 7
-	std  r9,48+stackblock(r1)
+	std  r9,48+STACKBLOCK(r1)
 #endif
 #if NARGS >= 8
-	std  r10,56+stackblock(r1)
+	std  r10,56+STACKBLOCK(r1)
 #endif
 #if NARGS >= 9
 #error too many arguments!
 #endif
-
-#if defined NEED_CANCELLATION && defined CENABLE
-	SINGLE_THREAD_P
-	bne-	.Lsocket_cancel
-#endif
-
-	li	r3,P(SOCKOP_,socket)
-	addi	r4,r1,stackblock
-	DO_CALL(SYS_ify(socketcall))
-	addi	r1,r1,FRAMESIZE
-	cfi_adjust_cfa_offset(-FRAMESIZE)
-	PSEUDO_RET
-
-#if defined NEED_CANCELLATION && defined CENABLE
-.Lsocket_cancel:
-	cfi_adjust_cfa_offset(FRAMESIZE)
 	mflr	r9
 	std	r9,FRAMESIZE+FRAME_LR_SAVE(r1)
-	cfi_offset (lr, FRAME_LR_SAVE)
-	CENABLE
-	std	r3,FRAME_MIN_SIZE+8(r1)
-	li	r3,P(SOCKOP_,socket)
-	addi	r4,r1,stackblock
-	DO_CALL(SYS_ify(socketcall))
-	mfcr	r0
-	std	r3,FRAME_MIN_SIZE(r1)
-	std	r0,FRAMESIZE+FRAME_CR_SAVE(r1)
-	cfi_offset (cr, FRAME_CR_SAVE)
-	ld  	r3,FRAME_MIN_SIZE+8(r1)
-	CDISABLE
-	ld	r4,FRAMESIZE+FRAME_LR_SAVE(r1)
-	ld	r0,FRAMESIZE+FRAME_CR_SAVE(r1)
-	ld	r3,FRAME_MIN_SIZE(r1)
-	mtlr	r4
-	mtcr	r0
+	cfi_offset(lr, FRAME_LR_SAVE);
+
+	li	r3,SYS_ify (socketcall)
+	li	r4,P(SOCKOP_,socket)
+	addi	r5,r1,STACKBLOCK
+	bl	HIDDEN_JUMPTARGET(__syscall_cancel)
+	nop
+	ld	r9,FRAMESIZE+FRAME_LR_SAVE(r1)
+	mtlr	r9
 	addi	r1,r1,FRAMESIZE
 	cfi_adjust_cfa_offset(-FRAMESIZE)
 	cfi_restore(lr)
-	cfi_restore(cr)
-	PSEUDO_RET
-#endif
-PSEUDO_END (__socket)
+	blr
+END (__socket)
 
 #ifndef NO_WEAK_ALIAS
 weak_alias (__socket, socket)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sync_file_range.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sync_file_range.c
index ed68705..48a3945 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sync_file_range.c
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sync_file_range.c
@@ -28,17 +28,7 @@ 
 int
 sync_file_range (int fd, __off64_t from, __off64_t to, unsigned int flags)
 {
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (sync_file_range2, 4, fd, flags, from, to);
-
-  int result;
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  result = INLINE_SYSCALL (sync_file_range2, 4, fd, flags, from, to);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (sync_file_range2, fd, flags, from, to);
 }
 #else
 int
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
index 5807d9d..05896a0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
@@ -31,116 +31,42 @@ 
 #  define DASHDASHPFX(str) __##str
 # endif
 
-#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
+# ifdef NOT_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):					\
-    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);				\
+    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;								\
+
+# undef PSEUDO_RET
+# define PSEUDO_RET							\
+    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
-
-# 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
-
-# ifdef 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 !defined NOT_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 defined 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
-
-# ifndef __ASSEMBLER__
-#  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);				\
-  cmpwi 10,0
-# endif
-
-#elif !defined __ASSEMBLER__
-
-# define SINGLE_THREAD_P (1)
-# define NO_CANCELLATION 1
+    blr
 
 #endif
 
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
index 93e454e..4922752 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
@@ -184,6 +184,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..4d9e5b5
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
@@ -0,0 +1,56 @@ 
+/* 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:
+
+	/*mflr	r10
+	std	r10,FRAME_LR_SAVE(r1)*/
+
+	lwz     r0,0(r3)
+	rldicl. r0,r0,62,63
+	beq     1f
+	b       __syscall_do_cancel
+	nop
+1:
+	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:
+
+	/*ld	r10,FRAME_LR_SAVE(r1)
+	mtlr	r10*/
+
+	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 0c11d2b..1684399 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;
+}
diff --git a/sysdeps/unix/sysv/linux/ppoll.c b/sysdeps/unix/sysv/linux/ppoll.c
index 4fceed1..ea04ddb 100644
--- a/sysdeps/unix/sysv/linux/ppoll.c
+++ b/sysdeps/unix/sysv/linux/ppoll.c
@@ -45,19 +45,7 @@  ppoll (struct pollfd *fds, nfds_t nfds, const struct timespec *timeout,
       timeout = &tval;
     }
 
-  int result;
-
-  if (SINGLE_THREAD_P)
-    result = INLINE_SYSCALL (ppoll, 5, fds, nfds, timeout, sigmask, _NSIG / 8);
-  else
-    {
-      int oldtype = LIBC_CANCEL_ASYNC ();
-
-      result = INLINE_SYSCALL (ppoll, 5, fds, nfds, timeout, sigmask,
-			       _NSIG / 8);
-
-      LIBC_CANCEL_RESET (oldtype);
-    }
+  int result = SYSCALL_CANCEL (ppoll, fds, nfds, timeout, sigmask, _NSIG / 8);
 
 # ifndef __ASSUME_PPOLL
   if (result == -1 && errno == ENOSYS)
diff --git a/sysdeps/unix/sysv/linux/pselect.c b/sysdeps/unix/sysv/linux/pselect.c
index b4e77c1..0a5bb5c 100644
--- a/sysdeps/unix/sysv/linux/pselect.c
+++ b/sysdeps/unix/sysv/linux/pselect.c
@@ -63,23 +63,12 @@  __pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 
 #ifndef CALL_PSELECT6
 # define CALL_PSELECT6(nfds, readfds, writefds, exceptfds, timeout, data) \
-  INLINE_SYSCALL (pselect6, 6, nfds, readfds, writefds, exceptfds,	      \
+  SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds,	      \
 		  timeout, data)
 #endif
 
-  if (SINGLE_THREAD_P)
-    result = CALL_PSELECT6 (nfds, readfds, writefds, exceptfds, timeout,
-			    &data);
-  else
-    {
-      int oldtype = LIBC_CANCEL_ASYNC ();
-
-      result = CALL_PSELECT6 (nfds, readfds, writefds, exceptfds, timeout,
-			      &data);
-
-      LIBC_CANCEL_RESET (oldtype);
-    }
-
+  result = CALL_PSELECT6 (nfds, readfds, writefds, exceptfds, timeout,
+			  &data);
 # ifndef __ASSUME_PSELECT
   if (result == -1 && errno == ENOSYS)
     result = __generic_pselect (nfds, readfds, writefds, exceptfds, timeout,
diff --git a/sysdeps/unix/sysv/linux/pthread_kill.c b/sysdeps/unix/sysv/linux/pthread_kill.c
index 0a4d862..b929645 100644
--- a/sysdeps/unix/sysv/linux/pthread_kill.c
+++ b/sysdeps/unix/sysv/linux/pthread_kill.c
@@ -24,9 +24,7 @@ 
 
 
 int
-__pthread_kill (threadid, signo)
-     pthread_t threadid;
-     int signo;
+__pthread_kill (pthread_t threadid, int signo)
 {
   struct pthread *pd = (struct pthread *) threadid;
 
@@ -43,9 +41,8 @@  __pthread_kill (threadid, signo)
     /* Not a valid thread handle.  */
     return ESRCH;
 
-  /* Disallow sending the signal we use for cancellation, timers,
-     for the setxid implementation.  */
-  if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID)
+  /* Disallow sending the signal we use for setxid implementation.  */
+  if (signo == SIGSETXID)
     return EINVAL;
 
   /* We have a special syscall to do the work.  */
diff --git a/sysdeps/unix/sysv/linux/readv.c b/sysdeps/unix/sysv/linux/readv.c
index a977d17..b6d9853 100644
--- a/sysdeps/unix/sysv/linux/readv.c
+++ b/sysdeps/unix/sysv/linux/readv.c
@@ -27,25 +27,9 @@ 
 /* Consider moving to syscalls.list.  */
 
 ssize_t
-__libc_readv (fd, vector, count)
-     int fd;
-     const struct iovec *vector;
-     int count;
+__libc_readv (int fd, const struct iovec *vector, int count)
 {
-  ssize_t result;
-
-  if (SINGLE_THREAD_P)
-    result = INLINE_SYSCALL (readv, 3, fd, vector, count);
-  else
-    {
-      int oldtype = LIBC_CANCEL_ASYNC ();
-
-      result = INLINE_SYSCALL (readv, 3, fd, vector, count);
-
-      LIBC_CANCEL_RESET (oldtype);
-    }
-
-  return result;
+  return SYSCALL_CANCEL (readv, fd, vector, count);
 }
 strong_alias (__libc_readv, __readv)
 weak_alias (__libc_readv, readv)
diff --git a/sysdeps/unix/sysv/linux/recvmmsg.c b/sysdeps/unix/sysv/linux/recvmmsg.c
index 57ddf31..95661a5 100644
--- a/sysdeps/unix/sysv/linux/recvmmsg.c
+++ b/sysdeps/unix/sysv/linux/recvmmsg.c
@@ -37,16 +37,7 @@  int
 recvmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags,
 	  const struct timespec *tmo)
 {
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (recvmmsg, 5, fd, vmessages, vlen, flags, tmo);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = INLINE_SYSCALL (recvmmsg, 5, fd, vmessages, vlen, flags, tmo);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags, tmo);
 }
 #elif defined __NR_socketcall
 # ifndef __ASSUME_RECVMMSG_SOCKETCALL
diff --git a/sysdeps/unix/sysv/linux/sendmmsg.c b/sysdeps/unix/sysv/linux/sendmmsg.c
index 3074066..b975370 100644
--- a/sysdeps/unix/sysv/linux/sendmmsg.c
+++ b/sysdeps/unix/sysv/linux/sendmmsg.c
@@ -36,16 +36,7 @@ 
 int
 __sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags)
 {
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (sendmmsg, 4, fd, vmessages, vlen, flags);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = INLINE_SYSCALL (sendmmsg, 4, fd, vmessages, vlen, flags);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (sendmmsg, fd, vmessages, vlen, flags);
 }
 libc_hidden_def (__sendmmsg)
 weak_alias (__sendmmsg, sendmmsg)
diff --git a/sysdeps/unix/sysv/linux/sigsuspend.c b/sysdeps/unix/sysv/linux/sigsuspend.c
index 3b393ad..80b56e0 100644
--- a/sysdeps/unix/sysv/linux/sigsuspend.c
+++ b/sysdeps/unix/sysv/linux/sigsuspend.c
@@ -22,29 +22,12 @@ 
 #include <sysdep-cancel.h>
 #include <sys/syscall.h>
 
-
-static inline int __attribute__ ((always_inline))
-do_sigsuspend (const sigset_t *set)
-{
-  return INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);
-}
-
 /* Change the set of blocked signals to SET,
    wait until a signal arrives, and restore the set of blocked signals.  */
 int
-__sigsuspend (set)
-     const sigset_t *set;
+__sigsuspend (const sigset_t *set)
 {
-  if (SINGLE_THREAD_P)
-    return do_sigsuspend (set);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = do_sigsuspend (set);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (rt_sigsuspend, set, _NSIG / 8);
 }
 libc_hidden_def (__sigsuspend)
 weak_alias (__sigsuspend, sigsuspend)
@@ -52,9 +35,8 @@  strong_alias (__sigsuspend, __libc_sigsuspend)
 
 #ifndef NO_CANCELLATION
 int
-__sigsuspend_nocancel (set)
-     const sigset_t *set;
+__sigsuspend_nocancel (const sigset_t *set)
 {
-  return do_sigsuspend (set);
+  return INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);
 }
 #endif
diff --git a/sysdeps/unix/sysv/linux/sigtimedwait.c b/sysdeps/unix/sysv/linux/sigtimedwait.c
index c7727cf..7b1ba00 100644
--- a/sysdeps/unix/sysv/linux/sigtimedwait.c
+++ b/sysdeps/unix/sysv/linux/sigtimedwait.c
@@ -51,7 +51,7 @@  do_sigtimedwait (const sigset_t *set, siginfo_t *info,
 
     /* XXX The size argument hopefully will have to be changed to the
        real size of the user-level sigset_t.  */
-  int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set,
+  int result = SYSCALL_CANCEL (rt_sigtimedwait, set,
 			       info, timeout, _NSIG / 8);
 
   /* The kernel generates a SI_TKILL code in si_code in case tkill is
@@ -67,23 +67,10 @@  do_sigtimedwait (const sigset_t *set, siginfo_t *info,
 
 /* Return any pending signal or wait for one for the given time.  */
 int
-__sigtimedwait (set, info, timeout)
-     const sigset_t *set;
-     siginfo_t *info;
-     const struct timespec *timeout;
+__sigtimedwait (const sigset_t *set, siginfo_t *info,
+		const struct timespec *timeout)
 {
-  if (SINGLE_THREAD_P)
-    return do_sigtimedwait (set, info, timeout);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.  */
-  int result = do_sigtimedwait (set, info, timeout);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return do_sigtimedwait (set, info, timeout);
 }
 libc_hidden_def (__sigtimedwait)
 weak_alias (__sigtimedwait, sigtimedwait)
diff --git a/sysdeps/unix/sysv/linux/sigwait.c b/sysdeps/unix/sysv/linux/sigwait.c
index b7ac868..6063cfc 100644
--- a/sysdeps/unix/sysv/linux/sigwait.c
+++ b/sysdeps/unix/sysv/linux/sigwait.c
@@ -55,51 +55,25 @@  do_sigwait (const sigset_t *set, int *sig)
 
   /* XXX The size argument hopefully will have to be changed to the
      real size of the user-level sigset_t.  */
-#ifdef INTERNAL_SYSCALL
-  INTERNAL_SYSCALL_DECL (err);
   do
-    ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, set,
-			    NULL, NULL, _NSIG / 8);
-  while (INTERNAL_SYSCALL_ERROR_P (ret, err)
-	 && INTERNAL_SYSCALL_ERRNO (ret, err) == EINTR);
-  if (! INTERNAL_SYSCALL_ERROR_P (ret, err))
+    ret = SYSCALL_CANCEL_NCS (rt_sigtimedwait, set, NULL, NULL, _NSIG / 8);
+  while (SYSCALL_CANCEL_ERROR (ret)
+	 && SYSCALL_CANCEL_ERRNO (ret) == EINTR);
+  if (!SYSCALL_CANCEL_ERROR (ret))
     {
       *sig = ret;
       ret = 0;
     }
   else
-    ret = INTERNAL_SYSCALL_ERRNO (ret, err);
-#else
-  do
-    ret = INLINE_SYSCALL (rt_sigtimedwait, 4, set, NULL, NULL, _NSIG / 8);
-  while (ret == -1 && errno == EINTR);
-  if (ret != -1)
-    {
-      *sig = ret;
-      ret = 0;
-    }
-  else
-    ret = errno;
-#endif
+    ret = SYSCALL_CANCEL_ERRNO (ret);
 
   return ret;
 }
 
 int
-__sigwait (set, sig)
-     const sigset_t *set;
-     int *sig;
+__sigwait (const sigset_t *set, int *sig)
 {
-  if (SINGLE_THREAD_P)
-    return do_sigwait (set, sig);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  int result = do_sigwait (set, sig);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return do_sigwait (set, sig);
 }
 libc_hidden_def (__sigwait)
 weak_alias (__sigwait, sigwait)
diff --git a/sysdeps/unix/sysv/linux/sigwaitinfo.c b/sysdeps/unix/sysv/linux/sigwaitinfo.c
index fa9b0b7..751a5fa 100644
--- a/sysdeps/unix/sysv/linux/sigwaitinfo.c
+++ b/sysdeps/unix/sysv/linux/sigwaitinfo.c
@@ -52,7 +52,7 @@  do_sigwaitinfo (const sigset_t *set, siginfo_t *info)
 
   /* XXX The size argument hopefully will have to be changed to the
      real size of the user-level sigset_t.  */
-  int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set,
+  int result = SYSCALL_CANCEL (rt_sigtimedwait, set,
 			       info, NULL, _NSIG / 8);
 
   /* The kernel generates a SI_TKILL code in si_code in case tkill is
@@ -72,18 +72,7 @@  __sigwaitinfo (set, info)
      const sigset_t *set;
      siginfo_t *info;
 {
-  if (SINGLE_THREAD_P)
-    return do_sigwaitinfo (set, info);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.  */
-  int result = do_sigwaitinfo (set, info);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return do_sigwaitinfo (set, info);
 }
 libc_hidden_def (__sigwaitinfo)
 weak_alias (__sigwaitinfo, sigwaitinfo)
diff --git a/sysdeps/unix/sysv/linux/sleep.c b/sysdeps/unix/sysv/linux/sleep.c
index 5411fd5..cae36f0 100644
--- a/sysdeps/unix/sysv/linux/sleep.c
+++ b/sysdeps/unix/sysv/linux/sleep.c
@@ -104,8 +104,6 @@  __sleep (unsigned int seconds)
 	 have to do anything here.  */
       if (oact.sa_handler == SIG_IGN)
 	{
-	  //__libc_cleanup_push (cl, &oset);
-
 	  /* We should leave SIGCHLD blocked.  */
 	  while (1)
 	    {
@@ -121,8 +119,6 @@  __sleep (unsigned int seconds)
 		}
 	    }
 
-	  //__libc_cleanup_pop (0);
-
 	  saved_errno = errno;
 	  /* Restore the original signal mask.  */
 	  (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
diff --git a/sysdeps/unix/sysv/linux/tcdrain.c b/sysdeps/unix/sysv/linux/tcdrain.c
index 5f33283..21f19f0 100644
--- a/sysdeps/unix/sysv/linux/tcdrain.c
+++ b/sysdeps/unix/sysv/linux/tcdrain.c
@@ -24,17 +24,7 @@ 
 int
 __libc_tcdrain (int fd)
 {
-  if (SINGLE_THREAD_P)
-    /* With an argument of 1, TCSBRK for output to be drain.  */
-    return INLINE_SYSCALL (ioctl, 3, fd, TCSBRK, 1);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
   /* With an argument of 1, TCSBRK for output to be drain.  */
-  int result = INLINE_SYSCALL (ioctl, 3, fd, TCSBRK, 1);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (ioctl, fd, TCSBRK, 1);
 }
 weak_alias (__libc_tcdrain, tcdrain)
diff --git a/sysdeps/unix/sysv/linux/timer_routines.c b/sysdeps/unix/sysv/linux/timer_routines.c
index 4ac9bbe..70f7b5d 100644
--- a/sysdeps/unix/sysv/linux/timer_routines.c
+++ b/sysdeps/unix/sysv/linux/timer_routines.c
@@ -84,15 +84,11 @@  timer_helper_thread (void *arg)
       /* sigwaitinfo cannot be used here, since it deletes
 	 SIGCANCEL == SIGTIMER from the set.  */
 
-      int oldtype = LIBC_CANCEL_ASYNC ();
-
       /* XXX The size argument hopefully will have to be changed to the
 	 real size of the user-level sigset_t.  */
-      int result = INLINE_SYSCALL (rt_sigtimedwait, 4, &ss, &si, NULL,
+      int result = SYSCALL_CANCEL (rt_sigtimedwait, &ss, &si, NULL,
 				   _NSIG / 8);
 
-      LIBC_CANCEL_RESET (oldtype);
-
       if (result > 0)
 	{
 	  if (si.si_code == SI_TIMER)
diff --git a/sysdeps/unix/sysv/linux/wait.c b/sysdeps/unix/sysv/linux/wait.c
index 905c233..de2ed60 100644
--- a/sysdeps/unix/sysv/linux/wait.c
+++ b/sysdeps/unix/sysv/linux/wait.c
@@ -26,18 +26,8 @@ 
 pid_t
 __libc_wait (__WAIT_STATUS_DEFN stat_loc)
 {
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
-			   (struct rusage *) NULL);
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  pid_t result = INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
-				 (struct rusage *) NULL);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (wait4, WAIT_ANY, stat_loc, 0,
+			 (struct rusage *) NULL);
 }
 
 weak_alias (__libc_wait, __wait)
diff --git a/sysdeps/unix/sysv/linux/waitid.c b/sysdeps/unix/sysv/linux/waitid.c
index e1dc8b8..58a0b71 100644
--- a/sysdeps/unix/sysv/linux/waitid.c
+++ b/sysdeps/unix/sysv/linux/waitid.c
@@ -26,7 +26,7 @@  do_waitid (idtype_t idtype, id_t id, siginfo_t *infop, int options)
 {
   /* The unused fifth argument is a `struct rusage *' that we could
      pass if we were using waitid to simulate wait3/wait4.  */
-  return INLINE_SYSCALL (waitid, 5, idtype, id, infop, options, NULL);
+  return SYSCALL_CANCEL (waitid, idtype, id, infop, options, NULL);
 }
 #define NO_DO_WAITID
 
diff --git a/sysdeps/unix/sysv/linux/waitpid.c b/sysdeps/unix/sysv/linux/waitpid.c
index c0a8682..62972f4 100644
--- a/sysdeps/unix/sysv/linux/waitpid.c
+++ b/sysdeps/unix/sysv/linux/waitpid.c
@@ -23,24 +23,11 @@ 
 __pid_t
 __libc_waitpid (__pid_t pid, int *stat_loc, int options)
 {
-  if (SINGLE_THREAD_P)
-    {
 #ifdef __NR_waitpid
-      return INLINE_SYSCALL (waitpid, 3, pid, stat_loc, options);
+  int result = SYSCALL_CANCEL (waitpid, pid, stat_loc, options);
 #else
-      return INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL);
+  int result = SYSCALL_CANCEL (wait4, pid, stat_loc, options, NULL);
 #endif
-    }
-
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-#ifdef __NR_waitpid
-  int result = INLINE_SYSCALL (waitpid, 3, pid, stat_loc, options);
-#else
-  int result = INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL);
-#endif
-
-  LIBC_CANCEL_RESET (oldtype);
 
   return result;
 }
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/fallocate.c b/sysdeps/unix/sysv/linux/wordsize-64/fallocate.c
index d75ad11..655d502 100644
--- a/sysdeps/unix/sysv/linux/wordsize-64/fallocate.c
+++ b/sysdeps/unix/sysv/linux/wordsize-64/fallocate.c
@@ -25,17 +25,7 @@  int
 fallocate (int fd, int mode, __off_t offset, __off_t len)
 {
 #ifdef __NR_fallocate
-  if (SINGLE_THREAD_P)
-    return INLINE_SYSCALL (fallocate, 4, fd, mode, offset, len);
-
-  int result;
-  int oldtype = LIBC_CANCEL_ASYNC ();
-
-  result = INLINE_SYSCALL (fallocate, 4, fd, mode, offset, len);
-
-  LIBC_CANCEL_RESET (oldtype);
-
-  return result;
+  return SYSCALL_CANCEL (fallocate, fd, mode, offset, len);
 #else
   __set_errno (ENOSYS);
   return -1;
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/openat.c b/sysdeps/unix/sysv/linux/wordsize-64/openat.c
index 12e0271..b0f8a0c 100644
--- a/sysdeps/unix/sysv/linux/wordsize-64/openat.c
+++ b/sysdeps/unix/sysv/linux/wordsize-64/openat.c
@@ -1,5 +1,4 @@ 
 #define __openat64 __rename___openat64
-#define __openat64_nocancel __rename___openat64_nocancel
 #define openat64 __rename_openat64
 
 #include "../openat.c"
@@ -10,5 +9,4 @@ 
 
 strong_alias (__openat, __openat64)
 hidden_ver (__openat, __openat64)
-strong_alias (__openat_nocancel, __openat64_nocancel)
 weak_alias (openat, openat64)
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/preadv.c b/sysdeps/unix/sysv/linux/wordsize-64/preadv.c
index 9ddd71e..ae33f46 100644
--- a/sysdeps/unix/sysv/linux/wordsize-64/preadv.c
+++ b/sysdeps/unix/sysv/linux/wordsize-64/preadv.c
@@ -37,17 +37,7 @@  preadv (int fd, const struct iovec *vector, int count, off_t offset)
 {
 #ifdef __NR_preadv
   ssize_t result;
-
-  if (SINGLE_THREAD_P)
-    result = INLINE_SYSCALL (preadv, 4, fd, vector, count, offset);
-  else
-    {
-      int oldtype = LIBC_CANCEL_ASYNC ();
-
-      result = INLINE_SYSCALL (preadv, 4, fd, vector, count, offset);
-
-      LIBC_CANCEL_RESET (oldtype);
-    }
+  result = SYSCALL_CANCEL (preadv, 4, fd, vector, count, offset);
 # ifdef __ASSUME_PREADV
   return result;
 # endif
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/pwritev.c b/sysdeps/unix/sysv/linux/wordsize-64/pwritev.c
index 9035a20..db34a68 100644
--- a/sysdeps/unix/sysv/linux/wordsize-64/pwritev.c
+++ b/sysdeps/unix/sysv/linux/wordsize-64/pwritev.c
@@ -37,17 +37,7 @@  pwritev (int fd, const struct iovec *vector, int count, off_t offset)
 {
 #ifdef __NR_pwritev
   ssize_t result;
-
-  if (SINGLE_THREAD_P)
-    result = INLINE_SYSCALL (pwritev, 4, fd, vector, count, offset);
-  else
-    {
-      int oldtype = LIBC_CANCEL_ASYNC ();
-
-      result = INLINE_SYSCALL (pwritev, 4, fd, vector, count, offset);
-
-      LIBC_CANCEL_RESET (oldtype);
-    }
+  result = SYSCALL_CANCEL (pwritev, fd, vector, count, offset);
 # ifdef __ASSUME_PWRITEV
   return result;
 # endif
diff --git a/sysdeps/unix/sysv/linux/writev.c b/sysdeps/unix/sysv/linux/writev.c
index f19221f..b7ef71d 100644
--- a/sysdeps/unix/sysv/linux/writev.c
+++ b/sysdeps/unix/sysv/linux/writev.c
@@ -28,25 +28,9 @@ 
 /* Consider moving to syscalls.list.  */
 
 ssize_t
-__libc_writev (fd, vector, count)
-     int fd;
-     const struct iovec *vector;
-     int count;
+__libc_writev (int fd, const struct iovec *vector, int count)
 {
-  ssize_t result;
-
-  if (SINGLE_THREAD_P)
-    result = INLINE_SYSCALL (writev, 3, fd, vector, count);
-  else
-    {
-      int oldtype = LIBC_CANCEL_ASYNC ();
-
-      result = INLINE_SYSCALL (writev, 3, fd, vector, count);
-
-      LIBC_CANCEL_RESET (oldtype);
-    }
-
-  return result;
+  return SYSCALL_CANCEL (writev, fd, vector, count);
 }
 strong_alias (__libc_writev, __writev)
 weak_alias (__libc_writev, writev)