@@ -383,17 +383,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 (); })
-
-
/* Set the stack guard field in TCB head. */
#define THREAD_SET_STACK_GUARD(value) \
THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
@@ -6,7 +6,7 @@ sysdep_routines += ioperm iopl vm86
endif
ifeq ($(subdir),elf)
-sysdep-dl-routines += libc-do-syscall
+sysdep-rtld_routines += libc-do-syscall
sysdep-others += lddlibc4
install-bin += lddlibc4
endif
@@ -223,7 +223,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)
@@ -16,6 +16,11 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#ifndef _SIGCONTEXTINFO_H
+#define _SIGCONTEXTINFO_H
+
+#include <stdint.h>
+
#define SIGCONTEXT struct sigcontext
#define SIGCONTEXT_EXTRA_ARGS
#define GET_PC(ctx) ((void *) ctx.eip)
@@ -48,3 +53,11 @@ do { \
"i" (sizeof (struct sigcontext) / 4) \
: "cc", "edi"); \
} while (0)
+
+static inline uintptr_t
+ucontext_get_pc (const ucontext_t *uc)
+{
+ return uc->uc_mcontext.gregs[REG_EIP];
+}
+
+#endif /* _SIGCONTEXTINFO_H */
new file mode 100644
@@ -0,0 +1,107 @@
+/* Cancellable syscall wrapper. Linux/i686 version.
+ Copyright (C) 2017 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)
+
+ .global __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
+
+ /* We can not use the vDSO helper for syscall (__kernel_vsyscall)
+ because the returned PC from kernel will indicate whether the
+ interrupted syscall have any side-effects that need to be reported
+ back to program. And the signal handler (sigcancel_handler at
+ nptl-init.c) checks the PC agains the __syscall_cancel_arch_*
+ marks. */
+ int $128
+
+ .global __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 for unwind. */
+ 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)
This patch adds the i386 modifications required for the BZ#12683. It basically provides the required ucontext_get_pc symbol, add the cancelable syscall wrapper and fix a thread atomic update macro. On i386 an arch-specific cancellation implementation is required because depending of the glibc configuration and underlying kernel the syscall may be done using a vDSO symbol (__kernel_vsyscall). By using the vDSO symbol the resulting PC value for an interrupted syscall points to an adress outside the expected markers in __syscall_cancel_arch. It has been discussed in LKML [1] on how kernel could help userland to accomplish it, but afaik discussion was stalled. Also, since glibc supports i486, the old 'int 0x80' should be used in the syscall wrapper. One option could make minimum default chip to pentium II (which implements sysenter) or add a runtime check on syscall_cancel.S to use 'int 0x80' or sysenter. Similar to x86_64, it also remove bogus arch-specific THREAD_ATOMIC_BIT_SET where it always reference to current thread instead of the one referenced by input 'descr' argument. Checked on i686-linux-gnu. * sysdeps/i386/nptl/tls.h (THREAD_ATOMIC_CMPXCHG_VAL, 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/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/sigcontextinfo.h (ucontext_get_pc): New function. [1] https://lkml.org/lkml/2016/3/8/1105 Signed-off-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> --- ChangeLog | 9 +++ sysdeps/i386/nptl/tls.h | 11 --- sysdeps/unix/sysv/linux/i386/Makefile | 2 +- sysdeps/unix/sysv/linux/i386/lowlevellock.h | 2 +- sysdeps/unix/sysv/linux/i386/sigcontextinfo.h | 13 ++++ sysdeps/unix/sysv/linux/i386/syscall_cancel.S | 107 ++++++++++++++++++++++++++ 6 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/i386/syscall_cancel.S -- 2.7.4