diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/aarch64/nptl/sysdep-cancel.h')
-rw-r--r-- | sysdeps/unix/sysv/linux/aarch64/nptl/sysdep-cancel.h | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/aarch64/nptl/sysdep-cancel.h b/sysdeps/unix/sysv/linux/aarch64/nptl/sysdep-cancel.h new file mode 100644 index 0000000000..f6903b5dd8 --- /dev/null +++ b/sysdeps/unix/sysv/linux/aarch64/nptl/sysdep-cancel.h @@ -0,0 +1,205 @@ +/* Copyright (C) 2003-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> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <nptl/pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + .type __##syscall_name##_nocancel,%function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + cfi_startproc; \ + DO_CALL (syscall_name, args); \ + PSEUDO_RET; \ + cfi_endproc; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + ENTRY (name); \ + SINGLE_THREAD_P; \ + DOARGS_##args; \ + bne .Lpseudo_cancel; \ + DO_CALL (syscall_name, 0); \ + UNDOARGS_##args; \ + cmn x0, 4095; \ + PSEUDO_RET; \ + .Lpseudo_cancel: \ + DOCARGS_##args; /* save syscall args etc. around CENABLE. */ \ + CENABLE; \ + mov x16, x0; /* put mask in safe place. */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + mov x8, SYS_ify (syscall_name); /* do the call. */ \ + svc 0; \ + str x0, [sp, -16]!; /* save syscall return value. */ \ + cfi_adjust_cfa_offset (16); \ + mov x0, x16; /* get mask back. */ \ + CDISABLE; \ + ldr x0, [sp], 16; \ + cfi_adjust_cfa_offset (-16); \ + ldr x30, [sp], 16; \ + cfi_adjust_cfa_offset (-16); \ + cfi_restore (x30); \ + UNDOARGS_##args; \ + cmn x0, 4095; + +# define DOCARGS_0 \ + str x30, [sp, -16]!; \ + cfi_adjust_cfa_offset (16); \ + cfi_rel_offset (x30, 0) + +# define UNDOCARGS_0 + +# define DOCARGS_1 \ + DOCARGS_0; \ + str x0, [sp, -16]!; \ + cfi_adjust_cfa_offset (16); \ + cfi_rel_offset (x0, 0) + +# define UNDOCARGS_1 \ + ldr x0, [sp], 16; \ + cfi_restore (x0); \ + cfi_adjust_cfa_offset (-16); \ + +# define DOCARGS_2 \ + DOCARGS_1; \ + str x1, [sp, -16]!; \ + cfi_adjust_cfa_offset (16); \ + cfi_rel_offset (x1, 0) + +# define UNDOCARGS_2 \ + ldr x1, [sp], 16; \ + cfi_restore (x1); \ + cfi_adjust_cfa_offset (-16); \ + UNDOCARGS_1 + +# define DOCARGS_3 \ + DOCARGS_2; \ + str x2, [sp, -16]!; \ + cfi_adjust_cfa_offset (16); \ + cfi_rel_offset (x2, 0) + +# define UNDOCARGS_3 \ + ldr x2, [sp], 16; \ + cfi_restore (x2); \ + cfi_adjust_cfa_offset (-16); \ + UNDOCARGS_2 + +# define DOCARGS_4 \ + DOCARGS_3; \ + str x3, [sp, -16]!; \ + cfi_adjust_cfa_offset (16); \ + cfi_rel_offset (x3, 0) + +# define UNDOCARGS_4 \ + ldr x3, [sp], 16; \ + cfi_restore (x3); \ + cfi_adjust_cfa_offset (-16); \ + UNDOCARGS_3 + +# define DOCARGS_5 \ + DOCARGS_4; \ + str x4, [sp, -16]!; \ + cfi_adjust_cfa_offset (16); \ + cfi_rel_offset (x4, 0) + +# define UNDOCARGS_5 \ + ldr x4, [sp], 16; \ + cfi_restore (x4); \ + cfi_adjust_cfa_offset (-16); \ + UNDOCARGS_4 + +# define DOCARGS_6 \ + DOCARGS_5; \ + str x5, [sp, -16]!; \ + cfi_adjust_cfa_offset (16); \ + cfi_rel_offset (x5, 0) + +# define UNDOCARGS_6 \ + ldr x5, [sp], 16; \ + cfi_restore (x5); \ + cfi_adjust_cfa_offset (-16); \ + UNDOCARGS_5 + +# ifdef IS_IN_libpthread +# define CENABLE bl __pthread_enable_asynccancel +# define CDISABLE bl __pthread_disable_asynccancel +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE bl __libc_enable_asynccancel +# define CDISABLE bl __libc_disable_asynccancel +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define CENABLE bl __librt_enable_asynccancel +# define CDISABLE bl __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +# if defined IS_IN_libpthread || !defined NOT_IN_libc +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +# else +# define SINGLE_THREAD_P \ + adrp x16, __local_multiple_threads; \ + add x16, x16, #:lo12:__local_multiple_threads; \ + ldr x16, [x16]; \ + cmp x16, 0; +# endif +# else +/* There is no __local_multiple_threads for librt, so use the TCB. */ +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + stp x0, x30, [sp, -16]!; \ + cfi_adjust_cfa_offset (16); \ + cfi_rel_offset (x0, 0); \ + cfi_rel_offset (x30, 8); \ + bl __read_tp; \ + sub x0, x0, PTHREAD_SIZEOF; \ + ldr x16, [x0, PTHREAD_MULTIPLE_THREADS_OFFSET]; \ + ldp x0, x30, [sp], 16; \ + cfi_restore (x0); \ + cfi_restore (x30); \ + cfi_adjust_cfa_offset (-16); \ + cmp x16, 0 +# define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P +# endif +# endif + +#elif !defined __ASSEMBLER__ + +/* For rtld, et cetera. */ +# 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) +#endif |