GNU C Library master sources branch azanella/bz12683 created. glibc-2.22-380-gb7f07c5
azanella@sourceware.org
azanella@sourceware.org
Mon Oct 12 18:24:00 GMT 2015
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".
The branch, azanella/bz12683 has been created
at b7f07c53f6abcf44b8fe5a62272ae0e44701d91e (commit)
- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b7f07c53f6abcf44b8fe5a62272ae0e44701d91e
commit b7f07c53f6abcf44b8fe5a62272ae0e44701d91e
Author: Adhemerval Zanella <adhemerval.zanella@linaro.com>
Date: Wed Aug 12 11:13:21 2015 -0300
nptl: s390x: Fix Race conditions in pthread cancellation (BZ#12683)
This patch adds the s390 modifications required for the BZ#12683 fix.
It basically removes the enable_asynccancel/disable_asynccancel function
usage on code, provide a arch-specific symbol that contains global
markers to be used in SIGCANCEL handler.
Checked on s390x (thanks to Stefan Liebler <stli@linux.vnet.ibm.com>).
* sysdeps/unix/sysv/linux/s390/s390-64/syscall_cancel.S: New file.
* sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): Redefine
to call __syscall_cancel function for cancellable syscalls.
(__pthread_get_ip): Add implementation.
* sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h (SYSCALL_CANCEL_ERROR): Add
definition.
(SYSCALL_CANCEL_ERRNO): Likewise.
diff --git a/ChangeLog b/ChangeLog
index f5afdfb..698037d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,14 @@
2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
Stefan Liebler <stli@linux.vnet.ibm.com>
+ * sysdeps/unix/sysv/linux/s390/s390-64/syscall_cancel.S: New file.
+ * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): Redefine
+ to call __syscall_cancel function for cancellable syscalls.
+ (__pthread_get_ip): Add implementation.
+ * sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h (SYSCALL_CANCEL_ERROR): Add
+ definition.
+ (SYSCALL_CANCEL_ERRNO): Likewise.
+
* sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S: New file.
* sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Redefine
to call __syscall_cancel function for cancellable syscalls.
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/syscall_cancel.S b/sysdeps/unix/sysv/linux/s390/s390-64/syscall_cancel.S
new file mode 100644
index 0000000..2da44a5
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/syscall_cancel.S
@@ -0,0 +1,87 @@
+/* Cancellable syscall wrapper - s390x version.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* long int [r2] __syscall_cancel_arch (int *cancelhandling [r2],
+ long int nr [r3],
+ long int arg1 [r4],
+ long int arg2 [r5],
+ long int arg3 [r6],
+ long int arg4 [SP+160],
+ long int arg5 [SP+168],
+ long int arg6 [SP+176]) */
+
+ENTRY (__syscall_cancel_arch)
+
+ /* Save registers and setup stack. */
+ stmg %r6,%r15,48(%r15) /* Save registers. */
+ cfi_offset (%r15,-40)
+ cfi_offset (%r14,-48)
+ cfi_offset (%r13,-56)
+ cfi_offset (%r12,-64)
+ cfi_offset (%r11,-72)
+ cfi_offset (%r10,-80)
+ cfi_offset (%r9,-88)
+ cfi_offset (%r8,-96)
+ cfi_offset (%r7,-104)
+ cfi_offset (%r6,-112)
+ lgr %r1,%r15
+ lg %r0,8(%r15) /* Load eos. */
+ aghi %r15,-160 /* Buy stack space. */
+ cfi_adjust_cfa_offset (160)
+ stg %r1,0(%r15) /* Store back chain. */
+ stg %r0,8(%r15) /* Store eos. */
+
+ .globl __syscall_cancel_arch_start
+ .type __syscall_cancel_arch_start,@function
+__syscall_cancel_arch_start:
+
+ /* if (*cancelhandling & CANCELED_BITMASK)
+ __syscall_do_cancel() */
+ tm 3(%r2),4
+ jne 1f
+
+ /* Issue a 6 argument syscall */
+ lgr %r1,%r3 /* Move syscall number. */
+ lgr %r2,%r4 /* First parameter. */
+ lgr %r3,%r5 /* Second parameter. */
+ lgr %r4,%r6 /* Third parameter. */
+ lg %r5,320(%r15) /* Fourth parameter. */
+ lg %r6,328(%r15) /* Fifth parameter. */
+ lg %r7,336(%r15) /* Sixth parameter. */
+
+ svc 0 /* svc number is always in r1. */
+
+ .globl __syscall_cancel_arch_end
+ .type __syscall_cancel_arch_end,@function
+__syscall_cancel_arch_end:
+ lg %r15,0(%r15) /* load back chain */
+ cfi_adjust_cfa_offset (-160)
+ lmg %r6,%r15,48(%r15) /* Load registers. */
+
+ br %r14
+
+ /* Branch to __syscall_do_cancel */
+1:
+ lg %r15,0(%r15) /* load back chain */
+ cfi_adjust_cfa_offset (-160)
+ lmg %r6,%r15,48(%r15) /* Load registers. */
+ jg __syscall_do_cancel
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h b/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
index e054dc9..9b14e25 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
@@ -24,93 +24,85 @@
#if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt)
+# if IS_IN (libc)
+# define JMP_SYSCALL_CANCEL HIDDEN_JUMPTARGET(__syscall_cancel)
+# else
+# define JMP_SYSCALL_CANCEL __syscall_cancel@plt
+# endif
+
+# define STORE_0 /* Nothing */
+# define STORE_1 /* Nothing */
+# define STORE_2 /* Nothing */
+# define STORE_3 /* Nothing */
+# define STORE_4 stg %r6,48(%r15); \
+ cfi_offset (%r6,-112);
+# define STORE_5 STORE_4
+# define STORE_6 STORE_4
+
+# define LOAD_0 /* Nothing */
+# define LOAD_1 /* Nothing */
+# define LOAD_2 /* Nothing */
+# define LOAD_3 /* Nothing */
+# define LOAD_4 lg %r6,48(%r15);
+# define LOAD_5 LOAD_4
+# define LOAD_6 LOAD_4
+
+# define MOVE_ARGS_0
+# define MOVE_ARGS_1 lgr %r3,%r2; \
+ MOVE_ARGS_0
+# define MOVE_ARGS_2 lgr %r4,%r3; \
+ MOVE_ARGS_1
+# define MOVE_ARGS_3 lgr %r5,%r4; \
+ MOVE_ARGS_2
+# define MOVE_ARGS_4 lgr %r6,%r5; \
+ MOVE_ARGS_3
+# define MOVE_ARGS_5 stg %r6,160(%r15); \
+ MOVE_ARGS_4
+# define MOVE_ARGS_6 lg %r14,160(%r14); \
+ stg %r14,168(%r15); \
+ MOVE_ARGS_5
+
+
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.text; \
L(pseudo_cancel): \
cfi_startproc; \
- STM_##args \
- stmg %r13,%r15,104(%r15); \
+ stmg %r14,%r15,112(%r15); \
cfi_offset (%r15,-40); \
cfi_offset (%r14,-48); \
- cfi_offset (%r13,-56); \
+ STORE_##args \
lgr %r14,%r15; \
- aghi %r15,-160; \
- cfi_adjust_cfa_offset (160); \
+ aghi %r15,-176; \
+ cfi_adjust_cfa_offset (176); \
stg %r14,0(%r15); \
- brasl %r14,CENABLE; \
- lgr %r0,%r2; \
- LM_##args \
- .if SYS_ify (syscall_name) < 256; \
- svc SYS_ify (syscall_name); \
- .else; \
- lghi %r1,SYS_ify (syscall_name); \
- svc 0; \
- .endif; \
- LR7_##args \
- lgr %r13,%r2; \
- lgr %r2,%r0; \
- brasl %r14,CDISABLE; \
- lgr %r2,%r13; \
- lmg %r13,%r15,104+160(%r15); \
+ MOVE_ARGS_##args \
+ lghi %r2,SYS_ify (syscall_name); \
+ brasl %r14,JMP_SYSCALL_CANCEL; \
+ lmg %r14,%r15,112+176(%r15); \
+ cfi_restore (%r14); \
+ cfi_restore (%r15); \
+ LOAD_##args \
cfi_endproc; \
j L(pseudo_check); \
ENTRY(name) \
SINGLE_THREAD_P \
jne L(pseudo_cancel); \
-.type __##syscall_name##_nocancel,@function; \
-.globl __##syscall_name##_nocancel; \
-__##syscall_name##_nocancel: \
DO_CALL(syscall_name, args); \
L(pseudo_check): \
lghi %r4,-4095; \
clgr %r2,%r4; \
jgnl SYSCALL_ERROR_LABEL; \
-.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
L(pseudo_end):
# if IS_IN (libpthread)
-# define CENABLE __pthread_enable_asynccancel
-# define CDISABLE __pthread_disable_asynccancel
# define __local_multiple_threads __pthread_multiple_threads
# elif IS_IN (libc)
-# define CENABLE __libc_enable_asynccancel
-# define CDISABLE __libc_disable_asynccancel
# define __local_multiple_threads __libc_multiple_threads
-# elif IS_IN (librt)
-# define CENABLE __librt_enable_asynccancel
-# define CDISABLE __librt_disable_asynccancel
-# else
+# elif !IS_IN (librt)
# error Unsupported library
# endif
-#define STM_0 /* Nothing */
-#define STM_1 stg %r2,16(%r15);
-#define STM_2 stmg %r2,%r3,16(%r15);
-#define STM_3 stmg %r2,%r4,16(%r15);
-#define STM_4 stmg %r2,%r5,16(%r15);
-#define STM_5 stmg %r2,%r5,16(%r15);
-#define STM_6 stmg %r2,%r7,16(%r15);
-
-#define LM_0 /* Nothing */
-#define LM_1 lg %r2,16+160(%r15);
-#define LM_2 lmg %r2,%r3,16+160(%r15);
-#define LM_3 lmg %r2,%r4,16+160(%r15);
-#define LM_4 lmg %r2,%r5,16+160(%r15);
-#define LM_5 lmg %r2,%r5,16+160(%r15);
-#define LM_6 lmg %r2,%r5,16+160(%r15); \
- cfi_offset (%r7, -104); \
- lg %r7,160+160(%r15);
-
-#define LR7_0 /* Nothing */
-#define LR7_1 /* Nothing */
-#define LR7_2 /* Nothing */
-#define LR7_3 /* Nothing */
-#define LR7_4 /* Nothing */
-#define LR7_5 /* Nothing */
-#define LR7_6 lg %r7,56+160(%r15); \
- cfi_restore (%r7);
-
# if IS_IN (libpthread) || IS_IN (libc)
# ifndef __ASSEMBLER__
extern int __local_multiple_threads attribute_hidden;
@@ -149,4 +141,10 @@ extern int __local_multiple_threads attribute_hidden;
# define RTLD_SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
+
+static inline
+uintptr_t __pthread_get_pc (const struct ucontext *uc)
+{
+ return uc->uc_mcontext.psw.addr;
+}
#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h b/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h
index c041153..4be051e 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h
@@ -249,6 +249,14 @@
#undef INTERNAL_SYSCALL_ERRNO
#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
+#undef SYSCALL_CANCEL_ERROR
+#define SYSCALL_CANCEL_ERROR(__val) \
+ ((unsigned long) (__val) >= -4095UL)
+
+#undef SYSCALL_CANCEL_ERRNO
+#define SYSCALL_CANCEL_ERRNO(__val) \
+ (-(__val))
+
#define DECLARGS_0()
#define DECLARGS_1(arg1) \
register unsigned long gpr2 asm ("2") = (unsigned long)(arg1);
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=cedfebf784618b89d93310681a8b2216139f0b52
commit cedfebf784618b89d93310681a8b2216139f0b52
Author: Adhemerval Zanella <adhemerval.zanella@linaro.com>
Date: Wed Aug 12 10:51:38 2015 -0300
nptl: s390: Fix Race conditions in pthread cancellation (BZ#12683)
This patch adds the s390 modifications required for the BZ#12683 fix.
It basically removes the enable_asynccancel/disable_asynccancel function
usage on code, provide a arch-specific symbol that contains global
markers to be used in SIGCANCEL handler.
Checked on s390 (thanks to Stefan Liebler <stli@linux.vnet.ibm.com>).
* sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S: New file.
* sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Redefine
to call __syscall_cancel function for cancellable syscalls.
(__pthread_get_ip): Add implementation.
* sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h (SYSCALL_CANCEL_ERROR): Add
definition.
(SYSCALL_CANCEL_ERRNO): Likewise.
diff --git a/ChangeLog b/ChangeLog
index 6d323ca..f5afdfb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,15 @@
2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ Stefan Liebler <stli@linux.vnet.ibm.com>
+
+ * sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S: New file.
+ * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Redefine
+ to call __syscall_cancel function for cancellable syscalls.
+ (__pthread_get_ip): Add implementation.
+ * sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h (SYSCALL_CANCEL_ERROR): Add
+ definition.
+ (SYSCALL_CANCEL_ERRNO): Likewise.
+
+2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
* sysdeps/unix/sysv/linux/arm/syscall_cancel.S: New file.
* sysdeps/unix/sysv/linux/arm/sysdep-cancel.h (PSEUDO): Redefine
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S b/sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S
new file mode 100644
index 0000000..bf90acd
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/syscall_cancel.S
@@ -0,0 +1,85 @@
+/* Cancellable syscall wrapper - s390 version.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* long int [r2] __syscall_cancel_arch (int *cancelhandling [r2],
+ long int nr [r3],
+ long int arg1 [r4],
+ long int arg2 [r5],
+ long int arg3 [r6],
+ long int arg4 [SP+96],
+ long int arg5 [SP+100],
+ long int arg6 [SP+104]) */
+
+ENTRY (__syscall_cancel_arch)
+ /* Save registers and setup stack. */
+ stm %r6,%r15,24(%r15) /* Save registers */
+ cfi_offset (%r15, -36)
+ cfi_offset (%r14, -40)
+ cfi_offset (%r13, -44)
+ cfi_offset (%r12, -48)
+ cfi_offset (%r11, -52)
+ cfi_offset (%r10, -56)
+ cfi_offset (%r9, -60)
+ cfi_offset (%r8, -64)
+ cfi_offset (%r7, -68)
+ cfi_offset (%r6, -72)
+ lr %r1,%r15
+ l %r0,4(0,%r15) /* Load eos */
+ ahi %r15,-96 /* Buy stack space */
+ cfi_adjust_cfa_offset (96)
+ st %r1,0(0,%r15) /* Store back chain */
+ st %r0,4(0,%r15) /* Store eos */
+
+ .globl __syscall_cancel_arch_start
+ .type __syscall_cancel_arch_start,@function
+__syscall_cancel_arch_start:
+
+ /* if (*cancelhandling & CANCELED_BITMASK)
+ __syscall_do_cancel() */
+ tm 3(%r2),4
+ jne 1f
+
+ /* Issue a 6 argument syscall */
+ lr %r1,%r3 /* Move syscall number. */
+ lr %r2,%r4 /* First parameter. */
+ lr %r3,%r5 /* Second parameter. */
+ lr %r4,%r6 /* Third parameter. */
+ l %r5,192(%r15) /* Fourth parameter. */
+ l %r6,196(%r15) /* Fifth parameter. */
+ l %r7,200(%r15) /* Sixth parameter. */
+
+ svc 0 /* svc number is always in r1. */
+ .globl __syscall_cancel_arch_end
+ .type __syscall_cancel_arch_end,@function
+__syscall_cancel_arch_end:
+ l %r15,0(%r15) /* Load back chain. */
+ cfi_adjust_cfa_offset (-96)
+ lm %r6,15,24(%r15) /* Load registers. */
+
+ br %r14
+
+ /* Branch to __syscall_do_cancel */
+1:
+ l %r15,0(%r15) /* Load back chain. */
+ cfi_adjust_cfa_offset (-96)
+ lm %r6,%r15,24(%r15) /* Load registers. */
+ jg __syscall_do_cancel
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
index 17b7aaa..886784e 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
@@ -24,97 +24,90 @@
#if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt)
+# if IS_IN (libc)
+# define PREPARE_CALL
+# define PREPARE_GOT
+# define JMP_SYSCALL_CANCEL HIDDEN_JUMPTARGET(__syscall_cancel)
+# else
+# define PREPARE_CALL l %r12,2f-0b(%r13); \
+ la %r12,0(%r12,%r13);
+# define PREPARE_GOT 2: .long _GLOBAL_OFFSET_TABLE_-0b;
+# define JMP_SYSCALL_CANCEL __syscall_cancel@plt
+# endif
+
+# define STORE_0 /* Nothing */
+# define STORE_1 /* Nothing */
+# define STORE_2 /* Nothing */
+# define STORE_3 /* Nothing */
+# define STORE_4 st %r6,24(%r15); \
+ cfi_offset (%r6,-72);
+# define STORE_5 STORE_4
+# define STORE_6 STORE_4
+
+# define LOAD_0 /* Nothing */
+# define LOAD_1 /* Nothing */
+# define LOAD_2 /* Nothing */
+# define LOAD_3 /* Nothing */
+# define LOAD_4 l %r6,24(%r15);
+# define LOAD_5 LOAD_4
+# define LOAD_6 LOAD_4
+
+# define MOVE_ARGS_0
+# define MOVE_ARGS_1 lr %r3,%r2; \
+ MOVE_ARGS_0
+# define MOVE_ARGS_2 lr %r4,%r3; \
+ MOVE_ARGS_1
+# define MOVE_ARGS_3 lr %r5,%r4; \
+ MOVE_ARGS_2
+# define MOVE_ARGS_4 lr %r6,%r5; \
+ MOVE_ARGS_3
+# define MOVE_ARGS_5 st %r6,96(%r15); \
+ MOVE_ARGS_4
+# define MOVE_ARGS_6 l %r14,96(%r14); \
+ st %r14,100(%r15); \
+ MOVE_ARGS_5
+
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.text; \
L(pseudo_cancel): \
cfi_startproc; \
- STM_##args \
stm %r12,%r15,48(%r15); \
cfi_offset (%r15, -36); \
cfi_offset (%r14, -40); \
cfi_offset (%r13, -44); \
cfi_offset (%r12, -48); \
+ STORE_##args \
lr %r14,%r15; \
- ahi %r15,-96; \
- cfi_adjust_cfa_offset (96); \
+ ahi %r15,-104; \
+ cfi_adjust_cfa_offset (104); \
st %r14,0(%r15); \
+ MOVE_ARGS_##args \
+ lhi %r2,SYS_ify (syscall_name); \
basr %r13,0; \
0: l %r1,1f-0b(%r13); \
+ PREPARE_CALL \
bas %r14,0(%r1,%r13); \
- lr %r0,%r2; \
- LM_##args \
- .if SYS_ify (syscall_name) < 256; \
- svc SYS_ify (syscall_name); \
- .else; \
- lhi %r1,SYS_ify (syscall_name); \
- svc 0; \
- .endif; \
- LR7_##args \
- l %r1,2f-0b(%r13); \
- lr %r12,%r2; \
- lr %r2,%r0; \
- bas %r14,0(%r1,%r13); \
- lr %r2,%r12; \
- lm %r12,%r15,48+96(%r15); \
+ lm %r12,%r15,48+104(%r15); \
+ cfi_restore (%r12); \
+ cfi_restore (%r13); \
+ cfi_restore (%r14); \
+ cfi_restore (%r15); \
+ LOAD_##args \
cfi_endproc; \
j L(pseudo_check); \
-1: .long CENABLE-0b; \
-2: .long CDISABLE-0b; \
+1: .long JMP_SYSCALL_CANCEL-0b; \
+ PREPARE_GOT \
ENTRY(name) \
SINGLE_THREAD_P(%r1) \
jne L(pseudo_cancel); \
-.type __##syscall_name##_nocancel,@function; \
-.globl __##syscall_name##_nocancel; \
-__##syscall_name##_nocancel: \
DO_CALL(syscall_name, args); \
L(pseudo_check): \
lhi %r4,-4095; \
clr %r2,%r4; \
jnl SYSCALL_ERROR_LABEL; \
-.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
L(pseudo_end):
-# if IS_IN (libpthread)
-# define CENABLE __pthread_enable_asynccancel
-# define CDISABLE __pthread_disable_asynccancel
-# elif IS_IN (libc)
-# define CENABLE __libc_enable_asynccancel
-# define CDISABLE __libc_disable_asynccancel
-# elif IS_IN (librt)
-# define CENABLE __librt_enable_asynccancel
-# define CDISABLE __librt_disable_asynccancel
-# else
-# error Unsupported library
-# endif
-
-#define STM_0 /* Nothing */
-#define STM_1 st %r2,8(%r15);
-#define STM_2 stm %r2,%r3,8(%r15);
-#define STM_3 stm %r2,%r4,8(%r15);
-#define STM_4 stm %r2,%r5,8(%r15);
-#define STM_5 stm %r2,%r5,8(%r15);
-#define STM_6 stm %r2,%r7,8(%r15);
-
-#define LM_0 /* Nothing */
-#define LM_1 l %r2,8+96(%r15);
-#define LM_2 lm %r2,%r3,8+96(%r15);
-#define LM_3 lm %r2,%r4,8+96(%r15);
-#define LM_4 lm %r2,%r5,8+96(%r15);
-#define LM_5 lm %r2,%r5,8+96(%r15);
-#define LM_6 lm %r2,%r5,8+96(%r15); \
- cfi_offset (%r7, -68); \
- l %r7,96+96(%r15);
-
-#define LR7_0 /* Nothing */
-#define LR7_1 /* Nothing */
-#define LR7_2 /* Nothing */
-#define LR7_3 /* Nothing */
-#define LR7_4 /* Nothing */
-#define LR7_5 /* Nothing */
-#define LR7_6 l %r7,28+96(%r15); \
- cfi_restore (%r7);
-
# ifndef __ASSEMBLER__
# define SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
@@ -136,4 +129,11 @@ L(pseudo_end):
# define RTLD_SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
+
+static inline
+uintptr_t __pthread_get_pc (const struct ucontext *uc)
+{
+ /* We have 31bit addresses, remove bit 0. */
+ return uc->uc_mcontext.psw.addr & 0x7FFFFFFF;
+}
#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h
index c768df1..08e2be4 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h
@@ -243,6 +243,14 @@
#undef INTERNAL_SYSCALL_ERRNO
#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
+#undef SYSCALL_CANCEL_ERROR
+#define SYSCALL_CANCEL_ERROR(__val) \
+ ((unsigned int) (__val) >= 0xfffff001u)
+
+#undef SYSCALL_CANCEL_ERRNO
+#define SYSCALL_CANCEL_ERRNO(__val) \
+ (-(__val))
+
#define DECLARGS_0()
#define DECLARGS_1(arg1) \
register unsigned long gpr2 asm ("2") = (unsigned long)(arg1);
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=1600ca8aca5710cda24a2bccee3257c5d69cbcd4
commit 1600ca8aca5710cda24a2bccee3257c5d69cbcd4
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Fri May 8 17:12:31 2015 -0300
nptl: arm: Fix Race conditions in pthread cancellation (BZ#12683)
This patch adds the ARM modifications required for the BZ#12683 fix.
It basically removes the enable_asynccancel/disable_asynccancel function
usage on code, provide a arch-specific symbol that contains global
markers to be used in SIGCANCEL handler.
Checked on armhf.
* sysdeps/unix/sysv/linux/arm/syscall_cancel.S: New file.
* sysdeps/unix/sysv/linux/arm/sysdep-cancel.h (PSEUDO): Redefine
to call __syscall_cancel function for cancellable syscalls.
* sysdeps/unix/sysv/linux/arm/sysdep.h (SYSCALL_CANCEL_ERROR): Add
definition.
(SYSCALL_CANCEL_ERRNO): Likewise.
diff --git a/ChangeLog b/ChangeLog
index a76eca5..6d323ca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ * sysdeps/unix/sysv/linux/arm/syscall_cancel.S: New file.
+ * sysdeps/unix/sysv/linux/arm/sysdep-cancel.h (PSEUDO): Redefine
+ to call __syscall_cancel function for cancellable syscalls.
+ * sysdeps/unix/sysv/linux/arm/sysdep.h (SYSCALL_CANCEL_ERROR): Add
+ definition.
+ (SYSCALL_CANCEL_ERRNO): Likewise.
+
* sysdeps/unix/sysv/linux/aarch64/syscall_cancel.S: New file.
* sysdeps/unix/sysv/linux/aarch64/sysdep-cancel.h (PSEUDO): Redefine
to call __syscall_cancel function for cancellable syscalls.
diff --git a/sysdeps/unix/sysv/linux/arm/syscall_cancel.S b/sysdeps/unix/sysv/linux/arm/syscall_cancel.S
new file mode 100644
index 0000000..da4b454
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arm/syscall_cancel.S
@@ -0,0 +1,72 @@
+/* Cancellable syscall wrapper - arm version.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* long int [r0] __syscall_cancel_arch (int *cancelhandling [r0],
+ long int nr [r1],
+ long int arg1 [r2],
+ long int arg2 [r3],
+ long int arg3 [SP],
+ long int arg4 [SP+4],
+ long int arg5 [SP+8],
+ long int arg6 [SP+12]) */
+
+#ifdef __thumb2__
+ .thumb
+#endif
+ .syntax unified
+
+ENTRY (__syscall_cancel_arch)
+ .fnstart
+ mov ip,sp
+ stmfd sp!,{r4,r5,r6,lr}
+ .save {r4,r5,r6,lr}
+
+ cfi_adjust_cfa_offset (20)
+ cfi_rel_offset (lr, 16)
+
+ .globl __syscall_cancel_arch_start
+__syscall_cancel_arch_start:
+
+ /* if (*cancelhandling & CANCELED_BITMASK)
+ __syscall_do_cancel() */
+ ldr r0,[r0]
+ tst r0, #4
+ bne 1f
+
+ /* Issue a 6 argument syscall, the nr [r1] being the syscall
+ number. */
+ mov r7,r1
+ mov r0,r2
+ mov r1,r3
+ ldmfd ip,{r2,r3,r4,r5,r6}
+ svc 0x0
+
+ .globl __syscall_cancel_arch_end
+__syscall_cancel_arch_end:
+ ldmfd sp!,{r4,r5,r6,lr}
+ cfi_adjust_cfa_offset (-16);
+ bx lr
+
+1:
+ mov lr, pc
+ b __syscall_do_cancel
+ .fnend
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
diff --git a/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h b/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h
index bdefa80..5063c9d 100644
--- a/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h
@@ -19,10 +19,17 @@
#include <tls.h>
#ifndef __ASSEMBLER__
# include <nptl/pthreadP.h>
+# include <sys/ucontext.h>
#endif
#if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt)
+# if IS_IN (libc)
+# define JMP_SYSCALL_CANCEL HIDDEN_JUMPTARGET(__syscall_cancel)
+# else
+# define JMP_SYSCALL_CANCEL __syscall_cancel(PLT)
+# endif
+
/* NOTE: We do mark syscalls with unwind annotations, for the benefit of
cancellation; but they're really only accurate at the point of the
syscall. The ARM unwind directives are not rich enough without adding
@@ -31,16 +38,10 @@
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.text; \
- ENTRY (__##syscall_name##_nocancel); \
- CFI_SECTIONS; \
- DO_CALL (syscall_name, args); \
- cmn r0, $4096; \
- PSEUDO_RET; \
- END (__##syscall_name##_nocancel); \
ENTRY (name); \
SINGLE_THREAD_P; \
- DOARGS_##args; \
bne .Lpseudo_cancel; \
+ DOARGS_##args; \
cfi_remember_state; \
ldr r7, =SYS_ify (syscall_name); \
swi 0x0; \
@@ -50,150 +51,29 @@
cfi_restore_state; \
.Lpseudo_cancel: \
.fnstart; /* matched by the .fnend in UNDOARGS below. */ \
- DOCARGS_##args; /* save syscall args etc. around CENABLE. */ \
- CENABLE; \
- mov ip, r0; /* put mask in safe place. */ \
- UNDOCARGS_##args; /* restore syscall args. */ \
- ldr r7, =SYS_ify (syscall_name); \
- swi 0x0; /* do the call. */ \
- mov r7, r0; /* save syscall return value. */ \
- mov r0, ip; /* get mask back. */ \
- CDISABLE; \
- mov r0, r7; /* retrieve return value. */ \
- RESTORE_LR_##args; \
- UNDOARGS_##args; \
+ push {r4, r5, lr}; \
+ .save {r4, r5, lr}; \
+ .pad $20; \
+ sub sp, sp, $20; \
+ ldr r5, [sp, $32]; \
+ ldr r4, [sp, $36]; \
+ str r3, [sp]; \
+ mov r3, r2; \
+ str r5, [sp, $4]; \
+ mov r2, r1; \
+ str r4, [sp, $8]; \
+ mov r1, r0; \
+ ldr r0, =SYS_ify (syscall_name); \
+ bl JMP_SYSCALL_CANCEL; \
+ add sp, sp, $20; \
+ pop {r4, r5, lr}; \
+ .fnend; \
cmn r0, $4096
-/* DOARGS pushes eight bytes on the stack for five arguments, twelve bytes for
- six arguments, and four bytes for fewer. In order to preserve doubleword
- alignment, sometimes we must save an extra register. */
-
-# define RESTART_UNWIND \
- .fnend; \
- .fnstart; \
- .save {r7}; \
- .save {lr}
-
-# define DOCARGS_0 \
- .save {r7}; \
- push {lr}; \
- cfi_adjust_cfa_offset (4); \
- cfi_rel_offset (lr, 0); \
- .save {lr}
-# define UNDOCARGS_0
-# define RESTORE_LR_0 \
- pop {lr}; \
- cfi_adjust_cfa_offset (-4); \
- cfi_restore (lr)
-
-# define DOCARGS_1 \
- .save {r7}; \
- push {r0, r1, lr}; \
- cfi_adjust_cfa_offset (12); \
- cfi_rel_offset (lr, 8); \
- .save {lr}; \
- .pad #8
-# define UNDOCARGS_1 \
- ldr r0, [sp], #8; \
- cfi_adjust_cfa_offset (-8); \
- RESTART_UNWIND
-# define RESTORE_LR_1 \
- RESTORE_LR_0
-
-# define DOCARGS_2 \
- .save {r7}; \
- push {r0, r1, lr}; \
- cfi_adjust_cfa_offset (12); \
- cfi_rel_offset (lr, 8); \
- .save {lr}; \
- .pad #8
-# define UNDOCARGS_2 \
- pop {r0, r1}; \
- cfi_adjust_cfa_offset (-8); \
- RESTART_UNWIND
-# define RESTORE_LR_2 \
- RESTORE_LR_0
-
-# define DOCARGS_3 \
- .save {r7}; \
- push {r0, r1, r2, r3, lr}; \
- cfi_adjust_cfa_offset (20); \
- cfi_rel_offset (lr, 16); \
- .save {lr}; \
- .pad #16
-# define UNDOCARGS_3 \
- pop {r0, r1, r2, r3}; \
- cfi_adjust_cfa_offset (-16); \
- RESTART_UNWIND
-# define RESTORE_LR_3 \
- RESTORE_LR_0
-
-# define DOCARGS_4 \
- .save {r7}; \
- push {r0, r1, r2, r3, lr}; \
- cfi_adjust_cfa_offset (20); \
- cfi_rel_offset (lr, 16); \
- .save {lr}; \
- .pad #16
-# define UNDOCARGS_4 \
- pop {r0, r1, r2, r3}; \
- cfi_adjust_cfa_offset (-16); \
- RESTART_UNWIND
-# define RESTORE_LR_4 \
- RESTORE_LR_0
-
-/* r4 is only stmfd'ed for correct stack alignment. */
-# define DOCARGS_5 \
- .save {r4, r7}; \
- push {r0, r1, r2, r3, r4, lr}; \
- cfi_adjust_cfa_offset (24); \
- cfi_rel_offset (lr, 20); \
- .save {lr}; \
- .pad #20
-# define UNDOCARGS_5 \
- pop {r0, r1, r2, r3}; \
- cfi_adjust_cfa_offset (-16); \
- .fnend; \
- .fnstart; \
- .save {r4, r7}; \
- .save {lr}; \
- .pad #4
-# define RESTORE_LR_5 \
- pop {r4, lr}; \
- cfi_adjust_cfa_offset (-8); \
- /* r4 will be marked as restored later. */ \
- cfi_restore (lr)
-
-# define DOCARGS_6 \
- .save {r4, r5, r7}; \
- push {r0, r1, r2, r3, lr}; \
- cfi_adjust_cfa_offset (20); \
- cfi_rel_offset (lr, 16); \
- .save {lr}; \
- .pad #16
-# define UNDOCARGS_6 \
- pop {r0, r1, r2, r3}; \
- cfi_adjust_cfa_offset (-16); \
- .fnend; \
- .fnstart; \
- .save {r4, r5, r7}; \
- .save {lr};
-# define RESTORE_LR_6 \
- RESTORE_LR_0
-
# if IS_IN (libpthread)
-# define CENABLE bl PLTJMP(__pthread_enable_asynccancel)
-# define CDISABLE bl PLTJMP(__pthread_disable_asynccancel)
# define __local_multiple_threads __pthread_multiple_threads
# elif IS_IN (libc)
-# define CENABLE bl PLTJMP(__libc_enable_asynccancel)
-# define CDISABLE bl PLTJMP(__libc_disable_asynccancel)
# define __local_multiple_threads __libc_multiple_threads
-# elif IS_IN (librt)
-# define CENABLE bl PLTJMP(__librt_enable_asynccancel)
-# define CDISABLE bl PLTJMP(__librt_disable_asynccancel)
-# else
-# error Unsupported library
# endif
# if IS_IN (libpthread) || IS_IN (libc)
@@ -238,4 +118,10 @@ extern int __local_multiple_threads attribute_hidden;
# define RTLD_SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
+
+static inline
+uintptr_t __pthread_get_pc (const struct ucontext *uc)
+{
+ return uc->uc_mcontext.arm_pc;
+}
#endif
diff --git a/sysdeps/unix/sysv/linux/arm/sysdep.h b/sysdeps/unix/sysv/linux/arm/sysdep.h
index 200f77a..6b18e34 100644
--- a/sysdeps/unix/sysv/linux/arm/sysdep.h
+++ b/sysdeps/unix/sysv/linux/arm/sysdep.h
@@ -387,6 +387,14 @@ __local_syscall_error: \
#undef INTERNAL_SYSCALL_ERRNO
#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
+#undef SYSCALL_CANCEL_ERROR
+#define SYSCALL_CANCEL_ERROR(__val) \
+ ((unsigned int) (__val) >= 0xfffff001u)
+
+#undef SYSCALL_CANCEL_ERRNO
+#define SYSCALL_CANCEL_ERRNO(__val) \
+ (-(__val))
+
/* List of system calls which are supported as vsyscalls. */
#define HAVE_CLOCK_GETTIME_VSYSCALL 1
#define HAVE_GETTIMEOFDAY_VSYSCALL 1
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=248ecd8a3621901117c196328407579893e14682
commit 248ecd8a3621901117c196328407579893e14682
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Wed May 6 17:51:29 2015 -0300
nptl: aarch64: Fix Race conditions in pthread cancellation (BZ#12683)
This patch adds the aarch64 modifications required for the BZ#12683 fix.
It basically removes the enable_asynccancel/disable_asynccancel function
usage on code, provide a arch-specific symbol that contains global
markers to be used in SIGCANCEL handler.
Checked on aarch64.
* sysdeps/unix/sysv/linux/aarch64/syscall_cancel.S: New file.
* sysdeps/unix/sysv/linux/aarch64/sysdep-cancel.h (PSEUDO): Redefine
to call __syscall_cancel function for cancellable syscalls.
(__pthread_get_ip): Add implementation.
* sysdeps/unix/sysv/linux/aarch64/sysdep.h (SYSCALL_CANCEL_ERROR): Add
definition.
(SYSCALL_CANCEL_ERRNO): Likewise.
diff --git a/ChangeLog b/ChangeLog
index c99db9e..a76eca5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ * sysdeps/unix/sysv/linux/aarch64/syscall_cancel.S: New file.
+ * sysdeps/unix/sysv/linux/aarch64/sysdep-cancel.h (PSEUDO): Redefine
+ to call __syscall_cancel function for cancellable syscalls.
+ (__pthread_get_ip): Add implementation.
+ * sysdeps/unix/sysv/linux/aarch64/sysdep.h (SYSCALL_CANCEL_ERROR): Add
+ definition.
+ (SYSCALL_CANCEL_ERRNO): Likewise.
+
* sysdeps/unix/sysv/linux/i386/fcntl.c (NO_CANCELLATION): Replace
by IS_IN (rtld).
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO):
diff --git a/sysdeps/unix/sysv/linux/aarch64/syscall_cancel.S b/sysdeps/unix/sysv/linux/aarch64/syscall_cancel.S
new file mode 100644
index 0000000..56ede8e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/syscall_cancel.S
@@ -0,0 +1,61 @@
+/* Cancellable syscall wrapper - aarch64 version.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* long int [r0] __syscall_cancel_arch (int *cancelhandling [x0],
+ long int nr [x1],
+ long int arg1 [x2],
+ long int arg2 [x3],
+ long int arg3 [x4],
+ long int arg4 [x5],
+ long int arg5 [x6],
+ long int arg6 [x7]) */
+
+ENTRY (__syscall_cancel_arch)
+
+ .globl __syscall_cancel_arch_start
+ .type __syscall_cancel_arch_start,@function
+__syscall_cancel_arch_start:
+
+ /* if (*cancelhandling & CANCELED_BITMASK)
+ __syscall_do_cancel() */
+ ldr w0, [x0]
+ tbnz w0, 2, 1f
+
+ /* Issue a 6 argument syscall, the nr [x1] being the syscall
+ number. */
+ mov x8, x1
+ mov x0, x2
+ mov x1, x3
+ mov x2, x4
+ mov x3, x5
+ mov x4, x6
+ mov x5, x7
+ svc 0x0
+
+ .globl __syscall_cancel_arch_end
+ .type __syscall_cancel_arch_end,@function
+__syscall_cancel_arch_end:
+ ret
+
+1:
+ b __syscall_do_cancel
+
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
diff --git a/sysdeps/unix/sysv/linux/aarch64/sysdep-cancel.h b/sysdeps/unix/sysv/linux/aarch64/sysdep-cancel.h
index 36e8e39..065f96e 100644
--- a/sysdeps/unix/sysv/linux/aarch64/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/aarch64/sysdep-cancel.h
@@ -20,80 +20,57 @@
#include <tls.h>
#ifndef __ASSEMBLER__
# include <nptl/pthreadP.h>
+# include <sys/ucontext.h>
#endif
#if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt)
+# if IS_IN (libc)
+# define JMP_SYSCALL_CANCEL HIDDEN_JUMPTARGET(__syscall_cancel)
+# else
+# define JMP_SYSCALL_CANCEL __syscall_cancel
+# endif
+
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
- .section ".text"; \
-ENTRY (__##syscall_name##_nocancel); \
-.Lpseudo_nocancel: \
- DO_CALL (syscall_name, args); \
-.Lpseudo_finish: \
- cmn x0, 4095; \
- b.cs .Lsyscall_error; \
- .subsection 2; \
- .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
ENTRY (name); \
SINGLE_THREAD_P(16); \
- cbz w16, .Lpseudo_nocancel; \
- /* Setup common stack frame no matter the number of args. \
- Also save the first arg, since it's basically free. */ \
- stp x30, x0, [sp, -64]!; \
- cfi_adjust_cfa_offset (64); \
- cfi_rel_offset (x30, 0); \
- DOCARGS_##args; /* save syscall args around CENABLE. */ \
- CENABLE; \
- mov x16, x0; /* save mask around syscall. */ \
- UNDOCARGS_##args; /* restore syscall args. */ \
+ cbnz w16, L(pseudo_cancel); \
DO_CALL (syscall_name, args); \
- str x0, [sp, 8]; /* save result around CDISABLE. */ \
- mov x0, x16; /* restore mask for CDISABLE. */ \
- CDISABLE; \
- /* Break down the stack frame, restoring result at once. */ \
- ldp x30, x0, [sp], 64; \
- cfi_adjust_cfa_offset (-64); \
- cfi_restore (x30); \
- b .Lpseudo_finish; \
- cfi_endproc; \
- .size name, .-name; \
- .previous
+ b L(pseudo_finish); \
+L(pseudo_cancel): \
+ stp x29, x30, [sp, -16]!; \
+ cfi_def_cfa_offset (16); \
+ cfi_offset (29, -16); \
+ cfi_offset (30, -8); \
+ add x29, sp, 0; \
+ cfi_def_cfa_register (29); \
+ mov x6, x5; \
+ mov x5, x4; \
+ mov x4, x3; \
+ mov x3, x2; \
+ mov x2, x1; \
+ mov x1, x0; \
+ mov x0, SYS_ify (syscall_name); \
+ bl JMP_SYSCALL_CANCEL; \
+ ldp x29, x30, [sp], 16; \
+ cfi_restore (30); \
+ cfi_restore (29); \
+ cfi_def_cfa (31, 0); \
+L(pseudo_finish): \
+ cmn x0, 4095; \
+ b.cs L(syscall_error);
# undef PSEUDO_END
# define PSEUDO_END(name) \
SYSCALL_ERROR_HANDLER; \
- cfi_endproc
-
-# define DOCARGS_0
-# define DOCARGS_1
-# define DOCARGS_2 str x1, [sp, 16]
-# define DOCARGS_3 stp x1, x2, [sp, 16]
-# define DOCARGS_4 DOCARGS_3; str x3, [sp, 32]
-# define DOCARGS_5 DOCARGS_3; stp x3, x4, [sp, 32]
-# define DOCARGS_6 DOCARGS_5; str x5, [sp, 48]
-
-# define UNDOCARGS_0
-# define UNDOCARGS_1 ldr x0, [sp, 8]
-# define UNDOCARGS_2 ldp x0, x1, [sp, 8]
-# define UNDOCARGS_3 UNDOCARGS_1; ldp x1, x2, [sp, 16]
-# define UNDOCARGS_4 UNDOCARGS_2; ldp x2, x3, [sp, 24]
-# define UNDOCARGS_5 UNDOCARGS_3; ldp x3, x4, [sp, 32]
-# define UNDOCARGS_6 UNDOCARGS_4; ldp x4, x5, [sp, 40]
+ cfi_endproc; \
+ .size name, .-name;
# if IS_IN (libpthread)
-# define CENABLE bl __pthread_enable_asynccancel
-# define CDISABLE bl __pthread_disable_asynccancel
# define __local_multiple_threads __pthread_multiple_threads
# elif IS_IN (libc)
-# define CENABLE bl __libc_enable_asynccancel
-# define CDISABLE bl __libc_disable_asynccancel
# define __local_multiple_threads __libc_multiple_threads
-# elif IS_IN (librt)
-# define CENABLE bl __librt_enable_asynccancel
-# define CDISABLE bl __librt_disable_asynccancel
-# else
-# error Unsupported library
# endif
# if IS_IN (libpthread) || IS_IN (libc)
@@ -131,4 +108,10 @@ extern int __local_multiple_threads attribute_hidden;
# define RTLD_SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
+
+static inline
+uintptr_t __pthread_get_pc (const struct ucontext *uc)
+{
+ return uc->uc_mcontext.pc;
+}
#endif
diff --git a/sysdeps/unix/sysv/linux/aarch64/sysdep.h b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
index fe94a50..5f73b9e 100644
--- a/sysdeps/unix/sysv/linux/aarch64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
@@ -199,6 +199,14 @@
# undef INTERNAL_SYSCALL_ERRNO
# define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
+#undef SYSCALL_CANCEL_ERROR
+#define SYSCALL_CANCEL_ERROR(__val) \
+ ((unsigned long) (__val) >= (unsigned long) -4095)
+
+#undef SYSCALL_CANCEL_ERRNO
+#define SYSCALL_CANCEL_ERRNO(__val) \
+ (-(__val))
+
# define LOAD_ARGS_0() \
register long _x0 asm ("x0");
# define LOAD_ARGS_1(x0) \
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=25016b1458218299794c9d77784f4d72670b3725
commit 25016b1458218299794c9d77784f4d72670b3725
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Mon Sep 29 09:20:10 2014 -0400
nptl: powerpc32: Fix Race conditions in pthread cancellation (BZ#12683)
This patches adds the ppc32 modification required for the BZ#12683
fix. It basically removes the enable_asynccancel/disable_asynccancel
function usage on code used on ppc32.
Checked on powerpc32.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO):
Redefine to call __syscall_cancel function for cancellable syscalls.
(__pthread_get_ip): Add implementation.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
[SYSCALL_CANCEL_ERROR]: New macro.
[SYSCALL_CANCEL_ERRNO]: New macro.
diff --git a/ChangeLog b/ChangeLog
index c9ea51f..c99db9e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ * sysdeps/unix/sysv/linux/i386/fcntl.c (NO_CANCELLATION): Replace
+ by IS_IN (rtld).
+ * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO):
+ Redefine to call __syscall_cancel function for cancellable syscalls.
+ (__pthread_get_ip): Add implementation.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
+ [SYSCALL_CANCEL_ERROR]: New macro.
+ [SYSCALL_CANCEL_ERRNO]: New macro.
+
* sysdeps/i386/nptl/tls.h (THREAD_ATOMIC_BIT_SET): Remove macro.
* sysdeps/unix/sysv/linux/i386/Makefile
[$(subdir) = elf] (sysdep-rtld_routines): Add libc-do-syscall object.
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
index dd9ff1c..4638882 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
@@ -25,94 +25,83 @@
#if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt)
+# if !IS_IN (libc)
+# define SETUP_PIC \
+ bcl 20,31,got_label; \
+got_label:
+
+# define CANCEL_JUMPTARGET \
+ stw r30,8(r1); \
+ mflr r30; \
+ addis r30,r30,_GLOBAL_OFFSET_TABLE_-got_label@ha; \
+ addi r30,r30,_GLOBAL_OFFSET_TABLE_-got_label@l; \
+ bl __syscall_cancel@plt; \
+ lwz r30,8(r1)
+# else
+# define SETUP_PIC
+# if defined SHARED && defined PIC
+# define CANCEL_JUMPTARGET \
+ bl __GI___syscall_cancel@locaL
+# else
+# define CANCEL_JUMPTARGET \
+ bl __syscall_cancel
+# endif
+# endif
+
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.section ".text"; \
ENTRY (name) \
SINGLE_THREAD_P; \
- bne- .Lpseudo_cancel; \
- .type __##syscall_name##_nocancel,@function; \
- .globl __##syscall_name##_nocancel; \
- __##syscall_name##_nocancel: \
+ bne- L(pseudo_cancel); \
DO_CALL (SYS_ify (syscall_name)); \
- PSEUDO_RET; \
- .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
- .Lpseudo_cancel: \
- stwu 1,-48(1); \
- cfi_adjust_cfa_offset (48); \
- mflr 9; \
- stw 9,52(1); \
+ bnslr+; \
+ b __syscall_error@local; \
+ L(pseudo_cancel): \
+ stwu r1,-16(r1); \
+ cfi_adjust_cfa_offset (16); \
+ mflr r0; \
+ SETUP_PIC; \
+ stw r0,20(r1); \
cfi_offset (lr, 4); \
- DOCARGS_##args; /* save syscall args around CENABLE. */ \
- CENABLE; \
- stw 3,16(1); /* store CENABLE return value (MASK). */ \
- UNDOCARGS_##args; /* restore syscall args. */ \
- DO_CALL (SYS_ify (syscall_name)); \
- mfcr 0; /* save CR/R3 around CDISABLE. */ \
- stw 3,8(1); \
- stw 0,12(1); \
- lwz 3,16(1); /* pass MASK to CDISABLE. */ \
- CDISABLE; \
- lwz 4,52(1); \
- lwz 0,12(1); /* restore CR/R3. */ \
- lwz 3,8(1); \
- mtlr 4; \
- mtcr 0; \
- addi 1,1,48;
-
-# define DOCARGS_0
-# define UNDOCARGS_0
-
-# define DOCARGS_1 stw 3,20(1); DOCARGS_0
-# define UNDOCARGS_1 lwz 3,20(1); UNDOCARGS_0
-
-# define DOCARGS_2 stw 4,24(1); DOCARGS_1
-# define UNDOCARGS_2 lwz 4,24(1); UNDOCARGS_1
-
-# define DOCARGS_3 stw 5,28(1); DOCARGS_2
-# define UNDOCARGS_3 lwz 5,28(1); UNDOCARGS_2
-
-# define DOCARGS_4 stw 6,32(1); DOCARGS_3
-# define UNDOCARGS_4 lwz 6,32(1); UNDOCARGS_3
-
-# define DOCARGS_5 stw 7,36(1); DOCARGS_4
-# define UNDOCARGS_5 lwz 7,36(1); UNDOCARGS_4
-
-# define DOCARGS_6 stw 8,40(1); DOCARGS_5
-# define UNDOCARGS_6 lwz 8,40(1); UNDOCARGS_5
-
-# if IS_IN (libpthread)
-# define CENABLE bl __pthread_enable_asynccancel@local
-# define CDISABLE bl __pthread_disable_asynccancel@local
-# elif IS_IN (libc)
-# define CENABLE bl __libc_enable_asynccancel@local
-# define CDISABLE bl __libc_disable_asynccancel@local
-# elif IS_IN (librt)
-# define CENABLE bl __librt_enable_asynccancel@local
-# define CDISABLE bl __librt_disable_asynccancel@local
-# else
-# error Unsupported library
-# endif
+ mr r9,r8; \
+ mr r8,r7; \
+ mr r7,r6; \
+ mr r6,r5; \
+ mr r5,r4; \
+ mr r4,r3; \
+ li r3,SYS_ify (syscall_name); \
+ CANCEL_JUMPTARGET; \
+ lwz r0,20(r1); \
+ addi r1,r1,16; \
+ cfi_adjust_cfa_offset (-16); \
+ mtlr r0; \
+ cfi_restore (lr); \
+ b __syscall_cancel_error@local;
+
+# undef PSEUDO_RET
+# define PSEUDO_RET
# ifndef __ASSEMBLER__
-# define SINGLE_THREAD_P \
- __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
- header.multiple_threads) == 0, 1)
+# define SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
# else
-# define SINGLE_THREAD_P \
- lwz 10,MULTIPLE_THREADS_OFFSET(2); \
+# define SINGLE_THREAD_P \
+ lwz 10,MULTIPLE_THREADS_OFFSET(2); \
cmpwi 10,0
# endif
-#elif !defined __ASSEMBLER__
-
-# define SINGLE_THREAD_P (1)
-# define NO_CANCELLATION 1
-
#endif
#ifndef __ASSEMBLER__
# define RTLD_SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
+
+static inline
+uintptr_t __pthread_get_pc (const ucontext_t *uc)
+{
+ return uc->uc_mcontext.uc_regs->gregs[PT_NIP];
+}
#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
index dc56bea..46fd267 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
@@ -100,6 +100,14 @@
sc_ret; \
})
+#undef SYSCALL_CANCEL_ERROR
+#define SYSCALL_CANCEL_ERROR(err) \
+ (err > 0xfffffffffffff000UL)
+
+#undef SYSCALL_CANCEL_ERRNO
+#define SYSCALL_CANCEL_ERRNO(err) \
+ (-err)
+
/* Define a macro which expands inline into the wrapper code for a system
call. This use is for internal calls that do not need to handle errors
normally. It will never touch errno.
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=5a221e82663e3aaee41e9ecb238750c56dd3357d
commit 5a221e82663e3aaee41e9ecb238750c56dd3357d
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Mon May 4 16:30:13 2015 -0300
nptl: i386: Fix Race conditions in pthread cancellation (BZ#12683)
This patch adds the i386 modifications required for the BZ#12683 fix.
It basically removes the enable_asynccancel/disable_asynccancel function
usage on code used on x86_64, provide a arch-specific symbol that
contains global markers to be used in SIGCANCEL handler, and add
cancellation entrypoints in the socketcall default header.
Checked on i686.
* sysdeps/i386/nptl/tls.h (THREAD_ATOMIC_BIT_SET): Remove macro.
* sysdeps/unix/sysv/linux/i386/Makefile
[$(subdir) = elf] (sysdep-rtld_routines): Add libc-do-syscall object.
* sysdeps/unix/sysv/linux/i386/fcntl.c (NO_CANCELLATION): Replace
by IS_IN (rtld).
* sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_wait_tid): Use
cancellable futex syscall macro.
* sysdeps/unix/sysv/linux/i386/syscall_cancel.S: New file.
* sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (PSEUDO): Redefine to
call __syscall_cancel function for cancellable syscalls.
* sysdeps/unix/sysv/linux/i386/sysdep.h (SYSCALL_CANCEL_ERROR): New
define.
(SYSCALL_CANCEL_ERRNO): Likewise.
(INTERNAL_SYSCALL_MAIN_NCS_0): Likewise.
(INTERNAL_SYSCALL_MAIN_NCS_1): Likewise.
(INTERNAL_SYSCALL_MAIN_NCS_2): Likewise.
(INTERNAL_SYSCALL_MAIN_NCS_3): Likewise.
(INTERNAL_SYSCALL_MAIN_NCS_4): Likewise.
(INTERNAL_SYSCALL_MAIN_NCS_5): Likewise.
(INTERNAL_SYSCALL_MAIN_NCS_6): Likewise.
(INTERNAL_SYSCALL_NCS): Redefine to call it with 6-arguments.
diff --git a/ChangeLog b/ChangeLog
index ad0be74..c9ea51f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,27 @@
2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ * sysdeps/i386/nptl/tls.h (THREAD_ATOMIC_BIT_SET): Remove macro.
+ * sysdeps/unix/sysv/linux/i386/Makefile
+ [$(subdir) = elf] (sysdep-rtld_routines): Add libc-do-syscall object.
+ * sysdeps/unix/sysv/linux/i386/fcntl.c (NO_CANCELLATION): Replace
+ by IS_IN (rtld).
+ * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_wait_tid): Use
+ cancellable futex syscall macro.
+ * sysdeps/unix/sysv/linux/i386/syscall_cancel.S: New file.
+ * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (PSEUDO): Redefine to
+ call __syscall_cancel function for cancellable syscalls.
+ * sysdeps/unix/sysv/linux/i386/sysdep.h (SYSCALL_CANCEL_ERROR): New
+ define.
+ (SYSCALL_CANCEL_ERRNO): Likewise.
+ (INTERNAL_SYSCALL_MAIN_NCS_0): Likewise.
+ (INTERNAL_SYSCALL_MAIN_NCS_1): Likewise.
+ (INTERNAL_SYSCALL_MAIN_NCS_2): Likewise.
+ (INTERNAL_SYSCALL_MAIN_NCS_3): Likewise.
+ (INTERNAL_SYSCALL_MAIN_NCS_4): Likewise.
+ (INTERNAL_SYSCALL_MAIN_NCS_5): Likewise.
+ (INTERNAL_SYSCALL_MAIN_NCS_6): Likewise.
+ (INTERNAL_SYSCALL_NCS): Redefine to call it with 6-arguments.
+
* sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h (__syscall_arg_t):
Define type for x32.
(__SSC): Add platform specific macro.
diff --git a/sysdeps/i386/nptl/tls.h b/sysdeps/i386/nptl/tls.h
index 829cd3a..ffac3a8 100644
--- a/sysdeps/i386/nptl/tls.h
+++ b/sysdeps/i386/nptl/tls.h
@@ -395,17 +395,6 @@ tls_fill_user_desc (union user_desc_init *desc,
abort (); })
-/* Atomic set bit. */
-#define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
- (void) ({ if (sizeof ((descr)->member) == 4) \
- asm volatile (LOCK_PREFIX "orl %1, %%gs:%P0" \
- :: "i" (offsetof (struct pthread, member)), \
- "ir" (1 << (bit))); \
- else \
- /* Not necessary for other sizes in the moment. */ \
- abort (); })
-
-
/* Call the user-provided thread function. */
#define CALL_THREAD_FCT(descr) \
({ void *__res; \
diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile
index 80da593..4f83d08 100644
--- a/sysdeps/unix/sysv/linux/i386/Makefile
+++ b/sysdeps/unix/sysv/linux/i386/Makefile
@@ -6,6 +6,7 @@ sysdep_routines += ioperm iopl vm86
endif
ifeq ($(subdir),elf)
+sysdep-rtld_routines += libc-do-syscall
sysdep-others += lddlibc4
install-bin += lddlibc4
endif
diff --git a/sysdeps/unix/sysv/linux/i386/fcntl.c b/sysdeps/unix/sysv/linux/i386/fcntl.c
index 56f4bd1..ac5eed4 100644
--- a/sysdeps/unix/sysv/linux/i386/fcntl.c
+++ b/sysdeps/unix/sysv/linux/i386/fcntl.c
@@ -23,7 +23,7 @@
#include <sys/syscall.h>
-#ifndef NO_CANCELLATION
+#if !IS_IN (rtld)
int
__fcntl_nocancel (int fd, int cmd, ...)
{
@@ -36,7 +36,7 @@ __fcntl_nocancel (int fd, int cmd, ...)
return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
}
-#endif /* NO_CANCELLATION */
+#endif
int
diff --git a/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/sysdeps/unix/sysv/linux/i386/lowlevellock.h
index 58f5638..02ea0fc 100644
--- a/sysdeps/unix/sysv/linux/i386/lowlevellock.h
+++ b/sysdeps/unix/sysv/linux/i386/lowlevellock.h
@@ -283,7 +283,7 @@ extern int __lll_timedlock_elision (int *futex, short *adapt_count,
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 *tid, const struct timespec *abstime)
diff --git a/sysdeps/unix/sysv/linux/i386/syscall_cancel.S b/sysdeps/unix/sysv/linux/i386/syscall_cancel.S
new file mode 100644
index 0000000..1ff6288
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/syscall_cancel.S
@@ -0,0 +1,105 @@
+/* Cancellable syscall wrapper - x86_64 version.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* long int [eax] __syscall_cancel_arch (int *cancelhandling [SP],
+ long int nr [SP+4],
+ long int arg1 [SP+8],
+ long int arg2 [SP+12],
+ long int arg3 [SP+16],
+ long int arg4 [SP+20],
+ long int arg5 [SP+24],
+ long int arg6 [SP+28]) */
+
+ENTRY (__syscall_cancel_arch)
+ pushl %ebp
+ cfi_def_cfa_offset (8)
+ cfi_offset (ebp, -8)
+ pushl %edi
+ cfi_def_cfa_offset (12)
+ cfi_offset (edi, -12)
+ pushl %esi
+ cfi_def_cfa_offset (16)
+ cfi_offset (esi, -16)
+ pushl %ebx
+ cfi_def_cfa_offset (20)
+ cfi_offset (ebx, -20)
+
+ .globl __syscall_cancel_arch_start
+ .type __syscall_cancel_arch_start,@function
+__syscall_cancel_arch_start:
+
+ /* if (*cancelhandling & CANCELED_BITMASK)
+ __syscall_do_cancel() */
+ testb $4, (%eax)
+ jne 1f
+
+ /* Issue a 6 argument syscall, the nr [%eax] being the syscall
+ number. */
+ movl 24(%esp), %eax
+ movl 28(%esp), %ebx
+ movl 32(%esp), %ecx
+ movl 36(%esp), %edx
+ movl 40(%esp), %esi
+ movl 44(%esp), %edi
+ movl 48(%esp), %ebp
+
+ /* It can not use the vDSO __kernel_vsyscall because the cancelable
+ checks in libc-cancelation.c requires to know if the cancellation
+ IP value that was trigger between the two
+ __syscall_cancel_arch_{start,end} marks. */
+ int $128
+
+ .globl __syscall_cancel_arch_end
+ .type __syscall_cancel_arch_end,@function
+__syscall_cancel_arch_end:
+
+ popl %ebx
+ cfi_restore (ebx)
+ cfi_def_cfa_offset (16)
+ popl %esi
+ cfi_restore (esi)
+ cfi_def_cfa_offset (12)
+ popl %edi
+ cfi_restore (edi)
+ cfi_def_cfa_offset (8)
+ popl %ebp
+ cfi_restore (ebp)
+ cfi_def_cfa_offset (4)
+ ret
+
+1:
+ /* Although the __syscall_do_cancel do not return, we need to stack
+ being set correctly so exceptions work correctly. */
+ popl %ebx
+ cfi_restore (ebx)
+ cfi_def_cfa_offset (16)
+ popl %esi
+ cfi_restore (esi)
+ cfi_def_cfa_offset (12)
+ popl %edi
+ cfi_restore (edi)
+ cfi_def_cfa_offset (8)
+ popl %ebp
+ cfi_restore (ebp)
+ cfi_def_cfa_offset (4)
+ jmp __syscall_do_cancel
+
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h b/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
index 1f86dae..ebbdef9 100644
--- a/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
@@ -24,112 +24,66 @@
#if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt)
+# if IS_IN (libc)
+# define JMP_STARTFUNC \
+ subl $16, %esp
+# define JMP_SYSCALL_CANCEL \
+ HIDDEN_JUMPTARGET(__syscall_cancel)
+# define JMP_ENDFUNC \
+ addl $44, %esp; \
+ cfi_def_cfa_offset (4)
+# else
+# define JMP_STARTFUNC \
+ pushl %ebx; \
+ cfi_def_cfa_offset (8); \
+ cfi_offset (ebx, -8); \
+ SETUP_PIC_REG (bx); \
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx; \
+ subl $12, %esp
+# define JMP_SYSCALL_CANCEL \
+ __syscall_cancel@plt
+# define JMP_ENDFUNC \
+ addl $40, %esp; \
+ cfi_def_cfa_offset (8); \
+ popl %ebx; \
+ cfi_restore (ebx); \
+ cfi_def_cfa_offset (4)
+# endif
+
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.text; \
ENTRY (name) \
cmpl $0, %gs:MULTIPLE_THREADS_OFFSET; \
jne L(pseudo_cancel); \
- .type __##syscall_name##_nocancel,@function; \
- .globl __##syscall_name##_nocancel; \
- __##syscall_name##_nocancel: \
DO_CALL (syscall_name, args); \
cmpl $-4095, %eax; \
jae SYSCALL_ERROR_LABEL; \
ret; \
- .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
L(pseudo_cancel): \
- CENABLE \
- SAVE_OLDTYPE_##args \
- PUSHCARGS_##args \
- DOCARGS_##args \
- movl $SYS_ify (syscall_name), %eax; \
- ENTER_KERNEL; \
- POPCARGS_##args; \
- POPSTATE_##args \
+ JMP_STARTFUNC; \
+ cfi_def_cfa_offset (20); \
+ pushl 40(%esp); \
+ cfi_def_cfa_offset (24); \
+ pushl 40(%esp); \
+ cfi_def_cfa_offset (28); \
+ pushl 40(%esp); \
+ cfi_def_cfa_offset (32); \
+ pushl 40(%esp); \
+ cfi_def_cfa_offset (36); \
+ pushl 40(%esp); \
+ cfi_def_cfa_offset (40); \
+ pushl 40(%esp); \
+ cfi_def_cfa_offset (44); \
+ pushl $SYS_ify (syscall_name); \
+ cfi_def_cfa_offset (48); \
+ call JMP_SYSCALL_CANCEL; \
+ JMP_ENDFUNC; \
cmpl $-4095, %eax; \
jae SYSCALL_ERROR_LABEL
-# define SAVE_OLDTYPE_0 movl %eax, %ecx;
-# define SAVE_OLDTYPE_1 SAVE_OLDTYPE_0
-# define SAVE_OLDTYPE_2 pushl %eax; cfi_adjust_cfa_offset (4);
-# define SAVE_OLDTYPE_3 SAVE_OLDTYPE_2
-# define SAVE_OLDTYPE_4 SAVE_OLDTYPE_2
-# define SAVE_OLDTYPE_5 SAVE_OLDTYPE_2
-# define SAVE_OLDTYPE_6 SAVE_OLDTYPE_2
-
-# define PUSHCARGS_0 /* No arguments to push. */
-# define DOCARGS_0 /* No arguments to frob. */
-# define POPCARGS_0 /* No arguments to pop. */
-# define _PUSHCARGS_0 /* No arguments to push. */
-# define _POPCARGS_0 /* No arguments to pop. */
-
-# define PUSHCARGS_1 movl %ebx, %edx; cfi_register (ebx, edx); PUSHCARGS_0
-# define DOCARGS_1 _DOARGS_1 (4)
-# define POPCARGS_1 POPCARGS_0; movl %edx, %ebx; cfi_restore (ebx);
-# define _PUSHCARGS_1 pushl %ebx; cfi_adjust_cfa_offset (4); \
- cfi_rel_offset (ebx, 0); _PUSHCARGS_0
-# define _POPCARGS_1 _POPCARGS_0; popl %ebx; \
- cfi_adjust_cfa_offset (-4); cfi_restore (ebx);
-
-# define PUSHCARGS_2 PUSHCARGS_1
-# define DOCARGS_2 _DOARGS_2 (12)
-# define POPCARGS_2 POPCARGS_1
-# define _PUSHCARGS_2 _PUSHCARGS_1
-# define _POPCARGS_2 _POPCARGS_1
-
-# define PUSHCARGS_3 _PUSHCARGS_2
-# define DOCARGS_3 _DOARGS_3 (20)
-# define POPCARGS_3 _POPCARGS_3
-# define _PUSHCARGS_3 _PUSHCARGS_2
-# define _POPCARGS_3 _POPCARGS_2
-
-# define PUSHCARGS_4 _PUSHCARGS_4
-# define DOCARGS_4 _DOARGS_4 (28)
-# define POPCARGS_4 _POPCARGS_4
-# define _PUSHCARGS_4 pushl %esi; cfi_adjust_cfa_offset (4); \
- cfi_rel_offset (esi, 0); _PUSHCARGS_3
-# define _POPCARGS_4 _POPCARGS_3; popl %esi; \
- cfi_adjust_cfa_offset (-4); cfi_restore (esi);
-
-# define PUSHCARGS_5 _PUSHCARGS_5
-# define DOCARGS_5 _DOARGS_5 (36)
-# define POPCARGS_5 _POPCARGS_5
-# define _PUSHCARGS_5 pushl %edi; cfi_adjust_cfa_offset (4); \
- cfi_rel_offset (edi, 0); _PUSHCARGS_4
-# define _POPCARGS_5 _POPCARGS_4; popl %edi; \
- cfi_adjust_cfa_offset (-4); cfi_restore (edi);
-
-# define PUSHCARGS_6 _PUSHCARGS_6
-# define DOCARGS_6 _DOARGS_6 (44)
-# define POPCARGS_6 _POPCARGS_6
-# define _PUSHCARGS_6 pushl %ebp; cfi_adjust_cfa_offset (4); \
- cfi_rel_offset (ebp, 0); _PUSHCARGS_5
-# define _POPCARGS_6 _POPCARGS_5; popl %ebp; \
- cfi_adjust_cfa_offset (-4); cfi_restore (ebp);
-
-# if IS_IN (libpthread)
-# define CENABLE call __pthread_enable_asynccancel;
-# define CDISABLE call __pthread_disable_asynccancel
-# elif IS_IN (libc)
-# define CENABLE call __libc_enable_asynccancel;
-# define CDISABLE call __libc_disable_asynccancel
-# elif IS_IN (librt)
-# define CENABLE call __librt_enable_asynccancel;
-# define CDISABLE call __librt_disable_asynccancel
-# else
-# error Unsupported library
-# endif
-# define POPSTATE_0 \
- pushl %eax; cfi_adjust_cfa_offset (4); movl %ecx, %eax; \
- CDISABLE; popl %eax; cfi_adjust_cfa_offset (-4);
-# define POPSTATE_1 POPSTATE_0
-# define POPSTATE_2 xchgl (%esp), %eax; CDISABLE; popl %eax; \
- cfi_adjust_cfa_offset (-4);
-# define POPSTATE_3 POPSTATE_2
-# define POPSTATE_4 POPSTATE_3
-# define POPSTATE_5 POPSTATE_4
-# define POPSTATE_6 POPSTATE_5
+# undef PSEUDO_RET
+# define PSEUDO_RET
# ifndef __ASSEMBLER__
# define SINGLE_THREAD_P \
@@ -150,4 +104,10 @@
# define RTLD_SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
+
+static inline
+uintptr_t __pthread_get_pc (const ucontext_t *uc)
+{
+ return (long int)uc->uc_mcontext.gregs[REG_EIP];
+}
#endif
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h
index d76aca5..b82e6a2 100644
--- a/sysdeps/unix/sysv/linux/i386/sysdep.h
+++ b/sysdeps/unix/sysv/linux/i386/sysdep.h
@@ -373,6 +373,42 @@ struct libc_do_syscall_args
register unsigned int resultvar; \
INTERNAL_SYSCALL_MAIN_##nr (name, err, args); \
(int) resultvar; })
+
+/* Same as INTERNAL_SYSCALL, but for non-constant name argument. */
+#define INTERNAL_SYSCALL_MAIN_NCS_0(name, err, args...) \
+ INTERNAL_SYSCALL_MAIN_INLINE_NCS(name, err, 0, args)
+#define INTERNAL_SYSCALL_MAIN_NCS_1(name, err, args...) \
+ INTERNAL_SYSCALL_MAIN_INLINE_NCS(name, err, 1, args)
+#define INTERNAL_SYSCALL_MAIN_NCS_2(name, err, args...) \
+ INTERNAL_SYSCALL_MAIN_INLINE_NCS(name, err, 2, args)
+#define INTERNAL_SYSCALL_MAIN_NCS_3(name, err, args...) \
+ INTERNAL_SYSCALL_MAIN_INLINE_NCS(name, err, 3, args)
+#define INTERNAL_SYSCALL_MAIN_NCS_4(name, err, args...) \
+ INTERNAL_SYSCALL_MAIN_INLINE_NCS(name, err, 4, args)
+#define INTERNAL_SYSCALL_MAIN_NCS_5(name, err, args...) \
+ INTERNAL_SYSCALL_MAIN_INLINE_NCS(name, err, 5, args)
+/* The NCS version is different because it has a non-constant 'name' arg
+ and then requires a different asm constraint ("0" instead of "i"). */
+#define INTERNAL_SYSCALL_MAIN_NCS_6(name, err, arg1, arg2, arg3, \
+ arg4, arg5, arg6) \
+ struct libc_do_syscall_args _xv = \
+ { \
+ (int) (arg1), \
+ (int) (arg5), \
+ (int) (arg6) \
+ }; \
+ asm volatile ( \
+ "movl %1, %%eax\n\t" \
+ "call __libc_do_syscall" \
+ : "=a" (resultvar) \
+ : "0" (name), "c" (arg2), "d" (arg3), "S" (arg4), "D" (&_xv) \
+ : "memory", "cc")
+#define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
+ ({ \
+ register unsigned int resultvar; \
+ INTERNAL_SYSCALL_MAIN_NCS_##nr (name, err, args); \
+ (int) resultvar; })
+
#ifdef I386_USE_SYSENTER
# ifdef SHARED
# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
@@ -385,9 +421,7 @@ struct libc_do_syscall_args
: "=a" (resultvar) \
: "i" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo)) \
ASMFMT_##nr(args) : "memory", "cc")
-# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
- ({ \
- register unsigned int resultvar; \
+# define INTERNAL_SYSCALL_MAIN_INLINE_NCS(name, err, nr, args...) \
EXTRAVAR_##nr \
asm volatile ( \
LOADARGS_##nr \
@@ -395,8 +429,7 @@ struct libc_do_syscall_args
RESTOREARGS_##nr \
: "=a" (resultvar) \
: "0" (name), "i" (offsetof (tcbhead_t, sysinfo)) \
- ASMFMT_##nr(args) : "memory", "cc"); \
- (int) resultvar; })
+ ASMFMT_##nr(args) : "memory", "cc")
# else
# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
EXTRAVAR_##nr \
@@ -407,17 +440,14 @@ struct libc_do_syscall_args
RESTOREARGS_##nr \
: "=a" (resultvar) \
: "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc")
-# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
- ({ \
- register unsigned int resultvar; \
+# define INTERNAL_SYSCALL_MAIN_INLINE_NCS(name, err, nr, args...) \
EXTRAVAR_##nr \
asm volatile ( \
LOADARGS_##nr \
"call *_dl_sysinfo\n\t" \
RESTOREARGS_##nr \
: "=a" (resultvar) \
- : "0" (name) ASMFMT_##nr(args) : "memory", "cc"); \
- (int) resultvar; })
+ : "0" (name) ASMFMT_##nr(args) : "memory", "cc")
# endif
#else
# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
@@ -429,17 +459,14 @@ struct libc_do_syscall_args
RESTOREARGS_##nr \
: "=a" (resultvar) \
: "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc")
-# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
- ({ \
- register unsigned int resultvar; \
+# define INTERNAL_SYSCALL_MAIN_INLINE_NCS(name, err, nr, args...) \
EXTRAVAR_##nr \
asm volatile ( \
LOADARGS_##nr \
"int $0x80\n\t" \
RESTOREARGS_##nr \
: "=a" (resultvar) \
- : "0" (name) ASMFMT_##nr(args) : "memory", "cc"); \
- (int) resultvar; })
+ : "0" (name) ASMFMT_##nr(args) : "memory", "cc")
#endif
#undef INTERNAL_SYSCALL_DECL
@@ -452,6 +479,14 @@ struct libc_do_syscall_args
#undef INTERNAL_SYSCALL_ERRNO
#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
+#undef SYSCALL_CANCEL_ERROR
+#define SYSCALL_CANCEL_ERROR(__val) \
+ ((unsigned int) (__val) >= 0xfffff001u)
+
+#undef SYSCALL_CANCEL_ERRNO
+#define SYSCALL_CANCEL_ERRNO(__val) \
+ (-(__val))
+
#define LOADARGS_0
#ifdef __PIC__
# if defined I386_USE_SYSENTER && defined SHARED
diff --git a/sysdeps/unix/sysv/linux/socketcall.h b/sysdeps/unix/sysv/linux/socketcall.h
index 007acba..1bd29fe 100644
--- a/sysdeps/unix/sysv/linux/socketcall.h
+++ b/sysdeps/unix/sysv/linux/socketcall.h
@@ -86,13 +86,35 @@
sc_ret; \
})
-#define SOCKETCALL_CANCEL(name, __a1, __a2, __a3, __a4, __a5, __a6) \
+
+#define __SOCKETCALL_CANCEL1(__name, __a1) \
+ SYSCALL_CANCEL_NCS (socketcall, __name, \
+ ((long int [1]) { (long int) __a1 }))
+#define __SOCKETCALL_CANCEL2(__name, __a1, __a2) \
+ SYSCALL_CANCEL_NCS (socketcall, __name, \
+ ((long int [2]) { (long int) __a1, (long int) __a2 }))
+#define __SOCKETCALL_CANCEL3(__name, __a1, __a2, __a3) \
+ SYSCALL_CANCEL_NCS (socketcall, __name, \
+ ((long int [3]) { (long int) __a1, (long int) __a2, (long int) __a3 }))
+#define __SOCKETCALL_CANCEL4(__name, __a1, __a2, __a3, __a4) \
+ SYSCALL_CANCEL_NCS (socketcall, __name, \
+ ((long int [4]) { (long int) __a1, (long int) __a2, (long int) __a3, \
+ (long int) __a4 }))
+#define __SOCKETCALL_CANCEL5(__name, __a1, __a2, __a3, __a4, __a5) \
+ SYSCALL_CANCEL_NCS (socketcall, __name, \
+ ((long int [5]) { (long int) __a1, (long int) __a2, (long int) __a3, \
+ (long int) __a4, (long int) __a5 }))
+#define __SOCKETCALL_CANCEL6(__name, __a1, __a2, __a3, __a4, __a5, __a6) \
+ SYSCALL_CANCEL_NCS (socketcall, __name, \
+ ((long int [6]) { (long int) __a1, (long int) __a2, (long int) __a3, \
+ (long int) __a4, (long int) __a5, (long int) __a6 }))
+
+#define __SOCKETCALL_CANCEL(...) __SOCKETCALL_DISP (__SOCKETCALL_CANCEL,\
+ __VA_ARGS__)
+
+#define SOCKETCALL_CANCEL(name, args...) \
({ \
- __syscall_arg_t __args[6] = { __SSC (__a1), __SSC (__a2), \
- __SSC (__a3), __SSC (__a4), \
- __SSC (__a5), __SSC (__a6) }; \
- long int sc_ret = SYSCALL_CANCEL_NCS (socketcall, SOCKOP_##name, \
- __args); \
+ long int sc_ret = __SOCKETCALL_CANCEL (SOCKOP_##name, args); \
if (SYSCALL_CANCEL_ERROR (sc_ret)) \
{ \
__set_errno (SYSCALL_CANCEL_ERRNO (sc_ret)); \
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=608a89b5d708853f27e747e16ecea101e0481bb6
commit 608a89b5d708853f27e747e16ecea101e0481bb6
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Sat May 9 14:20:26 2015 -0300
nptl: x32: Fix Race conditions in pthread cancellation (BZ#12683)
This patches adds the x32 modification required for the BZ#12683 fix.
It basically adjust the syscall size used to pass the arguments to
the syscall cancel wrappers.
Checked on x32.
* sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h (__syscall_arg_t):
Define type for x32.
(__SSC): Add platform specific macro.
diff --git a/ChangeLog b/ChangeLog
index ec20725..ad0be74 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ * sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h (__syscall_arg_t):
+ Define type for x32.
+ (__SSC): Add platform specific macro.
+
* sysdeps/unix/sysv/linux/x86_64/cancellation.S: Remove file.
* sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S: Remove file.
* sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S: Remove file.
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
index 2324168..f2dc8f0 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
@@ -18,6 +18,27 @@
#ifndef _LINUX_X32_SYSDEP_H
#define _LINUX_X32_SYSDEP_H 1
+#ifndef __ASSEMBLER__
+#include <libc-internal.h>
+
+typedef long long int __syscall_arg_t;
+
+/* Syscall arguments for x32 follows x86_64 size, however pointers are 32
+ bits in size. This suppress the GCC warning "cast from pointer to
+ integer of different size" when calling __syscall_cancel with
+ pointer as arguments. */
+# define __SSC(__x) \
+ ({ \
+ __syscall_arg_t __ret; \
+ DIAG_PUSH_NEEDS_COMMENT; \
+ DIAG_IGNORE_NEEDS_COMMENT (4.7, "-Wpointer-to-int-cast"); \
+ __ret = (sizeof(1 ? (__x) : 0ULL) < 8 ? \
+ (unsigned long int) (__x) : (long long int) (__x)); \
+ DIAG_POP_NEEDS_COMMENT; \
+ __ret; \
+ })
+#endif
+
/* There is some commonality. */
#include <sysdeps/unix/sysv/linux/x86_64/sysdep.h>
#include <sysdeps/x86_64/x32/sysdep.h>
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=e89b858373092650a1d69ecb0608cdce9cea448c
commit e89b858373092650a1d69ecb0608cdce9cea448c
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Mon Sep 29 09:48:34 2014 -0300
nptl: x86_64: Fix Race conditions in pthread cancellation (BZ#12683)
This patches adds the x86_64 modification required for the BZ#12683 fix.
It basically removes the enable_asynccancel/disable_asynccancel function
usage on code used on x86_64, and provide a arch-specific symbol that
contains global markers to be used in SIGCANCEL handler.
Checked on x86_64.
* sysdeps/unix/sysv/linux/x86_64/cancellation.S: Remove file.
* sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S: Remove file.
* sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S: Remove file.
* sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_wait_tid):
Use cancellable futex wait call.
* sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (PSEUDO): Likewise.
* sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S: New file.
* sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (PSEUDO): Redefine to
call __syscall_cancel function for cancellable syscalls.
(CENABLE): Remove definition.
(CDISABLE): Likewise.
(__pthread_get_ip): Add implementation.
* sysdeps/unix/sysv/linux/x86_64/sysdep.h (SYSCALL_CANCEL_ERROR): New
define.
(SYSCALL_CANCEL_ERRNO): Likewise.
* sysdeps/x86_64/nptl/tcb-offsets.sym [TCB_CANCELING_BITMASK]:
Remove.
* sysdeps/x86_64/nptl/tls.h (THREAD_ATOMIC_BIT_SET): Remove
macro.
diff --git a/ChangeLog b/ChangeLog
index 404a855..ec20725 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ * sysdeps/unix/sysv/linux/x86_64/cancellation.S: Remove file.
+ * sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S: Remove file.
+ * sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S: Remove file.
+ * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_wait_tid):
+ Use cancellable futex wait call.
+ * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (PSEUDO): Likewise.
+ * sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S: New file.
+ * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (PSEUDO): Redefine to
+ call __syscall_cancel function for cancellable syscalls.
+ (CENABLE): Remove definition.
+ (CDISABLE): Likewise.
+ (__pthread_get_ip): Add implementation.
+ * sysdeps/unix/sysv/linux/x86_64/sysdep.h (SYSCALL_CANCEL_ERROR): New
+ define.
+ (SYSCALL_CANCEL_ERRNO): Likewise.
+ * sysdeps/x86_64/nptl/tcb-offsets.sym [TCB_CANCELING_BITMASK]:
+ Remove.
+ * sysdeps/x86_64/nptl/tls.h (THREAD_ATOMIC_BIT_SET): Remove
+ macro.
+
* sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c (__libc_fnctl):
Remove CANCEL_ASYNC/CANCEL_RESET usage.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO):
diff --git a/sysdeps/unix/sysv/linux/x86_64/cancellation.S b/sysdeps/unix/sysv/linux/x86_64/cancellation.S
deleted file mode 100644
index 4c34beb..0000000
--- a/sysdeps/unix/sysv/linux/x86_64/cancellation.S
+++ /dev/null
@@ -1,117 +0,0 @@
-/* Copyright (C) 2009-2015 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#include <sysdep.h>
-#include <tcb-offsets.h>
-#include <kernel-features.h>
-#include "lowlevellock.h"
-
-#if IS_IN (libpthread)
-# if defined SHARED && !defined NO_HIDDEN
-# define __pthread_unwind __GI___pthread_unwind
-# endif
-#else
-# ifndef SHARED
- .weak __pthread_unwind
-# endif
-#endif
-
-
-#ifdef __ASSUME_PRIVATE_FUTEX
-# define LOAD_PRIVATE_FUTEX_WAIT(reg) \
- movl $(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg
-#else
-# if FUTEX_WAIT == 0
-# define LOAD_PRIVATE_FUTEX_WAIT(reg) \
- movl %fs:PRIVATE_FUTEX, reg
-# else
-# define LOAD_PRIVATE_FUTEX_WAIT(reg) \
- movl %fs:PRIVATE_FUTEX, reg ; \
- orl $FUTEX_WAIT, reg
-# endif
-#endif
-
-/* It is crucial that the functions in this file don't modify registers
- other than %rax and %r11. The syscall wrapper code depends on this
- because it doesn't explicitly save the other registers which hold
- relevant values. */
- .text
-
- .hidden __pthread_enable_asynccancel
-ENTRY(__pthread_enable_asynccancel)
- movl %fs:CANCELHANDLING, %eax
-2: movl %eax, %r11d
- orl $TCB_CANCELTYPE_BITMASK, %r11d
- cmpl %eax, %r11d
- je 1f
-
- lock
- cmpxchgl %r11d, %fs:CANCELHANDLING
- jnz 2b
-
- andl $(TCB_CANCELSTATE_BITMASK|TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK|TCB_EXITING_BITMASK|TCB_CANCEL_RESTMASK|TCB_TERMINATED_BITMASK), %r11d
- cmpl $(TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK), %r11d
- je 3f
-
-1: ret
-
-3: subq $8, %rsp
- cfi_adjust_cfa_offset(8)
- LP_OP(mov) $TCB_PTHREAD_CANCELED, %fs:RESULT
- lock
- orl $TCB_EXITING_BITMASK, %fs:CANCELHANDLING
- mov %fs:CLEANUP_JMP_BUF, %RDI_LP
-#ifdef SHARED
- call __pthread_unwind@PLT
-#else
- call __pthread_unwind
-#endif
- hlt
-END(__pthread_enable_asynccancel)
-
-
- .hidden __pthread_disable_asynccancel
-ENTRY(__pthread_disable_asynccancel)
- testl $TCB_CANCELTYPE_BITMASK, %edi
- jnz 1f
-
- movl %fs:CANCELHANDLING, %eax
-2: movl %eax, %r11d
- andl $~TCB_CANCELTYPE_BITMASK, %r11d
- lock
- cmpxchgl %r11d, %fs:CANCELHANDLING
- jnz 2b
-
- movl %r11d, %eax
-3: andl $(TCB_CANCELING_BITMASK|TCB_CANCELED_BITMASK), %eax
- cmpl $TCB_CANCELING_BITMASK, %eax
- je 4f
-1: ret
-
- /* Performance doesn't matter in this loop. We will
- delay until the thread is canceled. And we will unlikely
- enter the loop twice. */
-4: mov %fs:0, %RDI_LP
- movl $__NR_futex, %eax
- xorq %r10, %r10
- addq $CANCELHANDLING, %rdi
- LOAD_PRIVATE_FUTEX_WAIT (%esi)
- syscall
- movl %fs:CANCELHANDLING, %eax
- jmp 3b
-END(__pthread_disable_asynccancel)
diff --git a/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S b/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S
deleted file mode 100644
index dbb39f3..0000000
--- a/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Copyright (C) 2009-2015 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#define __pthread_enable_asynccancel __libc_enable_asynccancel
-#define __pthread_disable_asynccancel __libc_disable_asynccancel
-#include "cancellation.S"
diff --git a/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S b/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S
deleted file mode 100644
index 40b2986..0000000
--- a/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Copyright (C) 2009-2015 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#define __pthread_enable_asynccancel __librt_enable_asynccancel
-#define __pthread_disable_asynccancel __librt_disable_asynccancel
-#include "cancellation.S"
diff --git a/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h b/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
index de525cd..fbc5884 100644
--- a/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
+++ b/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
@@ -306,10 +306,10 @@ extern int __lll_timedlock_elision (int *futex, short *adapt_count,
afterwards. The kernel up to version 3.16.3 does not use the private futex
operations for futex wake-up when the clone terminates. */
#define lll_wait_tid(tid) \
- do { \
- __typeof (tid) __tid; \
- while ((__tid = (tid)) != 0) \
- lll_futex_wait (&(tid), __tid, LLL_SHARED);\
+ do { \
+ __typeof (tid) __tid; \
+ while ((__tid = (tid)) != 0) \
+ 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/x86_64/syscall_cancel.S b/sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S
new file mode 100644
index 0000000..3c44069
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/syscall_cancel.S
@@ -0,0 +1,62 @@
+/* Cancellable syscall wrapper - x86_64 version.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* long int [rax] __syscall_cancel_arch (int *cancelhandling [%rdi],
+ long int nr [%rsi],
+ long int arg1 [%rdx],
+ long int arg2 [%rcx],
+ long int arg3 [%r8],
+ long int arg4 [%r9],
+ long int arg5 [SP+8],
+ long int arg6 [SP+16]) */
+
+ENTRY (__syscall_cancel_arch)
+
+ .globl __syscall_cancel_arch_start
+ .type __syscall_cancel_arch_start,@function
+__syscall_cancel_arch_start:
+
+ /* if (*cancelhandling & CANCELED_BITMASK)
+ __syscall_do_cancel() */
+ mov (%rdi),%eax
+ testb $4, (%rdi)
+ jne __syscall_do_cancel
+
+ /* Issue a 6 argument syscall, the nr [%rax] being the syscall
+ number. */
+ mov %rdi,%r11
+ mov %rsi,%rax
+ mov %rdx,%rdi
+ mov %rcx,%rsi
+ mov %r8,%rdx
+ mov %r9,%r10
+ mov 8(%rsp),%r8
+ mov 16(%rsp),%r9
+ mov %r11,8(%rsp)
+ syscall
+
+ .globl __syscall_cancel_arch_end
+ .type __syscall_cancel_arch_end,@function
+__syscall_cancel_arch_end:
+
+ ret
+
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h b/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
index 6436ff0..8c4233f 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
@@ -24,53 +24,43 @@
#if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt)
-/* The code to disable cancellation depends on the fact that the called
- functions are special. They don't modify registers other than %rax
- and %r11 if they return. Therefore we don't have to preserve other
- registers around these calls. */
+# if IS_IN (libc)
+# define JMP_SYSCALL_CANCEL HIDDEN_JUMPTARGET(__syscall_cancel)
+# else
+# define JMP_SYSCALL_CANCEL __syscall_cancel@plt
+# endif
+
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.text; \
ENTRY (name) \
SINGLE_THREAD_P; \
jne L(pseudo_cancel); \
- .type __##syscall_name##_nocancel,@function; \
- .globl __##syscall_name##_nocancel; \
- __##syscall_name##_nocancel: \
DO_CALL (syscall_name, args); \
cmpq $-4095, %rax; \
jae SYSCALL_ERROR_LABEL; \
ret; \
- .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
L(pseudo_cancel): \
- /* We always have to align the stack before calling a function. */ \
- subq $8, %rsp; cfi_adjust_cfa_offset (8); \
- CENABLE \
- /* The return value from CENABLE is argument for CDISABLE. */ \
- movq %rax, (%rsp); \
- DO_CALL (syscall_name, args); \
- movq (%rsp), %rdi; \
- /* Save %rax since it's the error code from the syscall. */ \
- movq %rax, %rdx; \
- CDISABLE \
- movq %rdx, %rax; \
- addq $8,%rsp; cfi_adjust_cfa_offset (-8); \
- cmpq $-4095, %rax; \
- jae SYSCALL_ERROR_LABEL
-
+ subq $24, %rsp; \
+ cfi_def_cfa_offset (32); \
+ movq %r9, (%rsp); \
+ movq %r8, %r9; \
+ movq %rcx, %r8; \
+ movq %rdx, %rcx; \
+ movq %rsi, %rdx; \
+ movq %rdi, %rsi; \
+ lea SYS_ify (syscall_name), %edi; \
+ call JMP_SYSCALL_CANCEL; \
+ cfi_def_cfa_offset (8); \
+ addq $24, %rsp; \
+ cmpq $-4095, %rax; \
+ jae SYSCALL_ERROR_LABEL;
# if IS_IN (libpthread)
-# define CENABLE call __pthread_enable_asynccancel;
-# define CDISABLE call __pthread_disable_asynccancel;
# define __local_multiple_threads __pthread_multiple_threads
# elif IS_IN (libc)
-# define CENABLE call __libc_enable_asynccancel;
-# define CDISABLE call __libc_disable_asynccancel;
# define __local_multiple_threads __libc_multiple_threads
-# elif IS_IN (librt)
-# define CENABLE call __librt_enable_asynccancel;
-# define CDISABLE call __librt_disable_asynccancel;
-# else
+# elif !IS_IN (librt)
# error Unsupported library
# endif
@@ -78,7 +68,7 @@
# ifndef __ASSEMBLER__
extern int __local_multiple_threads attribute_hidden;
# define SINGLE_THREAD_P \
- __builtin_expect (__local_multiple_threads == 0, 1)
+ __builtin_expect (__local_multiple_threads == 0, 1)
# else
# define SINGLE_THREAD_P cmpl $0, __local_multiple_threads(%rip)
# endif
@@ -87,18 +77,13 @@ extern int __local_multiple_threads attribute_hidden;
# ifndef __ASSEMBLER__
# define SINGLE_THREAD_P \
- __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
- header.multiple_threads) == 0, 1)
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
# else
# define SINGLE_THREAD_P cmpl $0, %fs:MULTIPLE_THREADS_OFFSET
-# endif
+# endif /* __ASSEMBLER */
-# endif
-
-#elif !defined __ASSEMBLER__
-
-# define SINGLE_THREAD_P (1)
-# define NO_CANCELLATION 1
+# endif /* IS_IN (libpthread) || IS_IN (libc) */
#endif
@@ -106,4 +91,10 @@ extern int __local_multiple_threads attribute_hidden;
# define RTLD_SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
+
+static inline
+uintptr_t __pthread_get_pc (const ucontext_t *uc)
+{
+ return (long int)uc->uc_mcontext.gregs[REG_RIP];
+}
#endif
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
index 5a62cce..e4059f0 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
@@ -252,6 +252,14 @@
# undef INTERNAL_SYSCALL_ERRNO
# define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
+# undef SYSCALL_CANCEL_ERROR
+# define SYSCALL_CANCEL_ERROR(__val) \
+ ((unsigned long int) (long int) (__val) >= -4095L)
+
+# undef SYSCALL_CANCEL_ERRNO
+# define SYSCALL_CANCEL_ERRNO(__val) \
+ (-(__val))
+
/* List of system calls which are supported as vsyscalls. */
# define HAVE_CLOCK_GETTIME_VSYSCALL 1
# define HAVE_GETTIMEOFDAY_VSYSCALL 1
diff --git a/sysdeps/x86_64/nptl/tcb-offsets.sym b/sysdeps/x86_64/nptl/tcb-offsets.sym
index aeb7526..01c5ff7 100644
--- a/sysdeps/x86_64/nptl/tcb-offsets.sym
+++ b/sysdeps/x86_64/nptl/tcb-offsets.sym
@@ -20,7 +20,6 @@ PRIVATE_FUTEX offsetof (tcbhead_t, private_futex)
-- Not strictly offsets, but these values are also used in the TCB.
TCB_CANCELSTATE_BITMASK CANCELSTATE_BITMASK
TCB_CANCELTYPE_BITMASK CANCELTYPE_BITMASK
-TCB_CANCELING_BITMASK CANCELING_BITMASK
TCB_CANCELED_BITMASK CANCELED_BITMASK
TCB_EXITING_BITMASK EXITING_BITMASK
TCB_CANCEL_RESTMASK CANCEL_RESTMASK
diff --git a/sysdeps/x86_64/nptl/tls.h b/sysdeps/x86_64/nptl/tls.h
index b73e7ed..9caa23f 100644
--- a/sysdeps/x86_64/nptl/tls.h
+++ b/sysdeps/x86_64/nptl/tls.h
@@ -326,17 +326,6 @@ typedef struct
abort (); })
-/* Atomic set bit. */
-# define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
- (void) ({ if (sizeof ((descr)->member) == 4) \
- asm volatile (LOCK_PREFIX "orl %1, %%fs:%P0" \
- :: "i" (offsetof (struct pthread, member)), \
- "ir" (1 << (bit))); \
- else \
- /* Not necessary for other sizes in the moment. */ \
- abort (); })
-
-
# define CALL_THREAD_FCT(descr) \
({ void *__res; \
asm volatile ("movq %%fs:%P2, %%rdi\n\t" \
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=421b23a833e00537636b4567c919d51c32b92a74
commit 421b23a833e00537636b4567c919d51c32b92a74
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Fri Sep 18 18:14:19 2015 -0300
nptl: powerpc64: Fix Race conditions in pthread cancellation (BZ#12683)
This patches adds the powerpc64 modification required for the BZ#12683 fix.
It basically removes the enable_asynccancel/disable_asynccancel function
usage on code used on powerpc64, and provide a arch-specific symbol that
contains global markers to be used in SIGCANCEL handler.
Checked on powerpc64 and powerpc64le.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c (__libc_fnctl):
Remove CANCEL_ASYNC/CANCEL_RESET usage.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO):
Likewise.
(PSEUDO_RET): Likewise.
(__pthread_get_ip): Add implementation.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
(SYSCALL_CANCEL_ERROR): New define.
(SYSCALL_CANCEL_ERRNO): New define.
* sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S: New file:
cancellable syscall.
* sysdeps/unix/sysv/linux/powerpc/sysdep.c (__syscall_cancel_error):
New symbol: cancellable syscall error handler.
diff --git a/ChangeLog b/ChangeLog
index dd3254c..404a855 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c (__libc_fnctl):
+ Remove CANCEL_ASYNC/CANCEL_RESET usage.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO):
+ Likewise.
+ (PSEUDO_RET): Likewise.
+ (__pthread_get_ip): Add implementation.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
+ (SYSCALL_CANCEL_ERROR): New define.
+ (SYSCALL_CANCEL_ERRNO): New define.
+ * sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S: New file:
+ cancellable syscall.
+ * sysdeps/unix/sysv/linux/powerpc/sysdep.c (__syscall_cancel_error):
+ New symbol: cancellable syscall error handler.
+
* nptl/Makefile [routines]: Add syscall_cancel object.
[libpthread-routines]: Remove cancellation object.
(CFLAGS-cancellation.c): Remove -fasynchronous-unwind-tables.
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c
index 69031ba..3a10d16 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/fcntl.c
@@ -23,8 +23,7 @@
#include <sys/syscall.h>
-
-#ifndef NO_CANCELLATION
+#if !IS_IN (rtld)
int
__fcntl_nocancel (int fd, int cmd, ...)
{
@@ -39,7 +38,6 @@ __fcntl_nocancel (int fd, int cmd, ...)
}
#endif
-
int
__libc_fcntl (int fd, int cmd, ...)
{
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
index 5cd7ddb..aec7beb 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
@@ -27,121 +27,70 @@
# define DASHDASHPFX(str) __##str
-#if _CALL_ELF == 2
-#define CANCEL_FRAMESIZE (FRAME_MIN_SIZE+16+48)
-#define CANCEL_PARM_SAVE (FRAME_MIN_SIZE+16)
-#else
-#define CANCEL_FRAMESIZE (FRAME_MIN_SIZE+16)
-#define CANCEL_PARM_SAVE (CANCEL_FRAMESIZE+FRAME_PARM_SAVE)
-#endif
+# if !IS_IN (libc)
+# undef HIDDEN_JUMPTARGET
+# define HIDDEN_JUMPTARGET(__symbol) __symbol
+# endif
+
+#define CANCEL_FRAMESIZE (FRAME_MIN_SIZE)
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.section ".text"; \
ENTRY (name) \
SINGLE_THREAD_P; \
- bne- .Lpseudo_cancel; \
- .type DASHDASHPFX(syscall_name##_nocancel),@function; \
- .globl DASHDASHPFX(syscall_name##_nocancel); \
- DASHDASHPFX(syscall_name##_nocancel): \
+ bne- L(pseudo_cancel); \
DO_CALL (SYS_ify (syscall_name)); \
- PSEUDO_RET; \
- .size DASHDASHPFX(syscall_name##_nocancel),.-DASHDASHPFX(syscall_name##_nocancel); \
- .Lpseudo_cancel: \
- stdu 1,-CANCEL_FRAMESIZE(1); \
- cfi_adjust_cfa_offset (CANCEL_FRAMESIZE); \
- mflr 9; \
- std 9,CANCEL_FRAMESIZE+FRAME_LR_SAVE(1); \
+ bnslr+; \
+ TAIL_CALL_SYSCALL_ERROR; \
+ L(pseudo_cancel): \
+ mflr r0; \
+ std r0,FRAME_LR_SAVE(r1); \
cfi_offset (lr, FRAME_LR_SAVE); \
- DOCARGS_##args; /* save syscall args around CENABLE. */ \
- CENABLE; \
- std 3,FRAME_MIN_SIZE(1); /* store CENABLE return value (MASK). */ \
- UNDOCARGS_##args; /* restore syscall args. */ \
- DO_CALL (SYS_ify (syscall_name)); \
- mfcr 0; /* save CR/R3 around CDISABLE. */ \
- std 3,FRAME_MIN_SIZE+8(1); \
- std 0,CANCEL_FRAMESIZE+FRAME_CR_SAVE(1); \
- cfi_offset (cr, FRAME_CR_SAVE); \
- ld 3,FRAME_MIN_SIZE(1); /* pass MASK to CDISABLE. */ \
- CDISABLE; \
- ld 9,CANCEL_FRAMESIZE+FRAME_LR_SAVE(1); \
- ld 0,CANCEL_FRAMESIZE+FRAME_CR_SAVE(1); /* restore CR/R3. */ \
- ld 3,FRAME_MIN_SIZE+8(1); \
- mtlr 9; \
- mtcr 0; \
- addi 1,1,CANCEL_FRAMESIZE; \
+ stdu r1,-CANCEL_FRAMESIZE(r1); \
+ cfi_adjust_cfa_offset (CANCEL_FRAMESIZE); \
+ mr r9,r8; \
+ mr r8,r7; \
+ mr r7,r6; \
+ mr r6,r5; \
+ mr r5,r4; \
+ mr r4,r3; \
+ li r3,SYS_ify (syscall_name); \
+ bl HIDDEN_JUMPTARGET(__syscall_cancel); \
+ nop; \
+ bl JUMPTARGET(__syscall_cancel_error); \
+ nop; \
+ addi r1,r1,CANCEL_FRAMESIZE; \
cfi_adjust_cfa_offset (-CANCEL_FRAMESIZE); \
+ ld r0,FRAME_LR_SAVE(r1); \
+ mtlr r0; \
cfi_restore (lr); \
- cfi_restore (cr)
-
-# define DOCARGS_0
-# define UNDOCARGS_0
-
-# define DOCARGS_1 std 3,CANCEL_PARM_SAVE(1); DOCARGS_0
-# define UNDOCARGS_1 ld 3,CANCEL_PARM_SAVE(1); UNDOCARGS_0
-
-# define DOCARGS_2 std 4,CANCEL_PARM_SAVE+8(1); DOCARGS_1
-# define UNDOCARGS_2 ld 4,CANCEL_PARM_SAVE+8(1); UNDOCARGS_1
-
-# define DOCARGS_3 std 5,CANCEL_PARM_SAVE+16(1); DOCARGS_2
-# define UNDOCARGS_3 ld 5,CANCEL_PARM_SAVE+16(1); UNDOCARGS_2
+ blr
-# define DOCARGS_4 std 6,CANCEL_PARM_SAVE+24(1); DOCARGS_3
-# define UNDOCARGS_4 ld 6,CANCEL_PARM_SAVE+24(1); UNDOCARGS_3
-
-# define DOCARGS_5 std 7,CANCEL_PARM_SAVE+32(1); DOCARGS_4
-# define UNDOCARGS_5 ld 7,CANCEL_PARM_SAVE+32(1); UNDOCARGS_4
-
-# define DOCARGS_6 std 8,CANCEL_PARM_SAVE+40(1); DOCARGS_5
-# define UNDOCARGS_6 ld 8,CANCEL_PARM_SAVE+40(1); UNDOCARGS_5
-
-# if IS_IN (libpthread)
-# ifdef SHARED
-# define CENABLE bl JUMPTARGET(__pthread_enable_asynccancel)
-# define CDISABLE bl JUMPTARGET(__pthread_disable_asynccancel)
-# else
-# define CENABLE bl JUMPTARGET(__pthread_enable_asynccancel); nop
-# define CDISABLE bl JUMPTARGET(__pthread_disable_asynccancel); nop
-# endif
-# elif IS_IN (libc)
-# ifdef SHARED
-# define CENABLE bl JUMPTARGET(__libc_enable_asynccancel)
-# define CDISABLE bl JUMPTARGET(__libc_disable_asynccancel)
-# else
-# define CENABLE bl JUMPTARGET(__libc_enable_asynccancel); nop
-# define CDISABLE bl JUMPTARGET(__libc_disable_asynccancel); nop
-# endif
-# elif IS_IN (librt)
-# ifdef SHARED
-# define CENABLE bl JUMPTARGET(__librt_enable_asynccancel)
-# define CDISABLE bl JUMPTARGET(__librt_disable_asynccancel)
-# else
-# define CENABLE bl JUMPTARGET(__librt_enable_asynccancel); nop
-# define CDISABLE bl JUMPTARGET(__librt_disable_asynccancel); nop
-# endif
-# else
-# error Unsupported library
-# endif
+# undef PSEUDO_RET
+# define PSEUDO_RET
# ifndef __ASSEMBLER__
-# define SINGLE_THREAD_P \
- __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
- header.multiple_threads) == 0, 1)
+# define SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
# else
-# define SINGLE_THREAD_P \
- lwz 10,MULTIPLE_THREADS_OFFSET(13); \
+# define SINGLE_THREAD_P \
+ lwz 10,MULTIPLE_THREADS_OFFSET(13); \
cmpwi 10,0
# endif
-#elif !defined __ASSEMBLER__
-
-# define SINGLE_THREAD_P (1)
-# define NO_CANCELLATION 1
-
#endif
#ifndef __ASSEMBLER__
# define RTLD_SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
+
+static inline
+uintptr_t __pthread_get_pc (const ucontext_t *uc)
+{
+ return uc->uc_mcontext.gp_regs[PT_NIP];
+}
+
#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
index e2014cc..8a941f8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
@@ -131,6 +131,15 @@
sc_ret; \
})
+#undef SYSCALL_CANCEL_ERROR
+#define SYSCALL_CANCEL_ERROR(err) \
+ (err > 0xfffffffffffff000UL)
+
+#undef SYSCALL_CANCEL_ERRNO
+#define SYSCALL_CANCEL_ERRNO(err) \
+ (-err)
+
+
/* Define a macro which expands inline into the wrapper code for a system
call. This use is for internal calls that do not need to handle errors
normally. It will never touch errno. This returns just what the kernel
diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S b/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
new file mode 100644
index 0000000..c7068d3
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/syscall_cancel.S
@@ -0,0 +1,63 @@
+/* Cancellable syscall wrapper - powerpc version.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* long int [r3] __syscall_cancel_arch (int *cancelhandling [r3],
+ long int nr [r4],
+ long int arg1 [r5],
+ long int arg2 [r6],
+ long int arg3 [r7],
+ long int arg4 [r8],
+ long int arg5 [r9],
+ long int arg6 [r10]) */
+
+ENTRY (__syscall_cancel_arch)
+
+ .globl __syscall_cancel_arch_start
+ .type __syscall_cancel_arch_start,@function
+__syscall_cancel_arch_start:
+
+ /* if (*cancelhandling & CANCELED_BITMASK)
+ __syscall_do_cancel() */
+ lwz r0,0(r3)
+ rldicl. r0,r0,62,63
+ beq 1f
+ b __syscall_do_cancel
+ nop
+1:
+ /* Issue a 6 argument syscall, the nr [r4] being the syscall
+ number. */
+ mr r0,r4
+ mr r3,r5
+ mr r4,r6
+ mr r5,r7
+ mr r6,r8
+ mr r7,r9
+ mr r8,r10
+ sc
+
+ .globl __syscall_cancel_arch_end
+ .type __syscall_cancel_arch_end,@function
+__syscall_cancel_arch_end:
+
+ bnslr+
+ neg r3,r3
+ blr
+END (__syscall_cancel_arch)
+libc_hidden_def (__syscall_cancel_arch)
diff --git a/sysdeps/unix/sysv/linux/powerpc/sysdep.c b/sysdeps/unix/sysv/linux/powerpc/sysdep.c
index 6dc6737..8d58fd0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/sysdep.c
+++ b/sysdeps/unix/sysv/linux/powerpc/sysdep.c
@@ -26,3 +26,14 @@ __syscall_error (int err_no)
__set_errno (err_no);
return -1;
}
+
+long int
+__syscall_cancel_error (unsigned long err)
+{
+ if (__glibc_unlikely ((err) & (1 << 28)))
+ {
+ __set_errno (-err);
+ return -1;
+ }
+ return err;
+}
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=233bbf7e5bc9a94118cd454ce7b438a437e39d37
commit 233bbf7e5bc9a94118cd454ce7b438a437e39d37
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Fri Sep 18 18:26:35 2015 -0300
nptl: Fix Race conditions in pthread cancellation (BZ#12683)
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. Adjust 'lowlevellock.h' arch-specific implementations to provide
cancelable futex calls (used in libpthread code).
This patch adds the proposed changes to NPTL. The code leaves all the ports
broken without further patches in the list.
* nptl/Makefile [routines]: Add syscall_cancel object.
[libpthread-routines]: Remove cancellation object.
(CFLAGS-cancellation.c): Remove -fasynchronous-unwind-tables.
* nptl/Versions [GLIBC_PRIVATE] (libc): 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/nptl-init.c (sigcancel_handler): Rewrite function to avoid race
conditions.
(__pthread_initialize_minimal_internal): Add SA_RESTART to SIGCANCEL
handler.
* nptl/pt-system.c [LIBC_CANCEL_HANDLED]: Remove definition.
* io/creat.c (LIBC_CANCEL_HANDLED): Likewise.
* io/ppoll.c [ppoll] (LIBC_CANCEL_HANDLED): Likewise.
* misc/pselect [__pselect] (LIBC_CANCEL_HANDLED): Likewise.
* sysdeps/posix/pause.c (LIBC_CANCEL_HANDLED): Likewise.
* sysdeps/unix/sysv/linux/generic/creat.c (LIBC_CANCEL_HANDLED):
Likewise.
* 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.
(__syscall_cancel): Add prototype.
* nptl/pthread_cancel.c (pthread_cancel): Rewrite to just set
CANCELLED_BIT and call __pthread_kill.
* 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.
* nptl/pthread_timedjoin.c (pthread_timedjoin_np): Likewise.
* nptl/sem_timedwait.c (sem_timedwait): Likewise.
* nptl/sem_wait.c (__new_sem_wait): Likewise.
* nptl/sem_waitcommon.c (futex_abstimed_wait): 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/sigwait.c (__sigwait): Likewise.
* sysdeps/posix/waitid.c (__waitid): Likewise.
* sysdeps/nptl/lowlevellock.h (lll_wait_tid): Likewise.
* sysdeps/posix/open64.c (__libc_open64): Likewise.
* sysdeps/unix/sysv/linux/sigwait.c (__sigwait): Likewise.
* 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.
* rt/Makefile [CFLAGS-librt-cancellation.c]: Remove rule.
* sysdeps/generic/sysdep-cancel.h (LIBC_CANCEL_ASYNC): Remove define.
(LIBC_CANCEL_RESET): Likewise.
(LIBC_CANCEL_HANDLED): Likewise.
* sysdeps/unix/sysv/linux/clock_nanosleep.c (__clock_nanosleep):
Likewise.
* sysdeps/unix/sysv/linux/fcntl.c (__libc_fcntl): Likewise.
* sysdeps/unix/sysv/linux/generic/wordsize-32/fcntl.c (__libc_fcntl):
Likewise.
* sysdeps/nptl/Makefile [$(subdir) = rt] (librt-sysdep_routines):
Remove librt-cancellation object.
[$(subdir) = rt] (librt-cancellation.c): Remove rule.
* sysdeps/nptl/librt-cancellation.c: Remove file.
* sysdeps/unix/sysv/linux/lowlevellock-futex.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/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): New prototype.
* sysdeps/unix/sysv/linux/socketcall.h (SOCKETCALL): Use __SSC macros.
(SOCKETCALL_CANCEL): Use SYSCALL_CANCEL macros.
* 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.
* nptl/tst-cancel28.c: New file.
diff --git a/ChangeLog b/ChangeLog
index 0c9c7b2..dd3254c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,105 @@
2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ * nptl/Makefile [routines]: Add syscall_cancel object.
+ [libpthread-routines]: Remove cancellation object.
+ (CFLAGS-cancellation.c): Remove -fasynchronous-unwind-tables.
+ * nptl/Versions [GLIBC_PRIVATE] (libc): 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/nptl-init.c (sigcancel_handler): Rewrite function to avoid race
+ conditions.
+ (__pthread_initialize_minimal_internal): Add SA_RESTART to SIGCANCEL
+ handler.
+ * nptl/pt-system.c [LIBC_CANCEL_HANDLED]: Remove definition.
+ * io/creat.c (LIBC_CANCEL_HANDLED): Likewise.
+ * io/ppoll.c [ppoll] (LIBC_CANCEL_HANDLED): Likewise.
+ * misc/pselect [__pselect] (LIBC_CANCEL_HANDLED): Likewise.
+ * sysdeps/posix/pause.c (LIBC_CANCEL_HANDLED): Likewise.
+ * sysdeps/unix/sysv/linux/generic/creat.c (LIBC_CANCEL_HANDLED):
+ Likewise.
+ * 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.
+ (__syscall_cancel): Add prototype.
+ * nptl/pthread_cancel.c (pthread_cancel): Rewrite to just set
+ CANCELLED_BIT and call __pthread_kill.
+ * 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.
+ * nptl/pthread_timedjoin.c (pthread_timedjoin_np): Likewise.
+ * nptl/sem_timedwait.c (sem_timedwait): Likewise.
+ * nptl/sem_wait.c (__new_sem_wait): Likewise.
+ * nptl/sem_waitcommon.c (futex_abstimed_wait): 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/sigwait.c (__sigwait): Likewise.
+ * sysdeps/posix/waitid.c (__waitid): Likewise.
+ * sysdeps/nptl/lowlevellock.h (lll_wait_tid): Likewise.
+ * sysdeps/posix/open64.c (__libc_open64): Likewise.
+ * sysdeps/unix/sysv/linux/sigwait.c (__sigwait): Likewise.
+ * 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.
+ * rt/Makefile [CFLAGS-librt-cancellation.c]: Remove rule.
+ * sysdeps/generic/sysdep-cancel.h (LIBC_CANCEL_ASYNC): Remove define.
+ (LIBC_CANCEL_RESET): Likewise.
+ (LIBC_CANCEL_HANDLED): Likewise.
+ * sysdeps/unix/sysv/linux/clock_nanosleep.c (__clock_nanosleep):
+ Likewise.
+ * sysdeps/unix/sysv/linux/fcntl.c (__libc_fcntl): Likewise.
+ * sysdeps/unix/sysv/linux/generic/wordsize-32/fcntl.c (__libc_fcntl):
+ Likewise.
+ * sysdeps/nptl/Makefile [$(subdir) = rt] (librt-sysdep_routines):
+ Remove librt-cancellation object.
+ [$(subdir) = rt] (librt-cancellation.c): Remove rule.
+ * sysdeps/nptl/librt-cancellation.c: Remove file.
+ * sysdeps/unix/sysv/linux/lowlevellock-futex.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/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): New prototype.
+ * sysdeps/unix/sysv/linux/socketcall.h (SOCKETCALL): Use __SSC macros.
+ (SOCKETCALL_CANCEL): Use SYSCALL_CANCEL macros.
+ * 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.
+ * nptl/tst-cancel28.c: New file.
+
* nptl/Makefile [$(run-built-tests) = yes] (tests-special): Remove
tst-cancel-wrappers.sh.
* nptl/tst-cancel-wrappers.sh: Remove file.
diff --git a/io/creat.c b/io/creat.c
index c03810d..f602401 100644
--- a/io/creat.c
+++ b/io/creat.c
@@ -29,6 +29,3 @@ creat (file, mode)
{
return __open (file, O_WRONLY|O_CREAT|O_TRUNC, mode);
}
-
-/* __open handles cancellation. */
-LIBC_CANCEL_HANDLED ();
diff --git a/io/ppoll.c b/io/ppoll.c
index f64c737..3f08f1d 100644
--- a/io/ppoll.c
+++ b/io/ppoll.c
@@ -70,7 +70,5 @@ ppoll (struct pollfd *fds, nfds_t nfds, const struct timespec *timeout,
}
#ifndef ppoll
-/* __poll handles cancellation. */
-LIBC_CANCEL_HANDLED ();
libc_hidden_def (ppoll);
#endif
diff --git a/misc/pselect.c b/misc/pselect.c
index 2f8d0a3..e8d6dfd 100644
--- a/misc/pselect.c
+++ b/misc/pselect.c
@@ -73,6 +73,4 @@ __pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
}
#ifndef __pselect
weak_alias (__pselect, pselect)
-/* __select handles cancellation. */
-LIBC_CANCEL_HANDLED ();
#endif
diff --git a/nptl/Makefile b/nptl/Makefile
index b7ff3f1..1bd9dfb 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 pt-interp \
@@ -104,7 +104,6 @@ libpthread-routines = nptl-init vars events version pt-interp \
cleanup cleanup_defer cleanup_compat \
cleanup_defer_compat unwind \
pt-longjmp pt-cleanup\
- cancellation \
lowlevellock lowlevelrobustlock \
lll_timedlock_wait lll_timedwait_tid \
pt-fork pt-vfork \
@@ -159,7 +158,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
@@ -259,7 +257,7 @@ tests = tst-typesizes \
tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \
tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \
tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel24 tst-cancel25 \
- tst-cancel26 tst-cancel27 \
+ tst-cancel26 tst-cancel27 tst-cancel28 \
tst-cancel-self tst-cancel-self-cancelstate \
tst-cancel-self-canceltype tst-cancel-self-testcancel \
tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \
diff --git a/nptl/Versions b/nptl/Versions
index 0ae5def..734d47a 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 2bd3168..0000000
--- a/nptl/cancellation.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/* Copyright (C) 2002-2015 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"
-#include <futex-internal.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))
- {
- futex_wait_simple ((unsigned int *) &self->cancelhandling, newval,
- FUTEX_PRIVATE);
- newval = THREAD_GETMEM (self, cancelhandling);
- }
-}
diff --git a/nptl/descr.h b/nptl/descr.h
index a502048..6eb0036 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 cc9dc06..70f7f66 100644
--- a/nptl/libc-cancellation.c
+++ b/nptl/libc-cancellation.c
@@ -16,9 +16,69 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <setjmp.h>
+#include <stdlib.h>
#include "pthreadP.h"
+#if 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 (__syscall_arg_t nr, __syscall_arg_t a1,
+ __syscall_arg_t a2, __syscall_arg_t a3,
+ __syscall_arg_t a4, __syscall_arg_t a5,
+ __syscall_arg_t a6)
+{
+ long int result;
+ INTERNAL_SYSCALL_DECL (err);
+ result = INTERNAL_SYSCALL_NCS (nr, err, 6, a1, a2, a3, a4, a5, a6);
+ if (INTERNAL_SYSCALL_ERROR_P (result, err))
+ return -INTERNAL_SYSCALL_ERRNO (result, err);
+ return result;
+}
+
+#else
+
+/* Cancellation function called by all cancellable syscalls. */
+long int
+__syscall_cancel (__syscall_arg_t nr, __syscall_arg_t a1,
+ __syscall_arg_t a2, __syscall_arg_t a3,
+ __syscall_arg_t a4, __syscall_arg_t a5,
+ __syscall_arg_t 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);
+ if (INTERNAL_SYSCALL_ERROR_P (result, err))
+ return -INTERNAL_SYSCALL_ERRNO (result, err);
+ return 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/lll_timedlock_wait.c b/nptl/lll_timedlock_wait.c
index 37cf083..a21e66c 100644
--- a/nptl/lll_timedlock_wait.c
+++ b/nptl/lll_timedlock_wait.c
@@ -52,7 +52,7 @@ __lll_timedlock_wait (int *futex, const struct timespec *abstime, int private)
return ETIMEDOUT;
/* If *futex == 2, wait until woken or timeout. */
- lll_futex_timed_wait (futex, 2, &rt, private);
+ lll_futex_timed_wait_cancel (futex, 2, &rt, private);
}
return 0;
diff --git a/nptl/lll_timedwait_tid.c b/nptl/lll_timedwait_tid.c
index 68b4857..acb3c49 100644
--- a/nptl/lll_timedwait_tid.c
+++ b/nptl/lll_timedwait_tid.c
@@ -62,7 +62,8 @@ __lll_timedwait_tid (int *tidp, const struct timespec *abstime)
The kernel up to version 3.16.3 does not use the private futex
operations for futex wake-up when the clone terminates.
*/
- 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 79bcaab..de3bcb5 100644
--- a/nptl/nptl-init.c
+++ b/nptl/nptl-init.c
@@ -38,6 +38,7 @@
#include <kernel-features.h>
#include <libc-internal.h>
#include <pthread-pids.h>
+#include <sysdep-cancel.h>
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
/* Pointer to the corresponding variable in libc. */
@@ -200,36 +201,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 *pc = (const char *)__pthread_get_pc (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 ||
+ (pc >= __syscall_cancel_arch_start && pc < __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);
}
#endif
@@ -400,7 +406,10 @@ __pthread_initialize_minimal_internal (void)
cannot install the handler we do not abort. Maybe we should, but
it is only asynchronous cancellation which is affected. */
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;
(void) __libc_sigaction (SIGCANCEL, &sa, NULL);
# endif
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index b96be56..acfb577 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -277,50 +277,34 @@ __do_cancel (void)
{
struct pthread *self = THREAD_SELF;
- /* Make sure we get no more cancellations. */
- THREAD_ATOMIC_BIT_SET (self, cancelhandling, EXITING_BIT);
+ /* Make sure we get no more cancellations by clearing the cancel
+ state. */
+ 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 IS_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 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 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 *, __syscall_arg_t nr,
+ __syscall_arg_t arg1, __syscall_arg_t arg2, __syscall_arg_t arg3,
+ __syscall_arg_t arg4, __syscall_arg_t arg5, __syscall_arg_t arg6);
+libc_hidden_proto (__syscall_cancel_arch);
/* Internal prototypes. */
@@ -488,9 +472,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;
#if IS_IN (libpthread)
hidden_proto (__pthread_mutex_init)
@@ -521,16 +502,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;
#if IS_IN (libpthread)
/* Special versions which use non-exported functions. */
diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
index 981e4bc..c0776c6 100644
--- a/nptl/pthread_cancel.c
+++ b/nptl/pthread_cancel.c
@@ -23,7 +23,6 @@
#include <atomic.h>
#include <sysdep.h>
-
int
pthread_cancel (pthread_t th)
{
@@ -37,75 +36,17 @@ pthread_cancel (pthread_t 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;
-
-#ifdef SIGCANCEL
- /* 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);
-#else
- /* It should be impossible to get here at all, since
- pthread_setcanceltype should never have allowed
- PTHREAD_CANCEL_ASYNCHRONOUS to be set. */
- abort ();
-#endif
-
- 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);
+ THREAD_ATOMIC_BIT_SET (pd, cancelhandling, CANCELED_BIT);
+ /* 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;
+ __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));
- 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 10b0a61..8c944c6 100644
--- a/nptl/pthread_cond_timedwait.c
+++ b/nptl/pthread_cond_timedwait.c
@@ -42,7 +42,6 @@ extern void __condvar_cleanup (void *arg)
struct _condvar_cleanup_buffer
{
- int oldtype;
pthread_cond_t *cond;
pthread_mutex_t *mutex;
unsigned int bc_seq;
@@ -63,7 +62,7 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
int pshared = (cond->__data.__mutex == (void *) ~0l)
? LLL_SHARED : LLL_PRIVATE;
-#if (defined lll_futex_timed_wait_requeue_pi \
+#if (defined lll_futex_timed_wait_requeue_pi_cancel \
&& defined __ASSUME_REQUEUE_PI)
int pi_flag = 0;
#endif
@@ -156,12 +155,9 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *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 ();
-
/* 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
@@ -177,10 +173,11 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
{
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
@@ -188,21 +185,19 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
{
#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 0d6558b..8e7bebb 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;
@@ -106,7 +105,7 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
int pshared = (cond->__data.__mutex == (void *) ~0l)
? LLL_SHARED : LLL_PRIVATE;
-#if (defined lll_futex_wait_requeue_pi \
+#if (defined lll_futex_wait_requeue_pi_cancel \
&& defined __ASSUME_REQUEUE_PI)
int pi_flag = 0;
#endif
@@ -157,10 +156,7 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *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_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
@@ -174,19 +170,17 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *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 d10f4ea..17436f5 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -289,7 +289,7 @@ START_THREAD_DEFN
/* 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;
@@ -317,14 +317,10 @@ START_THREAD_DEFN
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 a60adbd..6976980 100644
--- a/nptl/pthread_exit.c
+++ b/nptl/pthread_exit.c
@@ -23,9 +23,14 @@
void
__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 c841ff9..2c8ce0c 100644
--- a/nptl/pthread_join.c
+++ b/nptl/pthread_join.c
@@ -61,13 +61,10 @@ pthread_join (pthread_t threadid, void **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
@@ -89,10 +86,6 @@ pthread_join (pthread_t threadid, void **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 10567e6..2131e95 100644
--- a/nptl/pthread_timedjoin.c
+++ b/nptl/pthread_timedjoin.c
@@ -71,17 +71,9 @@ pthread_timedjoin_np (pthread_t threadid, void **thread_return,
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_wait.c b/nptl/sem_wait.c
index fce7ed4..1fda284 100644
--- a/nptl/sem_wait.c
+++ b/nptl/sem_wait.c
@@ -43,14 +43,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/nptl/tst-cancel28.c b/nptl/tst-cancel28.c
new file mode 100644
index 0000000..9f474c2
--- /dev/null
+++ b/nptl/tst-cancel28.c
@@ -0,0 +1,98 @@
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This testcase checks if there is resource leakage if the syscall has
+ returned from kernelspace, but before userspace saves the return
+ value. The 'leaker' thread should be able to close the file
+ descriptor if the resource is already allocated, meaning that
+ if the cancellation signal arrives *after* the open syscal
+ return from kernel, the side-effect should be visible to
+ application. */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+void *
+writeopener (void *arg)
+{
+ int fd;
+ for (;;)
+ {
+ fd = open (arg, O_WRONLY);
+ close (fd);
+ }
+}
+
+void *
+leaker (void *arg)
+{
+ int fd = open (arg, O_RDONLY);
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, 0);
+ close (fd);
+ return 0;
+}
+
+
+#define ITER_COUNT 1000
+#define MAX_FILENO 1024
+
+static int
+do_test (void)
+{
+ pthread_t td, bg;
+ struct stat st;
+ char tmp[] = "/tmp/cancel_race_XXXXXX";
+ struct timespec ts;
+ int i;
+ int ret = 0;
+
+ mktemp (tmp);
+ mkfifo (tmp, 0600);
+ srand (1);
+
+ pthread_create (&bg, 0, writeopener, tmp);
+ for (i = 0; i < ITER_COUNT; i++)
+ {
+ pthread_create (&td, NULL, leaker, tmp);
+ ts.tv_nsec = rand () % 100000;
+ ts.tv_sec = 0;
+ nanosleep (&ts, NULL);
+ pthread_cancel (td);
+ pthread_join (td, NULL);
+ }
+
+ unlink (tmp);
+
+ for (i = STDERR_FILENO+1; i < MAX_FILENO; i++)
+ {
+ if (!fstat (i, &st))
+ {
+ printf ("leaked fd %d\n", i);
+ ret = 1;
+ }
+ }
+ return ret;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 10
+#include "../test-skeleton.c"
diff --git a/rt/Makefile b/rt/Makefile
index e62e059..11a2dd5 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 e9339a3..0d44a08 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 4a6ebfc..e5c84cb 100644
--- a/sysdeps/nptl/aio_misc.h
+++ b/sysdeps/nptl/aio_misc.h
@@ -34,22 +34,18 @@
#define AIO_MISC_WAIT(result, futex, timeout, cancel) \
do { \
- volatile unsigned int *futexaddr = &futex; \
+ unsigned int *futexaddr = (unsigned int *)&futex; \
unsigned int oldval = futex; \
\
if (oldval != 0) \
{ \
pthread_mutex_unlock (&__aio_requests_mutex); \
\
- int oldtype; \
- if (cancel) \
- oldtype = LIBC_CANCEL_ASYNC (); \
- \
int status; \
do \
{ \
- status = futex_reltimed_wait ((unsigned int *) futexaddr, oldval, \
- timeout, FUTEX_PRIVATE); \
+ status = futex_reltimed_wait_cancelable (futexaddr, oldval, \
+ timeout, FUTEX_PRIVATE); \
if (status != EAGAIN) \
break; \
\
@@ -57,9 +53,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 96c8fa0..9efac58 100644
--- a/sysdeps/nptl/gai_misc.h
+++ b/sysdeps/nptl/gai_misc.h
@@ -35,22 +35,18 @@
#define GAI_MISC_WAIT(result, futex, timeout, cancel) \
do { \
- volatile unsigned int *futexaddr = &futex; \
+ unsigned int *futexaddr = (unsigned int *)&futex; \
unsigned int oldval = futex; \
\
if (oldval != 0) \
{ \
pthread_mutex_unlock (&__gai_requests_mutex); \
\
- int oldtype; \
- if (cancel) \
- oldtype = LIBC_CANCEL_ASYNC (); \
- \
int status; \
do \
{ \
- status = futex_reltimed_wait ((unsigned int *) futexaddr, oldval, \
- timeout, FUTEX_PRIVATE); \
+ status = futex_reltimed_wait_cancelable (futexaddr, oldval, \
+ timeout, FUTEX_PRIVATE); \
if (status != EAGAIN) \
break; \
\
@@ -58,9 +54,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 facfbdb..0000000
--- a/sysdeps/nptl/librt-cancellation.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Copyright (C) 2002-2015 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 27f4142..4f1b7ff 100644
--- a/sysdeps/nptl/lowlevellock.h
+++ b/sysdeps/nptl/lowlevellock.h
@@ -243,7 +243,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/open64.c b/sysdeps/posix/open64.c
index 74f669f..0c91963 100644
--- a/sysdeps/posix/open64.c
+++ b/sysdeps/posix/open64.c
@@ -34,16 +34,8 @@ __libc_open64 (const char *file, int oflag, ...)
va_end (arg);
}
- if (SINGLE_THREAD_P)
- return __libc_open (file, oflag | O_LARGEFILE, mode);
-
- int oldtype = LIBC_CANCEL_ASYNC ();
-
- int result = __libc_open (file, oflag | O_LARGEFILE, mode);
-
- LIBC_CANCEL_RESET (oldtype);
-
- return result;
+ /* __libc_open should be a cancellation point. */
+ return __libc_open (file, oflag | O_LARGEFILE, mode);
}
weak_alias (__libc_open64, __open64)
libc_hidden_weak (__open64)
diff --git a/sysdeps/posix/pause.c b/sysdeps/posix/pause.c
index 6ba4d42..bdaf1cb 100644
--- a/sysdeps/posix/pause.c
+++ b/sysdeps/posix/pause.c
@@ -38,8 +38,6 @@ __libc_pause (void)
}
weak_alias (__libc_pause, pause)
-LIBC_CANCEL_HANDLED (); /* sigsuspend handles our cancellation. */
-
#ifndef NO_CANCELLATION
# include <not-cancel.h>
diff --git a/sysdeps/posix/sigpause.c b/sysdeps/posix/sigpause.c
index 662640d..863b541 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/sigwait.c b/sysdeps/posix/sigwait.c
index 8dc550b..f4b5d2f 100644
--- a/sysdeps/posix/sigwait.c
+++ b/sysdeps/posix/sigwait.c
@@ -88,13 +88,8 @@ __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;
+ /* do_sigwait should be a cancellation point. */
+ return do_sigwait (set, sig);
}
libc_hidden_def (__sigwait)
weak_alias (__sigwait, sigwait)
diff --git a/sysdeps/posix/waitid.c b/sysdeps/posix/waitid.c
index de41227..00a7db5 100644
--- a/sysdeps/posix/waitid.c
+++ b/sysdeps/posix/waitid.c
@@ -151,16 +151,7 @@ OUR_WAITID (idtype_t idtype, id_t id, siginfo_t *infop, int options)
int
__waitid (idtype_t idtype, id_t id, 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/unix/sysdep.h b/sysdeps/unix/sysdep.h
index 52dad58..8de99f1 100644
--- a/sysdeps/unix/sysdep.h
+++ b/sysdeps/unix/sysdep.h
@@ -20,31 +20,69 @@
#include <sys/syscall.h>
#define HAVE_SYSCALLS
+#ifndef __ASSEMBLER__
+# include <errno.h>
+
/* Note that using a `PASTE' macro loses. */
#define SYSCALL__(name, args) PSEUDO (__##name, name, args)
#define SYSCALL(name, args) PSEUDO (name, name, args)
/* Cancellation macros. */
-#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,n,...) n
+#ifndef __SSC
+typedef long int __syscall_arg_t;
+# define __SSC(__x) ((__syscall_arg_t) (__x))
+#endif
+
+#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(name, ...) \
- ({ \
- long int sc_ret; \
- if (SINGLE_THREAD_P) \
- sc_ret = INLINE_SYSCALL (name, __SYSCALL_NARGS(__VA_ARGS__), \
- __VA_ARGS__); \
- else \
- { \
- int sc_cancel_oldtype = LIBC_CANCEL_ASYNC (); \
- sc_ret = INLINE_SYSCALL (name, __SYSCALL_NARGS (__VA_ARGS__), \
- __VA_ARGS__); \
- LIBC_CANCEL_RESET (sc_cancel_oldtype); \
- } \
- sc_ret; \
+#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 (__syscall_arg_t nr, __syscall_arg_t arg1,
+ __syscall_arg_t arg2, __syscall_arg_t arg3,
+ __syscall_arg_t arg4, __syscall_arg_t arg5,
+ __syscall_arg_t 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/clock_nanosleep.c b/sysdeps/unix/sysv/linux/clock_nanosleep.c
index 69c47ca..fd96783 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/fcntl.c b/sysdeps/unix/sysv/linux/fcntl.c
index fa184db..192e50d 100644
--- a/sysdeps/unix/sysv/linux/fcntl.c
+++ b/sysdeps/unix/sysv/linux/fcntl.c
@@ -25,7 +25,7 @@
static int
-do_fcntl (int fd, int cmd, void *arg)
+__fcntl_common_nocancel (int fd, int cmd, void *arg)
{
if (cmd != F_GETOWN)
return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
@@ -40,8 +40,22 @@ do_fcntl (int fd, int cmd, void *arg)
return -1;
}
+static int
+__fcntl_common_cancel (int fd, int cmd, void *arg)
+{
+ if (cmd != F_GETOWN)
+ return SYSCALL_CANCEL (fcntl, fd, cmd, arg);
-#ifndef NO_CANCELLATION
+ struct f_owner_ex fex;
+ int res = SYSCALL_CANCEL_NCS (fcntl, fd, F_GETOWN_EX, &fex);
+ if (!SYSCALL_CANCEL_ERROR (res))
+ return fex.type == F_OWNER_GID ? -fex.pid : fex.pid;
+
+ __set_errno (SYSCALL_CANCEL_ERRNO (res));
+ return -1;
+}
+
+#if !IS_IN (rtld)
int
__fcntl_nocancel (int fd, int cmd, ...)
{
@@ -52,11 +66,10 @@ __fcntl_nocancel (int fd, int cmd, ...)
arg = va_arg (ap, void *);
va_end (ap);
- return do_fcntl (fd, cmd, arg);
+ return __fcntl_common_nocancel (fd, cmd, arg);
}
#endif
-
int
__libc_fcntl (int fd, int cmd, ...)
{
@@ -67,16 +80,10 @@ __libc_fcntl (int fd, int cmd, ...)
arg = va_arg (ap, void *);
va_end (ap);
- if (SINGLE_THREAD_P || cmd != F_SETLKW)
- return do_fcntl (fd, cmd, arg);
-
- int oldtype = LIBC_CANCEL_ASYNC ();
-
- int result = do_fcntl (fd, cmd, arg);
-
- LIBC_CANCEL_RESET (oldtype);
+ if (cmd != F_SETLKW)
+ return __fcntl_common_nocancel (fd, cmd, arg);
- return result;
+ return __fcntl_common_cancel (fd,cmd, arg);
}
libc_hidden_def (__libc_fcntl)
diff --git a/sysdeps/unix/sysv/linux/futex-internal.h b/sysdeps/unix/sysv/linux/futex-internal.h
index aca0911..260e3da 100644
--- a/sysdeps/unix/sysv/linux/futex-internal.h
+++ b/sysdeps/unix/sysv/linux/futex-internal.h
@@ -83,10 +83,7 @@ static __always_inline int
futex_wait_cancelable (unsigned int *futex_word, unsigned int expected,
int private)
{
- int oldtype;
- oldtype = __pthread_enable_asynccancel ();
- int err = lll_futex_timed_wait (futex_word, expected, NULL, private);
- __pthread_disable_asynccancel (oldtype);
+ int err = lll_futex_timed_wait_cancel (futex_word, expected, NULL, private);
switch (err)
{
case 0:
@@ -137,10 +134,7 @@ futex_reltimed_wait_cancelable (unsigned int *futex_word,
unsigned int expected,
const struct timespec *reltime, int private)
{
- int oldtype;
- oldtype = __pthread_enable_asynccancel ();
- int err = lll_futex_timed_wait (futex_word, expected, reltime, private);
- __pthread_disable_asynccancel (oldtype);
+ int err = lll_futex_timed_wait_cancel (futex_word, expected, reltime, private);
switch (err)
{
case 0:
@@ -200,11 +194,9 @@ futex_abstimed_wait_cancelable (unsigned int *futex_word,
despite them being valid. */
if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
return ETIMEDOUT;
- int oldtype;
- oldtype = __pthread_enable_asynccancel ();
- int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime,
- FUTEX_CLOCK_REALTIME, private);
- __pthread_disable_asynccancel (oldtype);
+ int err = lll_futex_timed_wait_bitset_cancel (futex_word, expected, abstime,
+ FUTEX_CLOCK_REALTIME,
+ private);
switch (err)
{
case 0:
diff --git a/sysdeps/unix/sysv/linux/generic/creat.c b/sysdeps/unix/sysv/linux/generic/creat.c
index dc298fb..36eb4e5 100644
--- a/sysdeps/unix/sysv/linux/generic/creat.c
+++ b/sysdeps/unix/sysv/linux/generic/creat.c
@@ -29,9 +29,6 @@ creat (const char *file, mode_t mode)
return __open (file, O_WRONLY | O_CREAT | O_TRUNC, mode);
}
-/* __open handles cancellation. */
-LIBC_CANCEL_HANDLED ();
-
#if __WORDSIZE == 64
weak_alias (creat, creat64)
#endif
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/fcntl.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/fcntl.c
index a11bf83..80b0603 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/fcntl.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/fcntl.c
@@ -26,7 +26,7 @@
static int
-do_fcntl (int fd, int cmd, void *arg)
+__fcntl_common_nocancel (int fd, int cmd, void *arg)
{
if (cmd != F_GETOWN)
return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
@@ -41,8 +41,22 @@ do_fcntl (int fd, int cmd, void *arg)
return -1;
}
+static int
+__fcntl_common_cancel (int fd, int cmd, void *arg)
+{
+ if (cmd != F_GETOWN)
+ return SYSCALL_CANCEL (fcntl64, fd, cmd, arg);
+
+ struct f_owner_ex fex;
+ int res = SYSCALL_CANCEL_NCS (fcntl64, fd, F_GETOWN_EX, &fex);
+ if (!SYSCALL_CANCEL_ERROR (res))
+ return fex.type == F_OWNER_GID ? -fex.pid : fex.pid;
-#ifndef NO_CANCELLATION
+ __set_errno (SYSCALL_CANCEL_ERRNO (res));
+ return -1;
+}
+
+#if !IS_IN (rtld)
int
__fcntl_nocancel (int fd, int cmd, ...)
{
@@ -53,7 +67,7 @@ __fcntl_nocancel (int fd, int cmd, ...)
arg = va_arg (ap, void *);
va_end (ap);
- return do_fcntl (fd, cmd, arg);
+ return __fcntl_common_nocancel (fd, cmd, arg);
}
#endif
@@ -69,15 +83,9 @@ __libc_fcntl (int fd, int cmd, ...)
va_end (ap);
if (SINGLE_THREAD_P || cmd != F_SETLKW)
- return do_fcntl (fd, cmd, arg);
-
- int oldtype = LIBC_CANCEL_ASYNC ();
-
- int result = do_fcntl (fd, cmd, arg);
-
- LIBC_CANCEL_RESET (oldtype);
+ return __fcntl_common_nocancel (fd, cmd, arg);
- return result;
+ return __fcntl_common_cancel (fd,cmd, arg);
}
libc_hidden_def (__libc_fcntl)
diff --git a/sysdeps/unix/sysv/linux/lowlevellock-futex.h b/sysdeps/unix/sysv/linux/lowlevellock-futex.h
index 59f6627..1edb66f 100644
--- a/sysdeps/unix/sysv/linux/lowlevellock-futex.h
+++ b/sysdeps/unix/sysv/linux/lowlevellock-futex.h
@@ -135,6 +135,50 @@
private), \
nr_wake, nr_move, mutex, val)
-#endif /* !__ASSEMBLER__ */
+/* Cancellable futex macros. */
+#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, __SSC (futexp), \
+ __SSC (__lll_private_flag (__op, private)), \
+ __SSC (val), __SSC (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, __SSC (futexp), \
+ __SSC (__lll_private_flag (__op, private)), \
+ __SSC (val), __SSC (timespec), 0, \
+ FUTEX_BITSET_MATCH_ANY); \
+ __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, __SSC (futexp), \
+ __SSC (__lll_private_flag (__op, private)), \
+ __SSC (val), __SSC (timespec), \
+ __SSC (mutex), 0); \
+ __ret; \
+ })
+
+# endif /* !__ASSEMBLER__ */
#endif /* lowlevellock-futex.h */
diff --git a/sysdeps/unix/sysv/linux/pthread_kill.c b/sysdeps/unix/sysv/linux/pthread_kill.c
index 8e8996a..f6d619c 100644
--- a/sysdeps/unix/sysv/linux/pthread_kill.c
+++ b/sysdeps/unix/sysv/linux/pthread_kill.c
@@ -41,9 +41,8 @@ __pthread_kill (pthread_t threadid, int 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/sigwait.c b/sysdeps/unix/sysv/linux/sigwait.c
index 26c3241..1003e5f 100644
--- a/sysdeps/unix/sysv/linux/sigwait.c
+++ b/sysdeps/unix/sysv/linux/sigwait.c
@@ -55,32 +55,17 @@ 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;
}
@@ -88,16 +73,7 @@ do_sigwait (const sigset_t *set, int *sig)
int
__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/socketcall.h b/sysdeps/unix/sysv/linux/socketcall.h
index f652239..007acba 100644
--- a/sysdeps/unix/sysv/linux/socketcall.h
+++ b/sysdeps/unix/sysv/linux/socketcall.h
@@ -86,17 +86,18 @@
sc_ret; \
})
-
-#if IS_IN (libc)
-# define __pthread_enable_asynccancel __libc_enable_asynccancel
-# define __pthread_disable_asynccancel __libc_disable_asynccancel
-#endif
-
-#define SOCKETCALL_CANCEL(name, args...) \
+#define SOCKETCALL_CANCEL(name, __a1, __a2, __a3, __a4, __a5, __a6) \
({ \
- int oldtype = LIBC_CANCEL_ASYNC (); \
- long int sc_ret = __SOCKETCALL (SOCKOP_##name, args); \
- LIBC_CANCEL_RESET (oldtype); \
+ __syscall_arg_t __args[6] = { __SSC (__a1), __SSC (__a2), \
+ __SSC (__a3), __SSC (__a4), \
+ __SSC (__a5), __SSC (__a6) }; \
+ long int sc_ret = SYSCALL_CANCEL_NCS (socketcall, SOCKOP_##name, \
+ __args); \
+ if (SYSCALL_CANCEL_ERROR (sc_ret)) \
+ { \
+ __set_errno (SYSCALL_CANCEL_ERRNO (sc_ret)); \
+ sc_ret = -1L; \
+ } \
sc_ret; \
})
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=f057c95593aeb88b62757daa11eca3b94513d76f
commit f057c95593aeb88b62757daa11eca3b94513d76f
Author: Adhemerval Zanella <adhemerval.zanella@linaro.com>
Date: Mon Sep 21 15:55:58 2015 -0700
nptl: Fix testcases for new pthread cancellation mechanism
With upcoming fix for BZ#12683, pthread cancellation does not act for:
1. If syscall is blocked but with some side effects already having taken
place (e.g. a partial read or write)
2. After the syscall has returned.
It is because program need to act on such cases (for instance, to avoid
leak of allocated resources our handling partial read/write).
This patches fixes the NPTL testcase that assumes the old behavior and
also remove the tst-cancel-wrappers.sh test (which checks for symbols
that does not exist anymore).
It also add two more testcase to check both the returned and the errno
value on case of a cancelled syscall.
Tested on i686, x86_64, x32, powerpc64le, and aarch64.
* nptl/Makefile [$(run-built-tests) = yes] (tests-special): Remove
tst-cancel-wrappers.sh.
* nptl/tst-cancel-wrappers.sh: Remove file.
* nptl/tst-cancel20.c (sh_body): Add pthread_testcancel after
cancellable syscall
* nptl/tst-cancel21.c (sh_body): Likewise.
(tf_body): Likewise.
* nptl/tst-cancel4.c (tf_Write): Likewise.
(tf_send): Likewise.
(cl_fifo): New function: pipe handling for open/open64.
(tf_sigpause): Use sigpause instead of __xpg_sigpausea and use
SIGINT instead of SIGCANCEL.
(tf_open): Use mkfifo to check for early cancel.
(tf_open64): New test: check for open64 cancellable syscall.
(tf_pread64): New test: check for pread64 cancellable syscall.
(tf_pwrite64): New test: check for pwrite64 cancellable syscall.
diff --git a/ChangeLog b/ChangeLog
index 00e1cc5..0c9c7b2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2015-10-12 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ * nptl/Makefile [$(run-built-tests) = yes] (tests-special): Remove
+ tst-cancel-wrappers.sh.
+ * nptl/tst-cancel-wrappers.sh: Remove file.
+ * nptl/tst-cancel20.c (sh_body): Add pthread_testcancel after
+ cancellable syscall
+ * nptl/tst-cancel21.c (sh_body): Likewise.
+ (tf_body): Likewise.
+ * nptl/tst-cancel4.c (tf_Write): Likewise.
+ (tf_send): Likewise.
+ (cl_fifo): New function: pipe handling for open/open64.
+ (tf_sigpause): Use sigpause instead of __xpg_sigpausea and use
+ SIGINT instead of SIGCANCEL.
+ (tf_open): Use mkfifo to check for early cancel.
+ (tf_open64): New test: check for open64 cancellable syscall.
+ (tf_pread64): New test: check for pread64 cancellable syscall.
+ (tf_pwrite64): New test: check for pwrite64 cancellable syscall.
+
2015-10-12 Andreas Schwab <schwab@suse.de>
[BZ #18969]
diff --git a/nptl/Makefile b/nptl/Makefile
index 311b1a7..b7ff3f1 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -398,8 +398,7 @@ tests-reverse += tst-cancel5 tst-cancel23 tst-vfork1x tst-vfork2x
ifeq ($(run-built-tests),yes)
tests-special += $(objpfx)tst-stack3-mem.out $(objpfx)tst-oddstacklimit.out
ifeq ($(build-shared),yes)
-tests-special += $(objpfx)tst-tls6.out $(objpfx)tst-cleanup0-cmp.out \
- $(objpfx)tst-cancel-wrappers.out
+tests-special += $(objpfx)tst-tls6.out $(objpfx)tst-cleanup0-cmp.out
endif
endif
@@ -615,7 +614,7 @@ $(objpfx)$(multidir)/crtn.o: $(objpfx)crtn.o $(objpfx)$(multidir)/
endif
generated += libpthread_nonshared.a \
- multidir.mk tst-atfork2.mtrace tst-cancel-wrappers.out \
+ multidir.mk tst-atfork2.mtrace \
tst-tls6.out
generated += $(objpfx)tst-atfork2.mtrace \
@@ -632,18 +631,6 @@ LDFLAGS-pthread.so += -e __nptl_main
$(objpfx)pt-interp.os: $(common-objpfx)runtime-linker.h
endif
-ifeq ($(run-built-tests),yes)
-ifeq (yes,$(build-shared))
-$(objpfx)tst-cancel-wrappers.out: tst-cancel-wrappers.sh
- $(SHELL) $< '$(NM)' \
- $(common-objpfx)libc_pic.a \
- $(common-objpfx)libc.a \
- $(objpfx)libpthread_pic.a \
- $(objpfx)libpthread.a > $@; \
- $(evaluate-test)
-endif
-endif
-
tst-exec4-ARGS = $(host-test-program-cmd)
$(objpfx)tst-execstack: $(libdl)
diff --git a/nptl/tst-cancel-wrappers.sh b/nptl/tst-cancel-wrappers.sh
deleted file mode 100644
index d492a54..0000000
--- a/nptl/tst-cancel-wrappers.sh
+++ /dev/null
@@ -1,92 +0,0 @@
-#! /bin/sh
-# Test whether all cancelable functions are cancelable.
-# Copyright (C) 2002-2015 Free Software Foundation, Inc.
-# This file is part of the GNU C Library.
-# Contributed by Jakub Jelinek <jakub@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/>.
-
-NM="$1"; shift
-while [ $# -gt 0 ]; do
- ( $NM -P $1; echo 'end[end]:' ) | gawk ' BEGIN {
-C["accept"]=1
-C["close"]=1
-C["connect"]=1
-C["creat"]=1
-C["fcntl"]=1
-C["fdatasync"]=1
-C["fsync"]=1
-C["msgrcv"]=1
-C["msgsnd"]=1
-C["msync"]=1
-C["nanosleep"]=1
-C["open"]=1
-C["open64"]=1
-C["pause"]=1
-C["poll"]=1
-C["pread"]=1
-C["pread64"]=1
-C["pselect"]=1
-C["pwrite"]=1
-C["pwrite64"]=1
-C["read"]=1
-C["readv"]=1
-C["recv"]=1
-C["recvfrom"]=1
-C["recvmsg"]=1
-C["select"]=1
-C["send"]=1
-C["sendmsg"]=1
-C["sendto"]=1
-C["sigpause"]=1
-C["sigsuspend"]=1
-C["sigwait"]=1
-C["sigwaitinfo"]=1
-C["tcdrain"]=1
-C["wait"]=1
-C["waitid"]=1
-C["waitpid"]=1
-C["write"]=1
-C["writev"]=1
-C["__xpg_sigpause"]=1
-}
-/:$/ {
- if (seen)
- {
- if (!seen_enable || !seen_disable)
- {
- printf "in '$1'(%s) %s'\''s cancellation missing\n", object, seen
- ret = 1
- }
- }
- seen=""
- seen_enable=""
- seen_disable=""
- object=gensub(/^.*\[(.*)\]:$/, "\\1", 1, $0)
- next
-}
-{
- if (C[$1] && $2 ~ /^[TW]$/)
- seen=$1
- else if ($1 ~ /^([.]|)__(libc|pthread)_enable_asynccancel$/ && $2 == "U")
- seen_enable=1
- else if ($1 ~ /^([.]|)__(libc|pthread)_disable_asynccancel$/ && $2 == "U")
- seen_disable=1
-}
-END {
- exit ret
-}' || exit
- shift
-done
diff --git a/nptl/tst-cancel20.c b/nptl/tst-cancel20.c
index 51b558e..b8c2337 100644
--- a/nptl/tst-cancel20.c
+++ b/nptl/tst-cancel20.c
@@ -49,6 +49,7 @@ sh_body (void)
puts ("read succeeded");
exit (1);
}
+ pthread_testcancel ();
pthread_cleanup_pop (0);
}
diff --git a/nptl/tst-cancel21.c b/nptl/tst-cancel21.c
index b54f236..307a269 100644
--- a/nptl/tst-cancel21.c
+++ b/nptl/tst-cancel21.c
@@ -50,6 +50,7 @@ sh_body (void)
puts ("read succeeded");
exit (1);
}
+ pthread_testcancel ();
pthread_cleanup_pop (0);
}
diff --git a/nptl/tst-cancel4.c b/nptl/tst-cancel4.c
index e50afd7..d63ddfd 100644
--- a/nptl/tst-cancel4.c
+++ b/nptl/tst-cancel4.c
@@ -38,8 +38,6 @@
#include <sys/un.h>
#include <sys/wait.h>
-#include "pthreadP.h"
-
/* Since STREAMS are not supported in the standard Linux kernel and
there we don't advertise STREAMS as supported is no need to test
@@ -117,7 +115,20 @@ cl (void *arg)
++cl_called;
}
+/* Named pipe used to check for blocking open. It should be closed
+ after the cancellation handling. */
+static char fifoname[] = "/tmp/tst-cancel4-fifo-XXXXXX";
+static int fifofd;
+static void
+cl_fifo (void *arg)
+{
+ ++cl_called;
+
+ unlink (fifoname);
+ close (fifofd);
+ fifofd = -1;
+}
static void *
tf_read (void *arg)
@@ -247,6 +258,10 @@ tf_write (void *arg)
char buf[WRITE_BUFFER_SIZE];
memset (buf, '\0', sizeof (buf));
s = write (fd, buf, sizeof (buf));
+ /* The write can return a value higher than 0 (meaning partial write)
+ due to the SIGCANCEL, but the thread may still be pending
+ cancellation. */
+ pthread_testcancel ();
pthread_cleanup_pop (0);
@@ -781,13 +796,7 @@ tf_sigpause (void *arg)
pthread_cleanup_push (cl, NULL);
-#ifdef SIGCANCEL
- /* Just for fun block the cancellation signal. We need to use
- __xpg_sigpause since otherwise we will get the BSD version. */
- __xpg_sigpause (SIGCANCEL);
-#else
- pause ();
-#endif
+ sigpause (sigmask (SIGINT));
pthread_cleanup_pop (0);
@@ -1143,6 +1152,10 @@ tf_send (void *arg)
char mem[700000];
send (tempfd2, mem, arg == NULL ? sizeof (mem) : 1, 0);
+ /* Thez send can return a value higher than 0 (meaning partial send)
+ due to the SIGCANCEL, but the thread may still be pending
+ cancellation. */
+ pthread_testcancel ();
pthread_cleanup_pop (0);
@@ -1396,9 +1409,23 @@ static void *
tf_open (void *arg)
{
if (arg == NULL)
- // XXX If somebody can provide a portable test case in which open()
- // blocks we can enable this test to run in both rounds.
- abort ();
+ {
+ fifofd = mkfifo (fifoname, S_IWUSR | S_IRUSR);
+ if (fifofd == -1)
+ {
+ printf ("%s: mkfifo failed\n", __FUNCTION__);
+ exit (1);
+ }
+ }
+ else
+ {
+ int r = pthread_barrier_wait (&b2);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ printf ("%s: barrier_wait failed\n", __FUNCTION__);
+ exit (1);
+ }
+ }
int r = pthread_barrier_wait (&b2);
if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
@@ -1407,16 +1434,49 @@ tf_open (void *arg)
exit (1);
}
- r = pthread_barrier_wait (&b2);
+ pthread_cleanup_push (cl_fifo, NULL);
+
+ open (arg ? "Makefile" : fifoname, O_RDONLY);
+
+ pthread_cleanup_pop (0);
+
+ printf ("%s: open returned\n", __FUNCTION__);
+
+ exit (1);
+}
+
+static void *
+tf_open64 (void *arg)
+{
+ if (arg == NULL)
+ {
+ fifofd = mkfifo (fifoname, S_IWUSR | S_IRUSR);
+ if (fifofd == -1)
+ {
+ printf ("%s: mkfifo failed\n", __FUNCTION__);
+ exit (1);
+ }
+ }
+ else
+ {
+ int r = pthread_barrier_wait (&b2);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ printf ("%s: barrier_wait failed\n", __FUNCTION__);
+ exit (1);
+ }
+ }
+
+ int r = pthread_barrier_wait (&b2);
if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
{
- printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+ printf ("%s: barrier_wait failed\n", __FUNCTION__);
exit (1);
}
- pthread_cleanup_push (cl, NULL);
+ pthread_cleanup_push (cl_fifo, NULL);
- open ("Makefile", O_RDONLY);
+ open64 (arg ? "Makefile" : fifoname, O_RDONLY);
pthread_cleanup_pop (0);
@@ -1510,6 +1570,46 @@ tf_pread (void *arg)
exit (1);
}
+static void *
+tf_pread64 (void *arg)
+{
+ if (arg == NULL)
+ // XXX If somebody can provide a portable test case in which pread()
+ // blocks we can enable this test to run in both rounds.
+ abort ();
+
+ tempfd = open64 ("Makefile", O_RDONLY);
+ if (tempfd == -1)
+ {
+ printf ("%s: cannot open64 Makefile\n", __FUNCTION__);
+ exit (1);
+ }
+
+ int r = pthread_barrier_wait (&b2);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ printf ("%s: barrier_wait failed\n", __FUNCTION__);
+ exit (1);
+ }
+
+ r = pthread_barrier_wait (&b2);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+ exit (1);
+ }
+
+ pthread_cleanup_push (cl, NULL);
+
+ char mem[10];
+ pread64 (tempfd, mem, sizeof (mem), 0);
+
+ pthread_cleanup_pop (0);
+
+ printf ("%s: pread64 returned\n", __FUNCTION__);
+
+ exit (1);
+}
static void *
tf_pwrite (void *arg)
@@ -1554,6 +1654,48 @@ tf_pwrite (void *arg)
exit (1);
}
+static void *
+tf_pwrite64 (void *arg)
+{
+ if (arg == NULL)
+ // XXX If somebody can provide a portable test case in which pwrite()
+ // blocks we can enable this test to run in both rounds.
+ abort ();
+
+ char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
+ tempfd = mkstemp (fname);
+ if (tempfd == -1)
+ {
+ printf ("%s: mkstemp failed\n", __FUNCTION__);
+ exit (1);
+ }
+ unlink (fname);
+
+ int r = pthread_barrier_wait (&b2);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ printf ("%s: barrier_wait failed\n", __FUNCTION__);
+ exit (1);
+ }
+
+ r = pthread_barrier_wait (&b2);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+ exit (1);
+ }
+
+ pthread_cleanup_push (cl, NULL);
+
+ char mem[10];
+ pwrite64 (tempfd, mem, sizeof (mem), 0);
+
+ pthread_cleanup_pop (0);
+
+ printf ("%s: pwrite64 returned\n", __FUNCTION__);
+
+ exit (1);
+}
static void *
tf_fsync (void *arg)
@@ -2140,10 +2282,13 @@ static struct
ADD_TEST (recv, 2, 0),
ADD_TEST (recvfrom, 2, 0),
ADD_TEST (recvmsg, 2, 0),
- ADD_TEST (open, 2, 1),
+ ADD_TEST (open, 2, 0),
+ ADD_TEST (open64, 2, 0),
ADD_TEST (close, 2, 1),
ADD_TEST (pread, 2, 1),
+ ADD_TEST (pread64, 2, 1),
ADD_TEST (pwrite, 2, 1),
+ ADD_TEST (pwrite64, 2, 1),
ADD_TEST (fsync, 2, 1),
ADD_TEST (fdatasync, 2, 1),
ADD_TEST (msync, 2, 1),
@@ -2185,6 +2330,12 @@ do_test (void)
}
setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val));
+ if (mktemp (fifoname) == NULL)
+ {
+ printf ("%s: cannot generate temp file name\n", __FUNCTION__);
+ exit (1);
+ }
+
int result = 0;
size_t cnt;
for (cnt = 0; cnt < ntest_tf; ++cnt)
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4e70e61ce46e599803922b38b05c4a5ebb9af9bc
commit 4e70e61ce46e599803922b38b05c4a5ebb9af9bc
Author: Adhemerval Zanella <adhemerval.zanella@linaro.com>
Date: Mon Oct 5 10:29:11 2015 -0300
nptl: x86_64: Remove assembly pthread_cond_{timed}wait.S implementation
This patch removes the x86_64 assembly implementation for
pthread_cond_timedwait and pthread_cond_wait for upcoming BZ#12683 fix.
The patch requires that cancellable futex calls to be called through
__syscall_cancel. Although it not strictly require, the remove of the
x86_64 specific implementation follows the rationale:
1. The adjustments required to this fix is extensive (parameters
save, functions calls, etc.) and there is little gain in keep an
alternate implementation for x86_64 in term of maintanability.
2. There is no pthread_cond benchmark that shows these implementations
are more 'optimized' that what current compilers can produce using
generic C code.
3. The changes required also can change the exact gains this optimized is
intended to provide.
diff --git a/ChangeLog b/ChangeLog
index f7734ac..00e1cc5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -139,6 +139,9 @@
2015-10-09 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+ * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+
* sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S: Remove
file.
* sysdeps/unix/sysv/linux/i386/pthread_cond_timedwait.S: Likewise.
diff --git a/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S b/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
deleted file mode 100644
index 15b872d..0000000
--- a/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+++ /dev/null
@@ -1,623 +0,0 @@
-/* Copyright (C) 2002-2015 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 <sysdep.h>
-#include <shlib-compat.h>
-#include <lowlevellock.h>
-#include <lowlevelcond.h>
-#include <pthread-pi-defines.h>
-#include <pthread-errnos.h>
-#include <stap-probe.h>
-
-#include <kernel-features.h>
-
-
- .text
-
-
-/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
- const struct timespec *abstime) */
- .globl __pthread_cond_timedwait
- .type __pthread_cond_timedwait, @function
- .align 16
-__pthread_cond_timedwait:
-.LSTARTCODE:
- cfi_startproc
-#ifdef SHARED
- cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
- DW.ref.__gcc_personality_v0)
- cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
-#else
- cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
- cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
-#endif
-
- pushq %r12
- cfi_adjust_cfa_offset(8)
- cfi_rel_offset(%r12, 0)
- pushq %r13
- cfi_adjust_cfa_offset(8)
- cfi_rel_offset(%r13, 0)
- pushq %r14
- cfi_adjust_cfa_offset(8)
- cfi_rel_offset(%r14, 0)
- pushq %r15
- cfi_adjust_cfa_offset(8)
- cfi_rel_offset(%r15, 0)
-#define FRAME_SIZE (32+8)
- subq $FRAME_SIZE, %rsp
- cfi_adjust_cfa_offset(FRAME_SIZE)
- cfi_remember_state
-
- LIBC_PROBE (cond_timedwait, 3, %rdi, %rsi, %rdx)
-
- cmpq $1000000000, 8(%rdx)
- movl $EINVAL, %eax
- jae 48f
-
- /* Stack frame:
-
- rsp + 48
- +--------------------------+
- rsp + 32 | timeout value |
- +--------------------------+
- rsp + 24 | old wake_seq value |
- +--------------------------+
- rsp + 16 | mutex pointer |
- +--------------------------+
- rsp + 8 | condvar pointer |
- +--------------------------+
- rsp + 4 | old broadcast_seq value |
- +--------------------------+
- rsp + 0 | old cancellation mode |
- +--------------------------+
- */
-
- LP_OP(cmp) $-1, dep_mutex(%rdi)
-
- /* Prepare structure passed to cancellation handler. */
- movq %rdi, 8(%rsp)
- movq %rsi, 16(%rsp)
- movq %rdx, %r13
-
- je 22f
- mov %RSI_LP, dep_mutex(%rdi)
-
-22:
- xorb %r15b, %r15b
-
- /* Get internal lock. */
- movl $1, %esi
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %esi, (%rdi)
-#else
- cmpxchgl %esi, cond_lock(%rdi)
-#endif
- jnz 31f
-
- /* Unlock the mutex. */
-32: movq 16(%rsp), %rdi
- xorl %esi, %esi
- callq __pthread_mutex_unlock_usercnt
-
- testl %eax, %eax
- jne 46f
-
- movq 8(%rsp), %rdi
- incq total_seq(%rdi)
- incl cond_futex(%rdi)
- addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
-
- /* Get and store current wakeup_seq value. */
- movq 8(%rsp), %rdi
- movq wakeup_seq(%rdi), %r9
- movl broadcast_seq(%rdi), %edx
- movq %r9, 24(%rsp)
- movl %edx, 4(%rsp)
-
- cmpq $0, (%r13)
- movq $-ETIMEDOUT, %r14
- js 36f
-
-38: movl cond_futex(%rdi), %r12d
-
- /* Unlock. */
- LOCK
-#if cond_lock == 0
- decl (%rdi)
-#else
- decl cond_lock(%rdi)
-#endif
- jne 33f
-
-.LcleanupSTART1:
-34: callq __pthread_enable_asynccancel
- movl %eax, (%rsp)
-
- movq %r13, %r10
- movl $FUTEX_WAIT_BITSET, %esi
- LP_OP(cmp) $-1, dep_mutex(%rdi)
- je 60f
-
- mov dep_mutex(%rdi), %R8_LP
- /* Requeue to a non-robust PI mutex if the PI bit is set and
- the robust bit is not set. */
- movl MUTEX_KIND(%r8), %eax
- andl $(ROBUST_BIT|PI_BIT), %eax
- cmpl $PI_BIT, %eax
- jne 61f
-
- movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
- xorl %eax, %eax
- /* The following only works like this because we only support
- two clocks, represented using a single bit. */
- testl $1, cond_nwaiters(%rdi)
- movl $FUTEX_CLOCK_REALTIME, %edx
- cmove %edx, %eax
- orl %eax, %esi
- movq %r12, %rdx
- addq $cond_futex, %rdi
- movl $SYS_futex, %eax
- syscall
-
- cmpl $0, %eax
- sete %r15b
-
-#ifdef __ASSUME_REQUEUE_PI
- jmp 62f
-#else
- je 62f
-
- /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
- successfully, it has already locked the mutex for us and the
- pi_flag (%r15b) is set to denote that fact. However, if another
- thread changed the futex value before we entered the wait, the
- syscall may return an EAGAIN and the mutex is not locked. We go
- ahead with a success anyway since later we look at the pi_flag to
- decide if we got the mutex or not. The sequence numbers then make
- sure that only one of the threads actually wake up. We retry using
- normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
- and PI futexes don't mix.
-
- Note that we don't check for EAGAIN specifically; we assume that the
- only other error the futex function could return is EAGAIN (barring
- the ETIMEOUT of course, for the timeout case in futex) since
- anything else would mean an error in our function. It is too
- expensive to do that check for every call (which is quite common in
- case of a large number of threads), so it has been skipped. */
- cmpl $-ENOSYS, %eax
- jne 62f
-
- subq $cond_futex, %rdi
-#endif
-
-61: movl $(FUTEX_WAIT_BITSET|FUTEX_PRIVATE_FLAG), %esi
-60: xorb %r15b, %r15b
- xorl %eax, %eax
- /* The following only works like this because we only support
- two clocks, represented using a single bit. */
- testl $1, cond_nwaiters(%rdi)
- movl $FUTEX_CLOCK_REALTIME, %edx
- movl $0xffffffff, %r9d
- cmove %edx, %eax
- orl %eax, %esi
- movq %r12, %rdx
- addq $cond_futex, %rdi
- movl $SYS_futex, %eax
- syscall
-62: movq %rax, %r14
-
- movl (%rsp), %edi
- callq __pthread_disable_asynccancel
-.LcleanupEND1:
-
- /* Lock. */
- movq 8(%rsp), %rdi
- movl $1, %esi
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %esi, (%rdi)
-#else
- cmpxchgl %esi, cond_lock(%rdi)
-#endif
- jne 35f
-
-36: movl broadcast_seq(%rdi), %edx
-
- movq woken_seq(%rdi), %rax
-
- movq wakeup_seq(%rdi), %r9
-
- cmpl 4(%rsp), %edx
- jne 53f
-
- cmpq 24(%rsp), %r9
- jbe 45f
-
- cmpq %rax, %r9
- ja 39f
-
-45: cmpq $-ETIMEDOUT, %r14
- je 99f
-
- /* We need to go back to futex_wait. If we're using requeue_pi, then
- release the mutex we had acquired and go back. */
- test %r15b, %r15b
- jz 38b
-
- /* Adjust the mutex values first and then unlock it. The unlock
- should always succeed or else the kernel did not lock the
- mutex correctly. */
- movq %r8, %rdi
- callq __pthread_mutex_cond_lock_adjust
- xorl %esi, %esi
- callq __pthread_mutex_unlock_usercnt
- /* Reload cond_var. */
- movq 8(%rsp), %rdi
- jmp 38b
-
-99: incq wakeup_seq(%rdi)
- incl cond_futex(%rdi)
- movl $ETIMEDOUT, %r14d
- jmp 44f
-
-53: xorq %r14, %r14
- jmp 54f
-
-39: xorq %r14, %r14
-44: incq woken_seq(%rdi)
-
-54: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
-
- /* Wake up a thread which wants to destroy the condvar object. */
- cmpq $0xffffffffffffffff, total_seq(%rdi)
- jne 55f
- movl cond_nwaiters(%rdi), %eax
- andl $~((1 << nwaiters_shift) - 1), %eax
- jne 55f
-
- addq $cond_nwaiters, %rdi
- LP_OP(cmp) $-1, dep_mutex-cond_nwaiters(%rdi)
- movl $1, %edx
-#ifdef __ASSUME_PRIVATE_FUTEX
- movl $FUTEX_WAKE, %eax
- movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
- cmove %eax, %esi
-#else
- movl $0, %eax
- movl %fs:PRIVATE_FUTEX, %esi
- cmove %eax, %esi
- orl $FUTEX_WAKE, %esi
-#endif
- movl $SYS_futex, %eax
- syscall
- subq $cond_nwaiters, %rdi
-
-55: LOCK
-#if cond_lock == 0
- decl (%rdi)
-#else
- decl cond_lock(%rdi)
-#endif
- jne 40f
-
- /* If requeue_pi is used the kernel performs the locking of the
- mutex. */
-41: movq 16(%rsp), %rdi
- testb %r15b, %r15b
- jnz 64f
-
- callq __pthread_mutex_cond_lock
-
-63: testq %rax, %rax
- cmoveq %r14, %rax
-
-48: addq $FRAME_SIZE, %rsp
- cfi_adjust_cfa_offset(-FRAME_SIZE)
- popq %r15
- cfi_adjust_cfa_offset(-8)
- cfi_restore(%r15)
- popq %r14
- cfi_adjust_cfa_offset(-8)
- cfi_restore(%r14)
- popq %r13
- cfi_adjust_cfa_offset(-8)
- cfi_restore(%r13)
- popq %r12
- cfi_adjust_cfa_offset(-8)
- cfi_restore(%r12)
-
- retq
-
- cfi_restore_state
-
-64: callq __pthread_mutex_cond_lock_adjust
- movq %r14, %rax
- jmp 48b
-
- /* Initial locking failed. */
-31:
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_lock_wait
- jmp 32b
-
- /* Unlock in loop requires wakeup. */
-33:
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_unlock_wake
- jmp 34b
-
- /* Locking in loop failed. */
-35:
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_lock_wait
-#if cond_lock != 0
- subq $cond_lock, %rdi
-#endif
- jmp 36b
-
- /* Unlock after loop requires wakeup. */
-40:
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_unlock_wake
- jmp 41b
-
- /* The initial unlocking of the mutex failed. */
-46: movq 8(%rsp), %rdi
- movq %rax, (%rsp)
- LOCK
-#if cond_lock == 0
- decl (%rdi)
-#else
- decl cond_lock(%rdi)
-#endif
- jne 47f
-
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_unlock_wake
-
-47: movq (%rsp), %rax
- jmp 48b
-
- .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
-versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
- GLIBC_2_3_2)
-
-
- .align 16
- .type __condvar_cleanup2, @function
-__condvar_cleanup2:
- /* Stack frame:
-
- rsp + 72
- +--------------------------+
- rsp + 64 | %r12 |
- +--------------------------+
- rsp + 56 | %r13 |
- +--------------------------+
- rsp + 48 | %r14 |
- +--------------------------+
- rsp + 24 | unused |
- +--------------------------+
- rsp + 16 | mutex pointer |
- +--------------------------+
- rsp + 8 | condvar pointer |
- +--------------------------+
- rsp + 4 | old broadcast_seq value |
- +--------------------------+
- rsp + 0 | old cancellation mode |
- +--------------------------+
- */
-
- movq %rax, 24(%rsp)
-
- /* Get internal lock. */
- movq 8(%rsp), %rdi
- movl $1, %esi
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %esi, (%rdi)
-#else
- cmpxchgl %esi, cond_lock(%rdi)
-#endif
- jz 1f
-
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_lock_wait
-#if cond_lock != 0
- subq $cond_lock, %rdi
-#endif
-
-1: movl broadcast_seq(%rdi), %edx
- cmpl 4(%rsp), %edx
- jne 3f
-
- /* We increment the wakeup_seq counter only if it is lower than
- total_seq. If this is not the case the thread was woken and
- then canceled. In this case we ignore the signal. */
- movq total_seq(%rdi), %rax
- cmpq wakeup_seq(%rdi), %rax
- jbe 6f
- incq wakeup_seq(%rdi)
- incl cond_futex(%rdi)
-6: incq woken_seq(%rdi)
-
-3: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
-
- /* Wake up a thread which wants to destroy the condvar object. */
- xorq %r12, %r12
- cmpq $0xffffffffffffffff, total_seq(%rdi)
- jne 4f
- movl cond_nwaiters(%rdi), %eax
- andl $~((1 << nwaiters_shift) - 1), %eax
- jne 4f
-
- LP_OP(cmp) $-1, dep_mutex(%rdi)
- leaq cond_nwaiters(%rdi), %rdi
- movl $1, %edx
-#ifdef __ASSUME_PRIVATE_FUTEX
- movl $FUTEX_WAKE, %eax
- movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
- cmove %eax, %esi
-#else
- movl $0, %eax
- movl %fs:PRIVATE_FUTEX, %esi
- cmove %eax, %esi
- orl $FUTEX_WAKE, %esi
-#endif
- movl $SYS_futex, %eax
- syscall
- subq $cond_nwaiters, %rdi
- movl $1, %r12d
-
-4: LOCK
-#if cond_lock == 0
- decl (%rdi)
-#else
- decl cond_lock(%rdi)
-#endif
- je 2f
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_unlock_wake
-
- /* Wake up all waiters to make sure no signal gets lost. */
-2: testq %r12, %r12
- jnz 5f
- addq $cond_futex, %rdi
- LP_OP(cmp) $-1, dep_mutex-cond_futex(%rdi)
- movl $0x7fffffff, %edx
-#ifdef __ASSUME_PRIVATE_FUTEX
- movl $FUTEX_WAKE, %eax
- movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
- cmove %eax, %esi
-#else
- movl $0, %eax
- movl %fs:PRIVATE_FUTEX, %esi
- cmove %eax, %esi
- orl $FUTEX_WAKE, %esi
-#endif
- movl $SYS_futex, %eax
- syscall
-
- /* Lock the mutex only if we don't own it already. This only happens
- in case of PI mutexes, if we got cancelled after a successful
- return of the futex syscall and before disabling async
- cancellation. */
-5: movq 16(%rsp), %rdi
- movl MUTEX_KIND(%rdi), %eax
- andl $(ROBUST_BIT|PI_BIT), %eax
- cmpl $PI_BIT, %eax
- jne 7f
-
- movl (%rdi), %eax
- andl $TID_MASK, %eax
- cmpl %eax, %fs:TID
- jne 7f
- /* We managed to get the lock. Fix it up before returning. */
- callq __pthread_mutex_cond_lock_adjust
- jmp 8f
-
-7: callq __pthread_mutex_cond_lock
-
-8: movq 24(%rsp), %rdi
- movq FRAME_SIZE(%rsp), %r15
- movq FRAME_SIZE+8(%rsp), %r14
- movq FRAME_SIZE+16(%rsp), %r13
- movq FRAME_SIZE+24(%rsp), %r12
-.LcallUR:
- call _Unwind_Resume@PLT
- hlt
-.LENDCODE:
- cfi_endproc
- .size __condvar_cleanup2, .-__condvar_cleanup2
-
-
- .section .gcc_except_table,"a",@progbits
-.LexceptSTART:
- .byte DW_EH_PE_omit # @LPStart format
- .byte DW_EH_PE_omit # @TType format
- .byte DW_EH_PE_uleb128 # call-site format
- .uleb128 .Lcstend-.Lcstbegin
-.Lcstbegin:
- .uleb128 .LcleanupSTART1-.LSTARTCODE
- .uleb128 .LcleanupEND1-.LcleanupSTART1
- .uleb128 __condvar_cleanup2-.LSTARTCODE
- .uleb128 0
- .uleb128 .LcallUR-.LSTARTCODE
- .uleb128 .LENDCODE-.LcallUR
- .uleb128 0
- .uleb128 0
-.Lcstend:
-
-
-#ifdef SHARED
- .hidden DW.ref.__gcc_personality_v0
- .weak DW.ref.__gcc_personality_v0
- .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
- .align LP_SIZE
- .type DW.ref.__gcc_personality_v0, @object
- .size DW.ref.__gcc_personality_v0, LP_SIZE
-DW.ref.__gcc_personality_v0:
- ASM_ADDR __gcc_personality_v0
-#endif
diff --git a/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S b/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
deleted file mode 100644
index 2e564a7..0000000
--- a/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+++ /dev/null
@@ -1,555 +0,0 @@
-/* Copyright (C) 2002-2015 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 <sysdep.h>
-#include <shlib-compat.h>
-#include <lowlevellock.h>
-#include <lowlevelcond.h>
-#include <tcb-offsets.h>
-#include <pthread-pi-defines.h>
-#include <pthread-errnos.h>
-#include <stap-probe.h>
-
-#include <kernel-features.h>
-
-
- .text
-
-/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
- .globl __pthread_cond_wait
- .type __pthread_cond_wait, @function
- .align 16
-__pthread_cond_wait:
-.LSTARTCODE:
- cfi_startproc
-#ifdef SHARED
- cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
- DW.ref.__gcc_personality_v0)
- cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
-#else
- cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
- cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
-#endif
-
-#define FRAME_SIZE (32+8)
- leaq -FRAME_SIZE(%rsp), %rsp
- cfi_adjust_cfa_offset(FRAME_SIZE)
-
- /* Stack frame:
-
- rsp + 32
- +--------------------------+
- rsp + 24 | old wake_seq value |
- +--------------------------+
- rsp + 16 | mutex pointer |
- +--------------------------+
- rsp + 8 | condvar pointer |
- +--------------------------+
- rsp + 4 | old broadcast_seq value |
- +--------------------------+
- rsp + 0 | old cancellation mode |
- +--------------------------+
- */
-
- LIBC_PROBE (cond_wait, 2, %rdi, %rsi)
-
- LP_OP(cmp) $-1, dep_mutex(%rdi)
-
- /* Prepare structure passed to cancellation handler. */
- movq %rdi, 8(%rsp)
- movq %rsi, 16(%rsp)
-
- je 15f
- mov %RSI_LP, dep_mutex(%rdi)
-
- /* Get internal lock. */
-15: movl $1, %esi
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %esi, (%rdi)
-#else
- cmpxchgl %esi, cond_lock(%rdi)
-#endif
- jne 1f
-
- /* Unlock the mutex. */
-2: movq 16(%rsp), %rdi
- xorl %esi, %esi
- callq __pthread_mutex_unlock_usercnt
-
- testl %eax, %eax
- jne 12f
-
- movq 8(%rsp), %rdi
- incq total_seq(%rdi)
- incl cond_futex(%rdi)
- addl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
-
- /* Get and store current wakeup_seq value. */
- movq 8(%rsp), %rdi
- movq wakeup_seq(%rdi), %r9
- movl broadcast_seq(%rdi), %edx
- movq %r9, 24(%rsp)
- movl %edx, 4(%rsp)
-
- /* Unlock. */
-8: movl cond_futex(%rdi), %edx
- LOCK
-#if cond_lock == 0
- decl (%rdi)
-#else
- decl cond_lock(%rdi)
-#endif
- jne 3f
-
-.LcleanupSTART:
-4: callq __pthread_enable_asynccancel
- movl %eax, (%rsp)
-
- xorq %r10, %r10
- LP_OP(cmp) $-1, dep_mutex(%rdi)
- leaq cond_futex(%rdi), %rdi
- movl $FUTEX_WAIT, %esi
- je 60f
-
- mov dep_mutex-cond_futex(%rdi), %R8_LP
- /* Requeue to a non-robust PI mutex if the PI bit is set and
- the robust bit is not set. */
- movl MUTEX_KIND(%r8), %eax
- andl $(ROBUST_BIT|PI_BIT), %eax
- cmpl $PI_BIT, %eax
- jne 61f
-
- movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi
- movl $SYS_futex, %eax
- syscall
-
- cmpl $0, %eax
- sete %r8b
-
-#ifdef __ASSUME_REQUEUE_PI
- jmp 62f
-#else
- je 62f
-
- /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
- successfully, it has already locked the mutex for us and the
- pi_flag (%r8b) is set to denote that fact. However, if another
- thread changed the futex value before we entered the wait, the
- syscall may return an EAGAIN and the mutex is not locked. We go
- ahead with a success anyway since later we look at the pi_flag to
- decide if we got the mutex or not. The sequence numbers then make
- sure that only one of the threads actually wake up. We retry using
- normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
- and PI futexes don't mix.
-
- Note that we don't check for EAGAIN specifically; we assume that the
- only other error the futex function could return is EAGAIN since
- anything else would mean an error in our function. It is too
- expensive to do that check for every call (which is quite common in
- case of a large number of threads), so it has been skipped. */
- cmpl $-ENOSYS, %eax
- jne 62f
-
-# ifndef __ASSUME_PRIVATE_FUTEX
- movl $FUTEX_WAIT, %esi
-# endif
-#endif
-
-61:
-#ifdef __ASSUME_PRIVATE_FUTEX
- movl $(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi
-#else
- orl %fs:PRIVATE_FUTEX, %esi
-#endif
-60: xorb %r8b, %r8b
- movl $SYS_futex, %eax
- syscall
-
-62: movl (%rsp), %edi
- callq __pthread_disable_asynccancel
-.LcleanupEND:
-
- /* Lock. */
- movq 8(%rsp), %rdi
- movl $1, %esi
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %esi, (%rdi)
-#else
- cmpxchgl %esi, cond_lock(%rdi)
-#endif
- jnz 5f
-
-6: movl broadcast_seq(%rdi), %edx
-
- movq woken_seq(%rdi), %rax
-
- movq wakeup_seq(%rdi), %r9
-
- cmpl 4(%rsp), %edx
- jne 16f
-
- cmpq 24(%rsp), %r9
- jbe 19f
-
- cmpq %rax, %r9
- jna 19f
-
- incq woken_seq(%rdi)
-
- /* Unlock */
-16: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
-
- /* Wake up a thread which wants to destroy the condvar object. */
- cmpq $0xffffffffffffffff, total_seq(%rdi)
- jne 17f
- movl cond_nwaiters(%rdi), %eax
- andl $~((1 << nwaiters_shift) - 1), %eax
- jne 17f
-
- addq $cond_nwaiters, %rdi
- LP_OP(cmp) $-1, dep_mutex-cond_nwaiters(%rdi)
- movl $1, %edx
-#ifdef __ASSUME_PRIVATE_FUTEX
- movl $FUTEX_WAKE, %eax
- movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
- cmove %eax, %esi
-#else
- movl $0, %eax
- movl %fs:PRIVATE_FUTEX, %esi
- cmove %eax, %esi
- orl $FUTEX_WAKE, %esi
-#endif
- movl $SYS_futex, %eax
- syscall
- subq $cond_nwaiters, %rdi
-
-17: LOCK
-#if cond_lock == 0
- decl (%rdi)
-#else
- decl cond_lock(%rdi)
-#endif
- jne 10f
-
- /* If requeue_pi is used the kernel performs the locking of the
- mutex. */
-11: movq 16(%rsp), %rdi
- testb %r8b, %r8b
- jnz 18f
-
- callq __pthread_mutex_cond_lock
-
-14: leaq FRAME_SIZE(%rsp), %rsp
- cfi_adjust_cfa_offset(-FRAME_SIZE)
-
- /* We return the result of the mutex_lock operation. */
- retq
-
- cfi_adjust_cfa_offset(FRAME_SIZE)
-
-18: callq __pthread_mutex_cond_lock_adjust
- xorl %eax, %eax
- jmp 14b
-
- /* We need to go back to futex_wait. If we're using requeue_pi, then
- release the mutex we had acquired and go back. */
-19: testb %r8b, %r8b
- jz 8b
-
- /* Adjust the mutex values first and then unlock it. The unlock
- should always succeed or else the kernel did not lock the mutex
- correctly. */
- movq 16(%rsp), %rdi
- callq __pthread_mutex_cond_lock_adjust
- movq %rdi, %r8
- xorl %esi, %esi
- callq __pthread_mutex_unlock_usercnt
- /* Reload cond_var. */
- movq 8(%rsp), %rdi
- jmp 8b
-
- /* Initial locking failed. */
-1:
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_lock_wait
- jmp 2b
-
- /* Unlock in loop requires wakeup. */
-3:
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- /* The call preserves %rdx. */
- callq __lll_unlock_wake
-#if cond_lock != 0
- subq $cond_lock, %rdi
-#endif
- jmp 4b
-
- /* Locking in loop failed. */
-5:
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_lock_wait
-#if cond_lock != 0
- subq $cond_lock, %rdi
-#endif
- jmp 6b
-
- /* Unlock after loop requires wakeup. */
-10:
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_unlock_wake
- jmp 11b
-
- /* The initial unlocking of the mutex failed. */
-12: movq %rax, %r10
- movq 8(%rsp), %rdi
- LOCK
-#if cond_lock == 0
- decl (%rdi)
-#else
- decl cond_lock(%rdi)
-#endif
- je 13f
-
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_unlock_wake
-
-13: movq %r10, %rax
- jmp 14b
-
- .size __pthread_cond_wait, .-__pthread_cond_wait
-versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
- GLIBC_2_3_2)
-
-
- .align 16
- .type __condvar_cleanup1, @function
- .globl __condvar_cleanup1
- .hidden __condvar_cleanup1
-__condvar_cleanup1:
- /* Stack frame:
-
- rsp + 32
- +--------------------------+
- rsp + 24 | unused |
- +--------------------------+
- rsp + 16 | mutex pointer |
- +--------------------------+
- rsp + 8 | condvar pointer |
- +--------------------------+
- rsp + 4 | old broadcast_seq value |
- +--------------------------+
- rsp + 0 | old cancellation mode |
- +--------------------------+
- */
-
- movq %rax, 24(%rsp)
-
- /* Get internal lock. */
- movq 8(%rsp), %rdi
- movl $1, %esi
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %esi, (%rdi)
-#else
- cmpxchgl %esi, cond_lock(%rdi)
-#endif
- jz 1f
-
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- callq __lll_lock_wait
-#if cond_lock != 0
- subq $cond_lock, %rdi
-#endif
-
-1: movl broadcast_seq(%rdi), %edx
- cmpl 4(%rsp), %edx
- jne 3f
-
- /* We increment the wakeup_seq counter only if it is lower than
- total_seq. If this is not the case the thread was woken and
- then canceled. In this case we ignore the signal. */
- movq total_seq(%rdi), %rax
- cmpq wakeup_seq(%rdi), %rax
- jbe 6f
- incq wakeup_seq(%rdi)
- incl cond_futex(%rdi)
-6: incq woken_seq(%rdi)
-
-3: subl $(1 << nwaiters_shift), cond_nwaiters(%rdi)
-
- /* Wake up a thread which wants to destroy the condvar object. */
- xorl %ecx, %ecx
- cmpq $0xffffffffffffffff, total_seq(%rdi)
- jne 4f
- movl cond_nwaiters(%rdi), %eax
- andl $~((1 << nwaiters_shift) - 1), %eax
- jne 4f
-
- LP_OP(cmp) $-1, dep_mutex(%rdi)
- leaq cond_nwaiters(%rdi), %rdi
- movl $1, %edx
-#ifdef __ASSUME_PRIVATE_FUTEX
- movl $FUTEX_WAKE, %eax
- movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
- cmove %eax, %esi
-#else
- movl $0, %eax
- movl %fs:PRIVATE_FUTEX, %esi
- cmove %eax, %esi
- orl $FUTEX_WAKE, %esi
-#endif
- movl $SYS_futex, %eax
- syscall
- subq $cond_nwaiters, %rdi
- movl $1, %ecx
-
-4: LOCK
-#if cond_lock == 0
- decl (%rdi)
-#else
- decl cond_lock(%rdi)
-#endif
- je 2f
-#if cond_lock != 0
- addq $cond_lock, %rdi
-#endif
- LP_OP(cmp) $-1, dep_mutex-cond_lock(%rdi)
- movl $LLL_PRIVATE, %eax
- movl $LLL_SHARED, %esi
- cmovne %eax, %esi
- /* The call preserves %rcx. */
- callq __lll_unlock_wake
-
- /* Wake up all waiters to make sure no signal gets lost. */
-2: testl %ecx, %ecx
- jnz 5f
- addq $cond_futex, %rdi
- LP_OP(cmp) $-1, dep_mutex-cond_futex(%rdi)
- movl $0x7fffffff, %edx
-#ifdef __ASSUME_PRIVATE_FUTEX
- movl $FUTEX_WAKE, %eax
- movl $(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi
- cmove %eax, %esi
-#else
- movl $0, %eax
- movl %fs:PRIVATE_FUTEX, %esi
- cmove %eax, %esi
- orl $FUTEX_WAKE, %esi
-#endif
- movl $SYS_futex, %eax
- syscall
-
- /* Lock the mutex only if we don't own it already. This only happens
- in case of PI mutexes, if we got cancelled after a successful
- return of the futex syscall and before disabling async
- cancellation. */
-5: movq 16(%rsp), %rdi
- movl MUTEX_KIND(%rdi), %eax
- andl $(ROBUST_BIT|PI_BIT), %eax
- cmpl $PI_BIT, %eax
- jne 7f
-
- movl (%rdi), %eax
- andl $TID_MASK, %eax
- cmpl %eax, %fs:TID
- jne 7f
- /* We managed to get the lock. Fix it up before returning. */
- callq __pthread_mutex_cond_lock_adjust
- jmp 8f
-
-
-7: callq __pthread_mutex_cond_lock
-
-8: movq 24(%rsp), %rdi
-.LcallUR:
- call _Unwind_Resume@PLT
- hlt
-.LENDCODE:
- cfi_endproc
- .size __condvar_cleanup1, .-__condvar_cleanup1
-
-
- .section .gcc_except_table,"a",@progbits
-.LexceptSTART:
- .byte DW_EH_PE_omit # @LPStart format
- .byte DW_EH_PE_omit # @TType format
- .byte DW_EH_PE_uleb128 # call-site format
- .uleb128 .Lcstend-.Lcstbegin
-.Lcstbegin:
- .uleb128 .LcleanupSTART-.LSTARTCODE
- .uleb128 .LcleanupEND-.LcleanupSTART
- .uleb128 __condvar_cleanup1-.LSTARTCODE
- .uleb128 0
- .uleb128 .LcallUR-.LSTARTCODE
- .uleb128 .LENDCODE-.LcallUR
- .uleb128 0
- .uleb128 0
-.Lcstend:
-
-
-#ifdef SHARED
- .hidden DW.ref.__gcc_personality_v0
- .weak DW.ref.__gcc_personality_v0
- .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
- .align LP_SIZE
- .type DW.ref.__gcc_personality_v0, @object
- .size DW.ref.__gcc_personality_v0, LP_SIZE
-DW.ref.__gcc_personality_v0:
- ASM_ADDR __gcc_personality_v0
-#endif
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=8ff83ccb89e436f2ecc97a2abf2b29e7aa271867
commit 8ff83ccb89e436f2ecc97a2abf2b29e7aa271867
Author: Adhemerval Zanella <adhemerval.zanella@linaro.com>
Date: Mon Oct 5 10:26:54 2015 -0300
nptl: i386: Remove assembly pthread_cond_{timed}wait.S implementation
With i386 support to call six-argument syscall through C code, it can use
the default C NPTL pthread_cond_{timed}wait implementation. This patch
removes the i386 assembly implementation for pthread_cond_timedwait and
pthread_cond_wait for upcoming BZ#12683 fix.
The patch requires that cancellable futex calls to be called through
__syscall_cancel instead. Although it not strictly require, the remove
of the i386 specific implementation follows the rationale:
1. The adjustments required to this fix is extensive (parameters
save, functions calls, etc.) and there is little gain in keep an
alternate implementation for i386 in term of maintanability.
2. There is no pthread_cond benchmark that shows these implementations
are more 'optimized' that what current compilers can produce using
generic C code.
3. The changes required also can change the exact gains this optimized is
intended to provide.
* sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S: Remove
file.
* sysdeps/unix/sysv/linux/i386/pthread_cond_timedwait.S: Likewise.
* sysdeps/unix/sysv/linux/i386/pthread_cond_wait.S: Likewise.
diff --git a/ChangeLog b/ChangeLog
index 00e1cc5..f7734ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -139,9 +139,6 @@
2015-10-09 Adhemerval Zanella <adhemerval.zanella@linaro.org>
- * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
- * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
-
* sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S: Remove
file.
* sysdeps/unix/sysv/linux/i386/pthread_cond_timedwait.S: Likewise.
diff --git a/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S b/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S
deleted file mode 100644
index 763144c..0000000
--- a/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Copyright (C) 2003-2015 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#define HAVE_CMOV 1
-#include "../pthread_cond_timedwait.S"
diff --git a/sysdeps/unix/sysv/linux/i386/pthread_cond_timedwait.S b/sysdeps/unix/sysv/linux/i386/pthread_cond_timedwait.S
deleted file mode 100644
index 130c090..0000000
--- a/sysdeps/unix/sysv/linux/i386/pthread_cond_timedwait.S
+++ /dev/null
@@ -1,973 +0,0 @@
-/* Copyright (C) 2002-2015 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 <sysdep.h>
-#include <shlib-compat.h>
-#include <lowlevellock.h>
-#include <lowlevelcond.h>
-#include <pthread-errnos.h>
-#include <pthread-pi-defines.h>
-#include <kernel-features.h>
-#include <stap-probe.h>
-
- .text
-
-/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
- const struct timespec *abstime) */
- .globl __pthread_cond_timedwait
- .type __pthread_cond_timedwait, @function
- .align 16
-__pthread_cond_timedwait:
-.LSTARTCODE:
- cfi_startproc
-#ifdef SHARED
- cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
- DW.ref.__gcc_personality_v0)
- cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
-#else
- cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
- cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
-#endif
-
- pushl %ebp
- cfi_adjust_cfa_offset(4)
- cfi_rel_offset(%ebp, 0)
- pushl %edi
- cfi_adjust_cfa_offset(4)
- cfi_rel_offset(%edi, 0)
- pushl %esi
- cfi_adjust_cfa_offset(4)
- cfi_rel_offset(%esi, 0)
- pushl %ebx
- cfi_adjust_cfa_offset(4)
- cfi_rel_offset(%ebx, 0)
-
- movl 20(%esp), %ebx
- movl 28(%esp), %ebp
-
- LIBC_PROBE (cond_timedwait, 3, %ebx, 24(%esp), %ebp)
-
- cmpl $1000000000, 4(%ebp)
- movl $EINVAL, %eax
- jae 18f
-
- /* Stack frame:
-
- esp + 32
- +--------------------------+
- esp + 24 | timeout value |
- +--------------------------+
- esp + 20 | futex pointer |
- +--------------------------+
- esp + 16 | pi-requeued flag |
- +--------------------------+
- esp + 12 | old broadcast_seq value |
- +--------------------------+
- esp + 4 | old wake_seq value |
- +--------------------------+
- esp + 0 | old cancellation mode |
- +--------------------------+
- */
-
-#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
-# ifdef PIC
- LOAD_PIC_REG (cx)
- cmpl $0, __have_futex_clock_realtime@GOTOFF(%ecx)
-# else
- cmpl $0, __have_futex_clock_realtime
-# endif
- je .Lreltmo
-#endif
-
- /* Get internal lock. */
- movl $1, %edx
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %edx, (%ebx)
-#else
- cmpxchgl %edx, cond_lock(%ebx)
-#endif
- jnz 1f
-
- /* Store the reference to the mutex. If there is already a
- different value in there this is a bad user bug. */
-2: cmpl $-1, dep_mutex(%ebx)
- movl 24(%esp), %eax
- je 17f
- movl %eax, dep_mutex(%ebx)
-
- /* Unlock the mutex. */
-17: xorl %edx, %edx
- call __pthread_mutex_unlock_usercnt
-
- testl %eax, %eax
- jne 16f
-
- addl $1, total_seq(%ebx)
- adcl $0, total_seq+4(%ebx)
- addl $1, cond_futex(%ebx)
- addl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
-
-#ifdef __ASSUME_FUTEX_CLOCK_REALTIME
-# define FRAME_SIZE 24
-#else
-# define FRAME_SIZE 32
-#endif
- subl $FRAME_SIZE, %esp
- cfi_adjust_cfa_offset(FRAME_SIZE)
- cfi_remember_state
-
- /* Get and store current wakeup_seq value. */
- movl wakeup_seq(%ebx), %edi
- movl wakeup_seq+4(%ebx), %edx
- movl broadcast_seq(%ebx), %eax
- movl %edi, 4(%esp)
- movl %edx, 8(%esp)
- movl %eax, 12(%esp)
-
- /* Reset the pi-requeued flag. */
- movl $0, 16(%esp)
-
- cmpl $0, (%ebp)
- movl $-ETIMEDOUT, %esi
- js 6f
-
-8: movl cond_futex(%ebx), %edi
- movl %edi, 20(%esp)
-
- /* Unlock. */
- LOCK
-#if cond_lock == 0
- subl $1, (%ebx)
-#else
- subl $1, cond_lock(%ebx)
-#endif
- jne 3f
-
-.LcleanupSTART:
-4: call __pthread_enable_asynccancel
- movl %eax, (%esp)
-
- leal (%ebp), %esi
-#if FUTEX_PRIVATE_FLAG > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- sete %cl
- je 40f
-
- movl dep_mutex(%ebx), %edi
- /* Requeue to a non-robust PI mutex if the PI bit is set and
- the robust bit is not set. */
- movl MUTEX_KIND(%edi), %eax
- andl $(ROBUST_BIT|PI_BIT), %eax
- cmpl $PI_BIT, %eax
- jne 40f
-
- movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
- /* The following only works like this because we only support
- two clocks, represented using a single bit. */
- testl $1, cond_nwaiters(%ebx)
- /* XXX Need to implement using sete instead of a jump. */
- jne 42f
- orl $FUTEX_CLOCK_REALTIME, %ecx
-
-42: movl 20(%esp), %edx
- addl $cond_futex, %ebx
-.Ladd_cond_futex_pi:
- movl $SYS_futex, %eax
- ENTER_KERNEL
- subl $cond_futex, %ebx
-.Lsub_cond_futex_pi:
- movl %eax, %esi
- /* Set the pi-requeued flag only if the kernel has returned 0. The
- kernel does not hold the mutex on ETIMEDOUT or any other error. */
- cmpl $0, %eax
- sete 16(%esp)
- je 41f
-
- /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
- successfully, it has already locked the mutex for us and the
- pi_flag (16(%esp)) is set to denote that fact. However, if another
- thread changed the futex value before we entered the wait, the
- syscall may return an EAGAIN and the mutex is not locked. We go
- ahead with a success anyway since later we look at the pi_flag to
- decide if we got the mutex or not. The sequence numbers then make
- sure that only one of the threads actually wake up. We retry using
- normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
- and PI futexes don't mix.
-
- Note that we don't check for EAGAIN specifically; we assume that the
- only other error the futex function could return is EAGAIN (barring
- the ETIMEOUT of course, for the timeout case in futex) since
- anything else would mean an error in our function. It is too
- expensive to do that check for every call (which is quite common in
- case of a large number of threads), so it has been skipped. */
- cmpl $-ENOSYS, %eax
- jne 41f
- xorl %ecx, %ecx
-
-40: subl $1, %ecx
- movl $0, 16(%esp)
-#ifdef __ASSUME_PRIVATE_FUTEX
- andl $FUTEX_PRIVATE_FLAG, %ecx
-#else
- andl %gs:PRIVATE_FUTEX, %ecx
-#endif
- addl $FUTEX_WAIT_BITSET, %ecx
- /* The following only works like this because we only support
- two clocks, represented using a single bit. */
- testl $1, cond_nwaiters(%ebx)
- jne 30f
- orl $FUTEX_CLOCK_REALTIME, %ecx
-30:
- movl 20(%esp), %edx
- movl $0xffffffff, %ebp
- addl $cond_futex, %ebx
-.Ladd_cond_futex:
- movl $SYS_futex, %eax
- ENTER_KERNEL
- subl $cond_futex, %ebx
-.Lsub_cond_futex:
- movl 28+FRAME_SIZE(%esp), %ebp
- movl %eax, %esi
-
-41: movl (%esp), %eax
- call __pthread_disable_asynccancel
-.LcleanupEND:
-
- /* Lock. */
- movl $1, %edx
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %edx, (%ebx)
-#else
- cmpxchgl %edx, cond_lock(%ebx)
-#endif
- jnz 5f
-
-6: movl broadcast_seq(%ebx), %eax
- cmpl 12(%esp), %eax
- jne 23f
-
- movl woken_seq(%ebx), %eax
- movl woken_seq+4(%ebx), %ecx
-
- movl wakeup_seq(%ebx), %edi
- movl wakeup_seq+4(%ebx), %edx
-
- cmpl 8(%esp), %edx
- jne 7f
- cmpl 4(%esp), %edi
- je 15f
-
-7: cmpl %ecx, %edx
- jne 9f
- cmp %eax, %edi
- jne 9f
-
-15: cmpl $-ETIMEDOUT, %esi
- je 28f
-
- /* We need to go back to futex_wait. If we're using requeue_pi, then
- release the mutex we had acquired and go back. */
- movl 16(%esp), %edx
- test %edx, %edx
- jz 8b
-
- /* Adjust the mutex values first and then unlock it. The unlock
- should always succeed or else the kernel did not lock the mutex
- correctly. */
- movl dep_mutex(%ebx), %eax
- call __pthread_mutex_cond_lock_adjust
- xorl %edx, %edx
- call __pthread_mutex_unlock_usercnt
- jmp 8b
-
-28: addl $1, wakeup_seq(%ebx)
- adcl $0, wakeup_seq+4(%ebx)
- addl $1, cond_futex(%ebx)
- movl $ETIMEDOUT, %esi
- jmp 14f
-
-23: xorl %esi, %esi
- jmp 24f
-
-9: xorl %esi, %esi
-14: addl $1, woken_seq(%ebx)
- adcl $0, woken_seq+4(%ebx)
-
-24: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
-
- /* Wake up a thread which wants to destroy the condvar object. */
- movl total_seq(%ebx), %eax
- andl total_seq+4(%ebx), %eax
- cmpl $0xffffffff, %eax
- jne 25f
- movl cond_nwaiters(%ebx), %eax
- andl $~((1 << nwaiters_shift) - 1), %eax
- jne 25f
-
- addl $cond_nwaiters, %ebx
- movl $SYS_futex, %eax
-#if FUTEX_PRIVATE_FLAG > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
- sete %cl
- subl $1, %ecx
-#ifdef __ASSUME_PRIVATE_FUTEX
- andl $FUTEX_PRIVATE_FLAG, %ecx
-#else
- andl %gs:PRIVATE_FUTEX, %ecx
-#endif
- addl $FUTEX_WAKE, %ecx
- movl $1, %edx
- ENTER_KERNEL
- subl $cond_nwaiters, %ebx
-
-25: LOCK
-#if cond_lock == 0
- subl $1, (%ebx)
-#else
- subl $1, cond_lock(%ebx)
-#endif
- jne 10f
-
-11: movl 24+FRAME_SIZE(%esp), %eax
- /* With requeue_pi, the mutex lock is held in the kernel. */
- movl 16(%esp), %ecx
- testl %ecx, %ecx
- jnz 27f
-
- call __pthread_mutex_cond_lock
-26: addl $FRAME_SIZE, %esp
- cfi_adjust_cfa_offset(-FRAME_SIZE)
-
- /* We return the result of the mutex_lock operation if it failed. */
- testl %eax, %eax
-#ifdef HAVE_CMOV
- cmovel %esi, %eax
-#else
- jne 22f
- movl %esi, %eax
-22:
-#endif
-
-18: popl %ebx
- cfi_adjust_cfa_offset(-4)
- cfi_restore(%ebx)
- popl %esi
- cfi_adjust_cfa_offset(-4)
- cfi_restore(%esi)
- popl %edi
- cfi_adjust_cfa_offset(-4)
- cfi_restore(%edi)
- popl %ebp
- cfi_adjust_cfa_offset(-4)
- cfi_restore(%ebp)
-
- ret
-
- cfi_restore_state
-
-27: call __pthread_mutex_cond_lock_adjust
- xorl %eax, %eax
- jmp 26b
-
- cfi_adjust_cfa_offset(-FRAME_SIZE);
- /* Initial locking failed. */
-1:
-#if cond_lock == 0
- movl %ebx, %edx
-#else
- leal cond_lock(%ebx), %edx
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_lock_wait
- jmp 2b
-
- /* The initial unlocking of the mutex failed. */
-16:
- LOCK
-#if cond_lock == 0
- subl $1, (%ebx)
-#else
- subl $1, cond_lock(%ebx)
-#endif
- jne 18b
-
- movl %eax, %esi
-#if cond_lock == 0
- movl %ebx, %eax
-#else
- leal cond_lock(%ebx), %eax
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_unlock_wake
-
- movl %esi, %eax
- jmp 18b
-
- cfi_adjust_cfa_offset(FRAME_SIZE)
-
- /* Unlock in loop requires wakeup. */
-3:
-#if cond_lock == 0
- movl %ebx, %eax
-#else
- leal cond_lock(%ebx), %eax
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_unlock_wake
- jmp 4b
-
- /* Locking in loop failed. */
-5:
-#if cond_lock == 0
- movl %ebx, %edx
-#else
- leal cond_lock(%ebx), %edx
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_lock_wait
- jmp 6b
-
- /* Unlock after loop requires wakeup. */
-10:
-#if cond_lock == 0
- movl %ebx, %eax
-#else
- leal cond_lock(%ebx), %eax
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_unlock_wake
- jmp 11b
-
-#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
- cfi_adjust_cfa_offset(-FRAME_SIZE)
-.Lreltmo:
- /* Get internal lock. */
- movl $1, %edx
- xorl %eax, %eax
- LOCK
-# if cond_lock == 0
- cmpxchgl %edx, (%ebx)
-# else
- cmpxchgl %edx, cond_lock(%ebx)
-# endif
- jnz 101f
-
- /* Store the reference to the mutex. If there is already a
- different value in there this is a bad user bug. */
-102: cmpl $-1, dep_mutex(%ebx)
- movl 24(%esp), %eax
- je 117f
- movl %eax, dep_mutex(%ebx)
-
- /* Unlock the mutex. */
-117: xorl %edx, %edx
- call __pthread_mutex_unlock_usercnt
-
- testl %eax, %eax
- jne 16b
-
- addl $1, total_seq(%ebx)
- adcl $0, total_seq+4(%ebx)
- addl $1, cond_futex(%ebx)
- addl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
-
- subl $FRAME_SIZE, %esp
- cfi_adjust_cfa_offset(FRAME_SIZE)
-
- /* Get and store current wakeup_seq value. */
- movl wakeup_seq(%ebx), %edi
- movl wakeup_seq+4(%ebx), %edx
- movl broadcast_seq(%ebx), %eax
- movl %edi, 4(%esp)
- movl %edx, 8(%esp)
- movl %eax, 12(%esp)
-
- /* Reset the pi-requeued flag. */
- movl $0, 16(%esp)
-
- /* Get the current time. */
-108: movl %ebx, %edx
-# ifdef __NR_clock_gettime
- /* Get the clock number. */
- movl cond_nwaiters(%ebx), %ebx
- andl $((1 << nwaiters_shift) - 1), %ebx
- /* Only clocks 0 and 1 are allowed so far. Both are handled in the
- kernel. */
- leal 24(%esp), %ecx
- movl $__NR_clock_gettime, %eax
- ENTER_KERNEL
- movl %edx, %ebx
-
- /* Compute relative timeout. */
- movl (%ebp), %ecx
- movl 4(%ebp), %edx
- subl 24(%esp), %ecx
- subl 28(%esp), %edx
-# else
- /* Get the current time. */
- leal 24(%esp), %ebx
- xorl %ecx, %ecx
- movl $__NR_gettimeofday, %eax
- ENTER_KERNEL
- movl %edx, %ebx
-
- /* Compute relative timeout. */
- movl 28(%esp), %eax
- movl $1000, %edx
- mul %edx /* Milli seconds to nano seconds. */
- movl (%ebp), %ecx
- movl 4(%ebp), %edx
- subl 24(%esp), %ecx
- subl %eax, %edx
-# endif
- jns 112f
- addl $1000000000, %edx
- subl $1, %ecx
-112: testl %ecx, %ecx
- movl $-ETIMEDOUT, %esi
- js 106f
-
- /* Store relative timeout. */
-121: movl %ecx, 24(%esp)
- movl %edx, 28(%esp)
-
- movl cond_futex(%ebx), %edi
- movl %edi, 20(%esp)
-
- /* Unlock. */
- LOCK
-# if cond_lock == 0
- subl $1, (%ebx)
-# else
- subl $1, cond_lock(%ebx)
-# endif
- jne 103f
-
-.LcleanupSTART2:
-104: call __pthread_enable_asynccancel
- movl %eax, (%esp)
-
- leal 24(%esp), %esi
-# if FUTEX_PRIVATE_FLAG > 255
- xorl %ecx, %ecx
-# endif
- cmpl $-1, dep_mutex(%ebx)
- sete %cl
- subl $1, %ecx
-# ifdef __ASSUME_PRIVATE_FUTEX
- andl $FUTEX_PRIVATE_FLAG, %ecx
-# else
- andl %gs:PRIVATE_FUTEX, %ecx
-# endif
-# if FUTEX_WAIT != 0
- addl $FUTEX_WAIT, %ecx
-# endif
- movl 20(%esp), %edx
- addl $cond_futex, %ebx
-.Ladd_cond_futex2:
- movl $SYS_futex, %eax
- ENTER_KERNEL
- subl $cond_futex, %ebx
-.Lsub_cond_futex2:
- movl %eax, %esi
-
-141: movl (%esp), %eax
- call __pthread_disable_asynccancel
-.LcleanupEND2:
-
-
- /* Lock. */
- movl $1, %edx
- xorl %eax, %eax
- LOCK
-# if cond_lock == 0
- cmpxchgl %edx, (%ebx)
-# else
- cmpxchgl %edx, cond_lock(%ebx)
-# endif
- jnz 105f
-
-106: movl broadcast_seq(%ebx), %eax
- cmpl 12(%esp), %eax
- jne 23b
-
- movl woken_seq(%ebx), %eax
- movl woken_seq+4(%ebx), %ecx
-
- movl wakeup_seq(%ebx), %edi
- movl wakeup_seq+4(%ebx), %edx
-
- cmpl 8(%esp), %edx
- jne 107f
- cmpl 4(%esp), %edi
- je 115f
-
-107: cmpl %ecx, %edx
- jne 9b
- cmp %eax, %edi
- jne 9b
-
-115: cmpl $-ETIMEDOUT, %esi
- je 28b
-
- jmp 8b
-
- cfi_adjust_cfa_offset(-FRAME_SIZE)
- /* Initial locking failed. */
-101:
-# if cond_lock == 0
- movl %ebx, %edx
-# else
- leal cond_lock(%ebx), %edx
-# endif
-# if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-# endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-# if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-# endif
- call __lll_lock_wait
- jmp 102b
-
- cfi_adjust_cfa_offset(FRAME_SIZE)
-
- /* Unlock in loop requires wakeup. */
-103:
-# if cond_lock == 0
- movl %ebx, %eax
-# else
- leal cond_lock(%ebx), %eax
-# endif
-# if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-# endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-# if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-# endif
- call __lll_unlock_wake
- jmp 104b
-
- /* Locking in loop failed. */
-105:
-# if cond_lock == 0
- movl %ebx, %edx
-# else
- leal cond_lock(%ebx), %edx
-# endif
-# if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-# endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-# if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-# endif
- call __lll_lock_wait
- jmp 106b
-#endif
-
- .size __pthread_cond_timedwait, .-__pthread_cond_timedwait
-versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
- GLIBC_2_3_2)
-
-
- .type __condvar_tw_cleanup2, @function
-__condvar_tw_cleanup2:
- subl $cond_futex, %ebx
- .size __condvar_tw_cleanup2, .-__condvar_tw_cleanup2
- .type __condvar_tw_cleanup, @function
-__condvar_tw_cleanup:
- movl %eax, %esi
-
- /* Get internal lock. */
- movl $1, %edx
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %edx, (%ebx)
-#else
- cmpxchgl %edx, cond_lock(%ebx)
-#endif
- jz 1f
-
-#if cond_lock == 0
- movl %ebx, %edx
-#else
- leal cond_lock(%ebx), %edx
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_lock_wait
-
-1: movl broadcast_seq(%ebx), %eax
- cmpl 12(%esp), %eax
- jne 3f
-
- /* We increment the wakeup_seq counter only if it is lower than
- total_seq. If this is not the case the thread was woken and
- then canceled. In this case we ignore the signal. */
- movl total_seq(%ebx), %eax
- movl total_seq+4(%ebx), %edi
- cmpl wakeup_seq+4(%ebx), %edi
- jb 6f
- ja 7f
- cmpl wakeup_seq(%ebx), %eax
- jbe 7f
-
-6: addl $1, wakeup_seq(%ebx)
- adcl $0, wakeup_seq+4(%ebx)
- addl $1, cond_futex(%ebx)
-
-7: addl $1, woken_seq(%ebx)
- adcl $0, woken_seq+4(%ebx)
-
-3: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
-
- /* Wake up a thread which wants to destroy the condvar object. */
- xorl %edi, %edi
- movl total_seq(%ebx), %eax
- andl total_seq+4(%ebx), %eax
- cmpl $0xffffffff, %eax
- jne 4f
- movl cond_nwaiters(%ebx), %eax
- andl $~((1 << nwaiters_shift) - 1), %eax
- jne 4f
-
- addl $cond_nwaiters, %ebx
- movl $SYS_futex, %eax
-#if FUTEX_PRIVATE_FLAG > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
- sete %cl
- subl $1, %ecx
-#ifdef __ASSUME_PRIVATE_FUTEX
- andl $FUTEX_PRIVATE_FLAG, %ecx
-#else
- andl %gs:PRIVATE_FUTEX, %ecx
-#endif
- addl $FUTEX_WAKE, %ecx
- movl $1, %edx
- ENTER_KERNEL
- subl $cond_nwaiters, %ebx
- movl $1, %edi
-
-4: LOCK
-#if cond_lock == 0
- subl $1, (%ebx)
-#else
- subl $1, cond_lock(%ebx)
-#endif
- je 2f
-
-#if cond_lock == 0
- movl %ebx, %eax
-#else
- leal cond_lock(%ebx), %eax
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_unlock_wake
-
- /* Wake up all waiters to make sure no signal gets lost. */
-2: testl %edi, %edi
- jnz 5f
- addl $cond_futex, %ebx
-#if FUTEX_PRIVATE_FLAG > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex-cond_futex(%ebx)
- sete %cl
- subl $1, %ecx
-#ifdef __ASSUME_PRIVATE_FUTEX
- andl $FUTEX_PRIVATE_FLAG, %ecx
-#else
- andl %gs:PRIVATE_FUTEX, %ecx
-#endif
- addl $FUTEX_WAKE, %ecx
- movl $SYS_futex, %eax
- movl $0x7fffffff, %edx
- ENTER_KERNEL
-
- /* Lock the mutex only if we don't own it already. This only happens
- in case of PI mutexes, if we got cancelled after a successful
- return of the futex syscall and before disabling async
- cancellation. */
-5: movl 24+FRAME_SIZE(%esp), %eax
- movl MUTEX_KIND(%eax), %ebx
- andl $(ROBUST_BIT|PI_BIT), %ebx
- cmpl $PI_BIT, %ebx
- jne 8f
-
- movl (%eax), %ebx
- andl $TID_MASK, %ebx
- cmpl %ebx, %gs:TID
- jne 8f
- /* We managed to get the lock. Fix it up before returning. */
- call __pthread_mutex_cond_lock_adjust
- jmp 9f
-
-8: call __pthread_mutex_cond_lock
-
-9: movl %esi, (%esp)
-.LcallUR:
- call _Unwind_Resume
- hlt
-.LENDCODE:
- cfi_endproc
- .size __condvar_tw_cleanup, .-__condvar_tw_cleanup
-
-
- .section .gcc_except_table,"a",@progbits
-.LexceptSTART:
- .byte DW_EH_PE_omit # @LPStart format (omit)
- .byte DW_EH_PE_omit # @TType format (omit)
- .byte DW_EH_PE_sdata4 # call-site format
- # DW_EH_PE_sdata4
- .uleb128 .Lcstend-.Lcstbegin
-.Lcstbegin:
- .long .LcleanupSTART-.LSTARTCODE
- .long .Ladd_cond_futex_pi-.LcleanupSTART
- .long __condvar_tw_cleanup-.LSTARTCODE
- .uleb128 0
- .long .Ladd_cond_futex_pi-.LSTARTCODE
- .long .Lsub_cond_futex_pi-.Ladd_cond_futex_pi
- .long __condvar_tw_cleanup2-.LSTARTCODE
- .uleb128 0
- .long .Lsub_cond_futex_pi-.LSTARTCODE
- .long .Ladd_cond_futex-.Lsub_cond_futex_pi
- .long __condvar_tw_cleanup-.LSTARTCODE
- .uleb128 0
- .long .Ladd_cond_futex-.LSTARTCODE
- .long .Lsub_cond_futex-.Ladd_cond_futex
- .long __condvar_tw_cleanup2-.LSTARTCODE
- .uleb128 0
- .long .Lsub_cond_futex-.LSTARTCODE
- .long .LcleanupEND-.Lsub_cond_futex
- .long __condvar_tw_cleanup-.LSTARTCODE
- .uleb128 0
-#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
- .long .LcleanupSTART2-.LSTARTCODE
- .long .Ladd_cond_futex2-.LcleanupSTART2
- .long __condvar_tw_cleanup-.LSTARTCODE
- .uleb128 0
- .long .Ladd_cond_futex2-.LSTARTCODE
- .long .Lsub_cond_futex2-.Ladd_cond_futex2
- .long __condvar_tw_cleanup2-.LSTARTCODE
- .uleb128 0
- .long .Lsub_cond_futex2-.LSTARTCODE
- .long .LcleanupEND2-.Lsub_cond_futex2
- .long __condvar_tw_cleanup-.LSTARTCODE
- .uleb128 0
-#endif
- .long .LcallUR-.LSTARTCODE
- .long .LENDCODE-.LcallUR
- .long 0
- .uleb128 0
-.Lcstend:
-
-
-#ifdef SHARED
- .hidden DW.ref.__gcc_personality_v0
- .weak DW.ref.__gcc_personality_v0
- .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
- .align 4
- .type DW.ref.__gcc_personality_v0, @object
- .size DW.ref.__gcc_personality_v0, 4
-DW.ref.__gcc_personality_v0:
- .long __gcc_personality_v0
-#endif
diff --git a/sysdeps/unix/sysv/linux/i386/pthread_cond_wait.S b/sysdeps/unix/sysv/linux/i386/pthread_cond_wait.S
deleted file mode 100644
index ec3538f..0000000
--- a/sysdeps/unix/sysv/linux/i386/pthread_cond_wait.S
+++ /dev/null
@@ -1,641 +0,0 @@
-/* Copyright (C) 2002-2015 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 <sysdep.h>
-#include <shlib-compat.h>
-#include <lowlevellock.h>
-#include <lowlevelcond.h>
-#include <tcb-offsets.h>
-#include <pthread-errnos.h>
-#include <pthread-pi-defines.h>
-#include <kernel-features.h>
-#include <stap-probe.h>
-
-
- .text
-
-/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */
- .globl __pthread_cond_wait
- .type __pthread_cond_wait, @function
- .align 16
-__pthread_cond_wait:
-.LSTARTCODE:
- cfi_startproc
-#ifdef SHARED
- cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect,
- DW.ref.__gcc_personality_v0)
- cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART)
-#else
- cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0)
- cfi_lsda(DW_EH_PE_udata4, .LexceptSTART)
-#endif
-
- pushl %ebp
- cfi_adjust_cfa_offset(4)
- cfi_rel_offset(%ebp, 0)
- pushl %edi
- cfi_adjust_cfa_offset(4)
- cfi_rel_offset(%edi, 0)
- pushl %esi
- cfi_adjust_cfa_offset(4)
- cfi_rel_offset(%esi, 0)
- pushl %ebx
- cfi_adjust_cfa_offset(4)
- cfi_rel_offset(%ebx, 0)
-
- xorl %esi, %esi
- movl 20(%esp), %ebx
-
- LIBC_PROBE (cond_wait, 2, 24(%esp), %ebx)
-
- /* Get internal lock. */
- movl $1, %edx
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %edx, (%ebx)
-#else
- cmpxchgl %edx, cond_lock(%ebx)
-#endif
- jnz 1f
-
- /* Store the reference to the mutex. If there is already a
- different value in there this is a bad user bug. */
-2: cmpl $-1, dep_mutex(%ebx)
- movl 24(%esp), %eax
- je 15f
- movl %eax, dep_mutex(%ebx)
-
- /* Unlock the mutex. */
-15: xorl %edx, %edx
- call __pthread_mutex_unlock_usercnt
-
- testl %eax, %eax
- jne 12f
-
- addl $1, total_seq(%ebx)
- adcl $0, total_seq+4(%ebx)
- addl $1, cond_futex(%ebx)
- addl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
-
-#define FRAME_SIZE 20
- subl $FRAME_SIZE, %esp
- cfi_adjust_cfa_offset(FRAME_SIZE)
- cfi_remember_state
-
- /* Get and store current wakeup_seq value. */
- movl wakeup_seq(%ebx), %edi
- movl wakeup_seq+4(%ebx), %edx
- movl broadcast_seq(%ebx), %eax
- movl %edi, 4(%esp)
- movl %edx, 8(%esp)
- movl %eax, 12(%esp)
-
- /* Reset the pi-requeued flag. */
-8: movl $0, 16(%esp)
- movl cond_futex(%ebx), %ebp
-
- /* Unlock. */
- LOCK
-#if cond_lock == 0
- subl $1, (%ebx)
-#else
- subl $1, cond_lock(%ebx)
-#endif
- jne 3f
-
-.LcleanupSTART:
-4: call __pthread_enable_asynccancel
- movl %eax, (%esp)
-
- xorl %ecx, %ecx
- cmpl $-1, dep_mutex(%ebx)
- sete %cl
- je 18f
-
- movl dep_mutex(%ebx), %edi
- /* Requeue to a non-robust PI mutex if the PI bit is set and
- the robust bit is not set. */
- movl MUTEX_KIND(%edi), %eax
- andl $(ROBUST_BIT|PI_BIT), %eax
- cmpl $PI_BIT, %eax
- jne 18f
-
- movl $(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx
- movl %ebp, %edx
- xorl %esi, %esi
- addl $cond_futex, %ebx
-.Ladd_cond_futex_pi:
- movl $SYS_futex, %eax
- ENTER_KERNEL
- subl $cond_futex, %ebx
-.Lsub_cond_futex_pi:
- /* Set the pi-requeued flag only if the kernel has returned 0. The
- kernel does not hold the mutex on error. */
- cmpl $0, %eax
- sete 16(%esp)
- je 19f
-
- /* When a futex syscall with FUTEX_WAIT_REQUEUE_PI returns
- successfully, it has already locked the mutex for us and the
- pi_flag (16(%esp)) is set to denote that fact. However, if another
- thread changed the futex value before we entered the wait, the
- syscall may return an EAGAIN and the mutex is not locked. We go
- ahead with a success anyway since later we look at the pi_flag to
- decide if we got the mutex or not. The sequence numbers then make
- sure that only one of the threads actually wake up. We retry using
- normal FUTEX_WAIT only if the kernel returned ENOSYS, since normal
- and PI futexes don't mix.
-
- Note that we don't check for EAGAIN specifically; we assume that the
- only other error the futex function could return is EAGAIN since
- anything else would mean an error in our function. It is too
- expensive to do that check for every call (which is quite common in
- case of a large number of threads), so it has been skipped. */
- cmpl $-ENOSYS, %eax
- jne 19f
- xorl %ecx, %ecx
-
-18: subl $1, %ecx
-#ifdef __ASSUME_PRIVATE_FUTEX
- andl $FUTEX_PRIVATE_FLAG, %ecx
-#else
- andl %gs:PRIVATE_FUTEX, %ecx
-#endif
-#if FUTEX_WAIT != 0
- addl $FUTEX_WAIT, %ecx
-#endif
- movl %ebp, %edx
- addl $cond_futex, %ebx
-.Ladd_cond_futex:
- movl $SYS_futex, %eax
- ENTER_KERNEL
- subl $cond_futex, %ebx
-.Lsub_cond_futex:
-
-19: movl (%esp), %eax
- call __pthread_disable_asynccancel
-.LcleanupEND:
-
- /* Lock. */
- movl $1, %edx
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %edx, (%ebx)
-#else
- cmpxchgl %edx, cond_lock(%ebx)
-#endif
- jnz 5f
-
-6: movl broadcast_seq(%ebx), %eax
- cmpl 12(%esp), %eax
- jne 16f
-
- movl woken_seq(%ebx), %eax
- movl woken_seq+4(%ebx), %ecx
-
- movl wakeup_seq(%ebx), %edi
- movl wakeup_seq+4(%ebx), %edx
-
- cmpl 8(%esp), %edx
- jne 7f
- cmpl 4(%esp), %edi
- je 22f
-
-7: cmpl %ecx, %edx
- jne 9f
- cmp %eax, %edi
- je 22f
-
-9: addl $1, woken_seq(%ebx)
- adcl $0, woken_seq+4(%ebx)
-
- /* Unlock */
-16: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
-
- /* Wake up a thread which wants to destroy the condvar object. */
- movl total_seq(%ebx), %eax
- andl total_seq+4(%ebx), %eax
- cmpl $0xffffffff, %eax
- jne 17f
- movl cond_nwaiters(%ebx), %eax
- andl $~((1 << nwaiters_shift) - 1), %eax
- jne 17f
-
- addl $cond_nwaiters, %ebx
- movl $SYS_futex, %eax
-#if FUTEX_PRIVATE_FLAG > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
- sete %cl
- subl $1, %ecx
-#ifdef __ASSUME_PRIVATE_FUTEX
- andl $FUTEX_PRIVATE_FLAG, %ecx
-#else
- andl %gs:PRIVATE_FUTEX, %ecx
-#endif
- addl $FUTEX_WAKE, %ecx
- movl $1, %edx
- ENTER_KERNEL
- subl $cond_nwaiters, %ebx
-
-17: LOCK
-#if cond_lock == 0
- subl $1, (%ebx)
-#else
- subl $1, cond_lock(%ebx)
-#endif
- jne 10f
-
- /* With requeue_pi, the mutex lock is held in the kernel. */
-11: movl 24+FRAME_SIZE(%esp), %eax
- movl 16(%esp), %ecx
- testl %ecx, %ecx
- jnz 21f
-
- call __pthread_mutex_cond_lock
-20: addl $FRAME_SIZE, %esp
- cfi_adjust_cfa_offset(-FRAME_SIZE);
-
-14: popl %ebx
- cfi_adjust_cfa_offset(-4)
- cfi_restore(%ebx)
- popl %esi
- cfi_adjust_cfa_offset(-4)
- cfi_restore(%esi)
- popl %edi
- cfi_adjust_cfa_offset(-4)
- cfi_restore(%edi)
- popl %ebp
- cfi_adjust_cfa_offset(-4)
- cfi_restore(%ebp)
-
- /* We return the result of the mutex_lock operation. */
- ret
-
- cfi_restore_state
-
-21: call __pthread_mutex_cond_lock_adjust
- xorl %eax, %eax
- jmp 20b
-
- cfi_adjust_cfa_offset(-FRAME_SIZE);
-
- /* We need to go back to futex_wait. If we're using requeue_pi, then
- release the mutex we had acquired and go back. */
-22: movl 16(%esp), %edx
- test %edx, %edx
- jz 8b
-
- /* Adjust the mutex values first and then unlock it. The unlock
- should always succeed or else the kernel did not lock the mutex
- correctly. */
- movl dep_mutex(%ebx), %eax
- call __pthread_mutex_cond_lock_adjust
- xorl %edx, %edx
- call __pthread_mutex_unlock_usercnt
- jmp 8b
-
- /* Initial locking failed. */
-1:
-#if cond_lock == 0
- movl %ebx, %edx
-#else
- leal cond_lock(%ebx), %edx
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_lock_wait
- jmp 2b
-
- /* The initial unlocking of the mutex failed. */
-12:
- LOCK
-#if cond_lock == 0
- subl $1, (%ebx)
-#else
- subl $1, cond_lock(%ebx)
-#endif
- jne 14b
-
- movl %eax, %esi
-#if cond_lock == 0
- movl %ebx, %eax
-#else
- leal cond_lock(%ebx), %eax
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_unlock_wake
-
- movl %esi, %eax
- jmp 14b
-
- cfi_adjust_cfa_offset(FRAME_SIZE)
-
- /* Unlock in loop requires wakeup. */
-3:
-#if cond_lock == 0
- movl %ebx, %eax
-#else
- leal cond_lock(%ebx), %eax
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_unlock_wake
- jmp 4b
-
- /* Locking in loop failed. */
-5:
-#if cond_lock == 0
- movl %ebx, %edx
-#else
- leal cond_lock(%ebx), %edx
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_lock_wait
- jmp 6b
-
- /* Unlock after loop requires wakeup. */
-10:
-#if cond_lock == 0
- movl %ebx, %eax
-#else
- leal cond_lock(%ebx), %eax
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_unlock_wake
- jmp 11b
-
- .size __pthread_cond_wait, .-__pthread_cond_wait
-versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
- GLIBC_2_3_2)
-
-
- .type __condvar_w_cleanup2, @function
-__condvar_w_cleanup2:
- subl $cond_futex, %ebx
- .size __condvar_w_cleanup2, .-__condvar_w_cleanup2
-.LSbl4:
- .type __condvar_w_cleanup, @function
-__condvar_w_cleanup:
- movl %eax, %esi
-
- /* Get internal lock. */
- movl $1, %edx
- xorl %eax, %eax
- LOCK
-#if cond_lock == 0
- cmpxchgl %edx, (%ebx)
-#else
- cmpxchgl %edx, cond_lock(%ebx)
-#endif
- jz 1f
-
-#if cond_lock == 0
- movl %ebx, %edx
-#else
- leal cond_lock(%ebx), %edx
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_lock_wait
-
-1: movl broadcast_seq(%ebx), %eax
- cmpl 12(%esp), %eax
- jne 3f
-
- /* We increment the wakeup_seq counter only if it is lower than
- total_seq. If this is not the case the thread was woken and
- then canceled. In this case we ignore the signal. */
- movl total_seq(%ebx), %eax
- movl total_seq+4(%ebx), %edi
- cmpl wakeup_seq+4(%ebx), %edi
- jb 6f
- ja 7f
- cmpl wakeup_seq(%ebx), %eax
- jbe 7f
-
-6: addl $1, wakeup_seq(%ebx)
- adcl $0, wakeup_seq+4(%ebx)
- addl $1, cond_futex(%ebx)
-
-7: addl $1, woken_seq(%ebx)
- adcl $0, woken_seq+4(%ebx)
-
-3: subl $(1 << nwaiters_shift), cond_nwaiters(%ebx)
-
- /* Wake up a thread which wants to destroy the condvar object. */
- xorl %edi, %edi
- movl total_seq(%ebx), %eax
- andl total_seq+4(%ebx), %eax
- cmpl $0xffffffff, %eax
- jne 4f
- movl cond_nwaiters(%ebx), %eax
- andl $~((1 << nwaiters_shift) - 1), %eax
- jne 4f
-
- addl $cond_nwaiters, %ebx
- movl $SYS_futex, %eax
-#if FUTEX_PRIVATE_FLAG > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex-cond_nwaiters(%ebx)
- sete %cl
- subl $1, %ecx
-#ifdef __ASSUME_PRIVATE_FUTEX
- andl $FUTEX_PRIVATE_FLAG, %ecx
-#else
- andl %gs:PRIVATE_FUTEX, %ecx
-#endif
- addl $FUTEX_WAKE, %ecx
- movl $1, %edx
- ENTER_KERNEL
- subl $cond_nwaiters, %ebx
- movl $1, %edi
-
-4: LOCK
-#if cond_lock == 0
- subl $1, (%ebx)
-#else
- subl $1, cond_lock(%ebx)
-#endif
- je 2f
-
-#if cond_lock == 0
- movl %ebx, %eax
-#else
- leal cond_lock(%ebx), %eax
-#endif
-#if (LLL_SHARED-LLL_PRIVATE) > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex(%ebx)
- setne %cl
- subl $1, %ecx
- andl $(LLL_SHARED-LLL_PRIVATE), %ecx
-#if LLL_PRIVATE != 0
- addl $LLL_PRIVATE, %ecx
-#endif
- call __lll_unlock_wake
-
- /* Wake up all waiters to make sure no signal gets lost. */
-2: testl %edi, %edi
- jnz 5f
- addl $cond_futex, %ebx
-#if FUTEX_PRIVATE_FLAG > 255
- xorl %ecx, %ecx
-#endif
- cmpl $-1, dep_mutex-cond_futex(%ebx)
- sete %cl
- subl $1, %ecx
-#ifdef __ASSUME_PRIVATE_FUTEX
- andl $FUTEX_PRIVATE_FLAG, %ecx
-#else
- andl %gs:PRIVATE_FUTEX, %ecx
-#endif
- addl $FUTEX_WAKE, %ecx
- movl $SYS_futex, %eax
- movl $0x7fffffff, %edx
- ENTER_KERNEL
-
- /* Lock the mutex only if we don't own it already. This only happens
- in case of PI mutexes, if we got cancelled after a successful
- return of the futex syscall and before disabling async
- cancellation. */
-5: movl 24+FRAME_SIZE(%esp), %eax
- movl MUTEX_KIND(%eax), %ebx
- andl $(ROBUST_BIT|PI_BIT), %ebx
- cmpl $PI_BIT, %ebx
- jne 8f
-
- movl (%eax), %ebx
- andl $TID_MASK, %ebx
- cmpl %ebx, %gs:TID
- jne 8f
- /* We managed to get the lock. Fix it up before returning. */
- call __pthread_mutex_cond_lock_adjust
- jmp 9f
-
-8: call __pthread_mutex_cond_lock
-
-9: movl %esi, (%esp)
-.LcallUR:
- call _Unwind_Resume
- hlt
-.LENDCODE:
- cfi_endproc
- .size __condvar_w_cleanup, .-__condvar_w_cleanup
-
-
- .section .gcc_except_table,"a",@progbits
-.LexceptSTART:
- .byte DW_EH_PE_omit # @LPStart format (omit)
- .byte DW_EH_PE_omit # @TType format (omit)
- .byte DW_EH_PE_sdata4 # call-site format
- # DW_EH_PE_sdata4
- .uleb128 .Lcstend-.Lcstbegin
-.Lcstbegin:
- .long .LcleanupSTART-.LSTARTCODE
- .long .Ladd_cond_futex_pi-.LcleanupSTART
- .long __condvar_w_cleanup-.LSTARTCODE
- .uleb128 0
- .long .Ladd_cond_futex_pi-.LSTARTCODE
- .long .Lsub_cond_futex_pi-.Ladd_cond_futex_pi
- .long __condvar_w_cleanup2-.LSTARTCODE
- .uleb128 0
- .long .Lsub_cond_futex_pi-.LSTARTCODE
- .long .Ladd_cond_futex-.Lsub_cond_futex_pi
- .long __condvar_w_cleanup-.LSTARTCODE
- .uleb128 0
- .long .Ladd_cond_futex-.LSTARTCODE
- .long .Lsub_cond_futex-.Ladd_cond_futex
- .long __condvar_w_cleanup2-.LSTARTCODE
- .uleb128 0
- .long .Lsub_cond_futex-.LSTARTCODE
- .long .LcleanupEND-.Lsub_cond_futex
- .long __condvar_w_cleanup-.LSTARTCODE
- .uleb128 0
- .long .LcallUR-.LSTARTCODE
- .long .LENDCODE-.LcallUR
- .long 0
- .uleb128 0
-.Lcstend:
-
-#ifdef SHARED
- .hidden DW.ref.__gcc_personality_v0
- .weak DW.ref.__gcc_personality_v0
- .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
- .align 4
- .type DW.ref.__gcc_personality_v0, @object
- .size DW.ref.__gcc_personality_v0, 4
-DW.ref.__gcc_personality_v0:
- .long __gcc_personality_v0
-#endif
-----------------------------------------------------------------------
hooks/post-receive
--
GNU C Library master sources
More information about the Glibc-cvs
mailing list