aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/linux/sysdep-cancel.h
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux/sysdep-cancel.h')
-rw-r--r--sysdeps/unix/sysv/linux/sysdep-cancel.h63
1 files changed, 62 insertions, 1 deletions
diff --git a/sysdeps/unix/sysv/linux/sysdep-cancel.h b/sysdeps/unix/sysv/linux/sysdep-cancel.h
index 96c9a904b8..6e3f0455c2 100644
--- a/sysdeps/unix/sysv/linux/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/sysdep-cancel.h
@@ -1,4 +1,4 @@
-/* Single-thread optimization definitions. Linux version.
+/* Cancellable syscall definitions Linux version.
Copyright (C) 2017-2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -21,5 +21,66 @@
#define _SYSDEP_CANCEL_H
#include <sysdep.h>
+#include "pthreadP.h"
+
+/* Called by the INTERNAL_SYSCALL_CANCEL macro, check for cancellation and
+ returns the syscall value or its negative error code. */
+static __always_inline long int
+internal_syscall_cancel (__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
+ __syscall_arg_t nr)
+{
+ long int result;
+ struct pthread *pd = THREAD_SELF;
+
+ /* If cancellation is not enabled, call the syscall directly and also
+ for thread terminatation to avoid call __syscall_do_cancel while
+ executing cleanup handlers. */
+ int ch = atomic_load_relaxed (&pd->cancelhandling);
+ if (SINGLE_THREAD_P || !cancel_enabled (ch) || cancel_exiting (ch))
+ {
+ result = INTERNAL_SYSCALL_NCS_CALL (nr, a1, a2, a3, a4, a5, a6
+ __SYSCALL_CANCEL7_ARCH_ARG7);
+ if (INTERNAL_SYSCALL_ERROR_P (result))
+ return -INTERNAL_SYSCALL_ERRNO (result);
+ 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 __SYSCALL_CANCEL7_ARCH_ARG7);
+
+ /* If the cancellable syscall was interrupted by SIGCANCEL and it has no
+ side-effect, cancel the thread if cancellation is enabled. */
+ ch = atomic_load_relaxed (&pd->cancelhandling);
+ /* The behaviour here assumes that EINTR is returned only if there are no
+ visible side effects. POSIX Issue 7 has not yet provided any stronger
+ language for close, and in theory the close syscall could return EINTR
+ and leave the file descriptor open (conforming and leaks). It expects
+ that no such kernel is used with glibc. */
+ if (result == -EINTR && cancel_enabled_and_canceled (ch))
+ __syscall_do_cancel ();
+
+ return result;
+}
+
+/* Called by the SYSCALL_CANCEL macro, check for cancellation and return the
+ syscall expected success value (usually 0) or, in case of failure, -1 and
+ sets errno to syscall return value. */
+static __always_inline long int
+syscall_cancel (__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 __syscall_arg_t nr)
+{
+ int r = internal_syscall_cancel (a1, a2, a3, a4, a5, a6,
+ __SYSCALL_CANCEL7_ARG nr);
+ return __glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (r))
+ ? SYSCALL_ERROR_LABEL (INTERNAL_SYSCALL_ERRNO (r))
+ : r;
+}
#endif