diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h')
-rw-r--r-- | sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h b/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h new file mode 100644 index 0000000000..6f1c9d745b --- /dev/null +++ b/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h @@ -0,0 +1,280 @@ +/* Copyright (C) 2005-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 <sysdeps/generic/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 + +# ifndef NO_ERROR +# define NO_ERROR -0x1000 +# endif + +/* The syscall cancellation mechanism requires userspace + assistance, the following code does roughly this: + + do arguments (read arg5 and arg6 to registers) + setup frame + + check if there are threads, yes jump to pseudo_cancel + + unthreaded: + syscall + check syscall return (jump to pre_end) + set errno + set return to -1 + (jump to pre_end) + + pseudo_cancel: + cenable + syscall + cdisable + check syscall return (jump to pre_end) + set errno + set return to -1 + + pre_end + restore stack + + It is expected that 'ret' and 'END' macros will + append an 'undo arguments' and 'return' to the + this PSEUDO macro. */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + ENTRY (__##syscall_name##_nocancel) \ + DOARGS_##args ASM_LINE_SEP \ + stwm TREG, 64(%sp) ASM_LINE_SEP \ + .cfi_offset TREG, 0 ASM_LINE_SEP \ + .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ + stw %sp, -4(%sp) ASM_LINE_SEP \ + .cfi_offset 30, -4 ASM_LINE_SEP \ + stw %r19, -32(%sp) ASM_LINE_SEP \ + .cfi_offset 19, -32 ASM_LINE_SEP \ + /* Save r19 */ ASM_LINE_SEP \ + SAVE_PIC(TREG) ASM_LINE_SEP \ + /* Do syscall, delay loads # */ ASM_LINE_SEP \ + ble 0x100(%sr2,%r0) ASM_LINE_SEP \ + ldi SYS_ify (syscall_name), %r20 /* delay */ ASM_LINE_SEP \ + ldi NO_ERROR,%r1 ASM_LINE_SEP \ + cmpb,>>=,n %r1,%ret0,L(pre_nc_end) ASM_LINE_SEP \ + /* Restore r19 from TREG */ ASM_LINE_SEP \ + LOAD_PIC(TREG) /* delay */ ASM_LINE_SEP \ + SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ + /* Use TREG for temp storage */ ASM_LINE_SEP \ + copy %ret0, TREG /* delay */ ASM_LINE_SEP \ + /* OPTIMIZE: Don't reload r19 */ ASM_LINE_SEP \ + /* do a -1*syscall_ret0 */ ASM_LINE_SEP \ + sub %r0, TREG, TREG ASM_LINE_SEP \ + /* Store into errno location */ ASM_LINE_SEP \ + stw TREG, 0(%sr0,%ret0) ASM_LINE_SEP \ + /* return -1 as error */ ASM_LINE_SEP \ + ldi -1, %ret0 ASM_LINE_SEP \ +L(pre_nc_end): ASM_LINE_SEP \ + /* No need to LOAD_PIC */ ASM_LINE_SEP \ + /* Undo frame */ ASM_LINE_SEP \ + ldwm -64(%sp),TREG ASM_LINE_SEP \ + .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ + /* Restore rp before exit */ ASM_LINE_SEP \ + ldw -20(%sp), %rp ASM_LINE_SEP \ + .cfi_restore 2 ASM_LINE_SEP \ + ret ASM_LINE_SEP \ + END(__##syscall_name##_nocancel) ASM_LINE_SEP \ + /**********************************************/ASM_LINE_SEP \ + ENTRY (name) \ + DOARGS_##args ASM_LINE_SEP \ + stwm TREG, 64(%sp) ASM_LINE_SEP \ + .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ + stw %sp, -4(%sp) ASM_LINE_SEP \ + .cfi_offset 30, -4 ASM_LINE_SEP \ + stw %r19, -32(%sp) ASM_LINE_SEP \ + .cfi_offset 19, -32 ASM_LINE_SEP \ + /* Done setting up frame, continue... */ ASM_LINE_SEP \ + SINGLE_THREAD_P ASM_LINE_SEP \ + cmpib,<>,n 0,%ret0,L(pseudo_cancel) ASM_LINE_SEP \ +L(unthreaded): ASM_LINE_SEP \ + /* Save r19 */ ASM_LINE_SEP \ + SAVE_PIC(TREG) ASM_LINE_SEP \ + /* Do syscall, delay loads # */ ASM_LINE_SEP \ + ble 0x100(%sr2,%r0) ASM_LINE_SEP \ + ldi SYS_ify (syscall_name), %r20 /* delay */ ASM_LINE_SEP \ + ldi NO_ERROR,%r1 ASM_LINE_SEP \ + cmpb,>>=,n %r1,%ret0,L(pre_end) ASM_LINE_SEP \ + /* Restore r19 from TREG */ ASM_LINE_SEP \ + LOAD_PIC(TREG) /* delay */ ASM_LINE_SEP \ + SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ + /* Use TREG for temp storage */ ASM_LINE_SEP \ + copy %ret0, TREG /* delay */ ASM_LINE_SEP \ + /* OPTIMIZE: Don't reload r19 */ ASM_LINE_SEP \ + /* do a -1*syscall_ret0 */ ASM_LINE_SEP \ + sub %r0, TREG, TREG ASM_LINE_SEP \ + /* Store into errno location */ ASM_LINE_SEP \ + stw TREG, 0(%sr0,%ret0) ASM_LINE_SEP \ + b L(pre_end) ASM_LINE_SEP \ + /* return -1 as error */ ASM_LINE_SEP \ + ldi -1, %ret0 /* delay */ ASM_LINE_SEP \ +L(pseudo_cancel): ASM_LINE_SEP \ + PUSHARGS_##args /* Save args */ ASM_LINE_SEP \ + /* Save r19 into TREG */ ASM_LINE_SEP \ + CENABLE /* FUNC CALL */ ASM_LINE_SEP \ + SAVE_PIC(TREG) /* delay */ ASM_LINE_SEP \ + /* restore syscall args */ ASM_LINE_SEP \ + POPARGS_##args ASM_LINE_SEP \ + /* save mask from cenable (use stub rp slot) */ ASM_LINE_SEP \ + stw %ret0, -24(%sp) ASM_LINE_SEP \ + /* ... SYSCALL ... */ ASM_LINE_SEP \ + ble 0x100(%sr2,%r0) ASM_LINE_SEP \ + ldi SYS_ify (syscall_name), %r20 /* delay */ ASM_LINE_SEP \ + /* ............... */ ASM_LINE_SEP \ + LOAD_PIC(TREG) ASM_LINE_SEP \ + /* pass mask as arg0 to cdisable */ ASM_LINE_SEP \ + ldw -24(%sp), %r26 ASM_LINE_SEP \ + CDISABLE ASM_LINE_SEP \ + stw %ret0, -24(%sp) /* delay */ ASM_LINE_SEP \ + /* Restore syscall return */ ASM_LINE_SEP \ + ldw -24(%sp), %ret0 ASM_LINE_SEP \ + /* compare error */ ASM_LINE_SEP \ + ldi NO_ERROR,%r1 ASM_LINE_SEP \ + /* branch if no error */ ASM_LINE_SEP \ + cmpb,>>=,n %r1,%ret0,L(pre_end) ASM_LINE_SEP \ + LOAD_PIC(TREG) /* cond. nullify */ ASM_LINE_SEP \ + copy %ret0, TREG /* save syscall return */ ASM_LINE_SEP \ + SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ + /* make syscall res value positive */ ASM_LINE_SEP \ + sub %r0, TREG, TREG /* delay */ ASM_LINE_SEP \ + /* No need to LOAD_PIC */ ASM_LINE_SEP \ + /* store into errno location */ ASM_LINE_SEP \ + stw TREG, 0(%sr0,%ret0) ASM_LINE_SEP \ + /* return -1 */ ASM_LINE_SEP \ + ldi -1, %ret0 ASM_LINE_SEP \ +L(pre_end): ASM_LINE_SEP \ + /* No need to LOAD_PIC */ ASM_LINE_SEP \ + /* Undo frame */ ASM_LINE_SEP \ + ldwm -64(%sp),TREG ASM_LINE_SEP \ + .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ + /* Restore rp before exit */ ASM_LINE_SEP \ + ldw -20(%sp), %rp ASM_LINE_SEP \ + .cfi_restore 2 ASM_LINE_SEP + +/* Save arguments into our frame */ +# define PUSHARGS_0 /* nothing to do */ +# define PUSHARGS_1 PUSHARGS_0 stw %r26, -36(%sr0,%sp) ASM_LINE_SEP \ + .cfi_offset 26, -36 ASM_LINE_SEP +# define PUSHARGS_2 PUSHARGS_1 stw %r25, -40(%sr0,%sp) ASM_LINE_SEP \ + .cfi_offset 25, -40 ASM_LINE_SEP +# define PUSHARGS_3 PUSHARGS_2 stw %r24, -44(%sr0,%sp) ASM_LINE_SEP \ + .cfi_offset 24, -44 ASM_LINE_SEP +# define PUSHARGS_4 PUSHARGS_3 stw %r23, -48(%sr0,%sp) ASM_LINE_SEP \ + .cfi_offset 23, -48 ASM_LINE_SEP +# define PUSHARGS_5 PUSHARGS_4 stw %r22, -52(%sr0,%sp) ASM_LINE_SEP \ + .cfi_offset 22, -52 ASM_LINE_SEP +# define PUSHARGS_6 PUSHARGS_5 stw %r21, -56(%sr0,%sp) ASM_LINE_SEP \ + .cfi_offset 21, -56 ASM_LINE_SEP + +/* Bring them back from the stack */ +# define POPARGS_0 /* nothing to do */ +# define POPARGS_1 POPARGS_0 ldw -36(%sr0,%sp), %r26 ASM_LINE_SEP \ + .cfi_restore 26 ASM_LINE_SEP +# define POPARGS_2 POPARGS_1 ldw -40(%sr0,%sp), %r25 ASM_LINE_SEP \ + .cfi_restore 25 ASM_LINE_SEP +# define POPARGS_3 POPARGS_2 ldw -44(%sr0,%sp), %r24 ASM_LINE_SEP \ + .cfi_restore 24 ASM_LINE_SEP +# define POPARGS_4 POPARGS_3 ldw -48(%sr0,%sp), %r23 ASM_LINE_SEP \ + .cfi_restore 23 ASM_LINE_SEP +# define POPARGS_5 POPARGS_4 ldw -52(%sr0,%sp), %r22 ASM_LINE_SEP \ + .cfi_restore 22 ASM_LINE_SEP +# define POPARGS_6 POPARGS_5 ldw -56(%sr0,%sp), %r21 ASM_LINE_SEP \ + .cfi_restore 21 ASM_LINE_SEP + +# ifdef IS_IN_libpthread +# ifdef PIC +# define CENABLE .import __pthread_enable_asynccancel,code ASM_LINE_SEP \ + bl __pthread_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __pthread_disable_asynccancel,code ASM_LINE_SEP \ + bl __pthread_disable_asynccancel,%r2 ASM_LINE_SEP +# else +# define CENABLE .import __pthread_enable_asynccancel,code ASM_LINE_SEP \ + bl __pthread_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __pthread_disable_asynccancel,code ASM_LINE_SEP \ + bl __pthread_disable_asynccancel,%r2 ASM_LINE_SEP +# endif +# elif !defined NOT_IN_libc +# ifdef PIC +# define CENABLE .import __libc_enable_asynccancel,code ASM_LINE_SEP \ + bl __libc_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __libc_disable_asynccancel,code ASM_LINE_SEP \ + bl __libc_disable_asynccancel,%r2 ASM_LINE_SEP +# else +# define CENABLE .import __libc_enable_asynccancel,code ASM_LINE_SEP \ + bl __libc_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __libc_disable_asynccancel,code ASM_LINE_SEP \ + bl __libc_disable_asynccancel,%r2 ASM_LINE_SEP +# endif +# elif defined IS_IN_librt +# ifdef PIC +# define CENABLE .import __librt_enable_asynccancel,code ASM_LINE_SEP \ + bl __librt_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __librt_disable_asynccancel,code ASM_LINE_SEP \ + bl __librt_disable_asynccancel,%r2 ASM_LINE_SEP +# else +# define CENABLE .import __librt_enable_asynccancel,code ASM_LINE_SEP \ + bl __librt_enable_asynccancel,%r2 ASM_LINE_SEP +# define CDISABLE .import __librt_disable_asynccancel,code ASM_LINE_SEP \ + bl __librt_disable_asynccancel,%r2 ASM_LINE_SEP +# endif +# else +# error Unsupported library +# endif + +# ifdef IS_IN_libpthread +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define __local_multiple_threads __libc_multiple_threads +# elif IS_IN_librt +# define __local_multiple_threads __librt_multiple_threads +# else +# error Unsupported library +# endif + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +/* Read the value of header.multiple_threads from the thread pointer */ +# define SINGLE_THREAD_P \ + mfctl %cr27, %ret0 ASM_LINE_SEP \ + ldw MULTIPLE_THREADS_THREAD_OFFSET(%sr0,%ret0),%ret0 ASM_LINE_SEP +# endif +#elif !defined __ASSEMBLER__ + +/* This code should never be used but we define it anyhow. */ +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif +/* !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt */ + +#ifndef __ASSEMBLER__ +# define RTLD_SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +#endif |