about summary refs log tree commit diff
path: root/sysdeps/unix/sysv/linux/syscall_cancel.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux/syscall_cancel.c')
-rw-r--r--sysdeps/unix/sysv/linux/syscall_cancel.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/syscall_cancel.c b/sysdeps/unix/sysv/linux/syscall_cancel.c
new file mode 100644
index 0000000000..5fa0706486
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/syscall_cancel.c
@@ -0,0 +1,73 @@
+/* Pthread cancellation syscall bridge.  Default Linux version.
+   Copyright (C) 2023 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>
+#include <pthreadP.h>
+
+#warning "This implementation should be use just as reference or for bootstrapping"
+
+/* This is the generic version of the cancellable syscall code which
+   adds the label guards (__syscall_cancel_arch_{start,end}) used on SIGCANCEL
+   handler to check if the cancelled syscall have side-effects that need to be
+   returned to the caller.
+
+   This implementation should be used as a reference one to document the
+   implementation constraints:
+
+     1. The __syscall_cancel_arch_start should point just before the test
+        that thread is already cancelled,
+     2.	The __syscall_cancel_arch_end should point to the immediate next
+        instruction after the syscall one.
+     3. It should return the syscall value or a negative result if is has
+        failed, similar to INTERNAL_SYSCALL_CALL.
+
+   The __syscall_cancel_arch_end one is because the kernel will signal
+   interrupted syscall with side effects by setting the signal frame program
+   counter (on the ucontext_t third argument from SA_SIGINFO signal handler)
+   right after the syscall instruction.
+
+   For some architecture, the INTERNAL_SYSCALL_NCS macro use more instructions
+   to get the error condition from kernel (as for powerpc and sparc that
+   checks for the conditional register), or uses an out of the line helper
+   (ARM thumb), or uses a kernel helper gate (i686 or ia64).  In this case
+   the architecture should either adjust the macro or provide a custom
+   __syscall_cancel_arch implementation.   */
+
+long int
+__syscall_cancel_arch (volatile int *ch, __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
+		       __SYSCALL_CANCEL7_ARG_DEF)
+{
+#define ADD_LABEL(__label)		\
+  asm volatile (			\
+    ".global " __label "\t\n"		\
+    __label ":\n");
+
+  ADD_LABEL ("__syscall_cancel_arch_start");
+  if (__glibc_unlikely (*ch & CANCELED_BITMASK))
+    __syscall_do_cancel();
+
+  long int result = INTERNAL_SYSCALL_NCS_CALL (nr, a1, a2, a3, a4, a5, a6
+					       __SYSCALL_CANCEL7_ARG7);
+  ADD_LABEL ("__syscall_cancel_arch_end");
+  if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result)))
+    return -INTERNAL_SYSCALL_ERRNO (result);
+  return result;
+}