Back to index

glibc  2.9
sysdep-cancel.h
Go to the documentation of this file.
00001 /* cancellable system calls for Linux/HPPA.
00002    Copyright (C) 2003 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Carlos O'Donell <carlos@baldric.uwo.ca>, 2003.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <sysdep.h>
00022 #include <tls.h>
00023 #ifndef __ASSEMBLER__
00024 # include <linuxthreads/internals.h>
00025 #endif
00026 
00027 #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
00028 
00029 # ifndef NO_ERROR
00030 #  define NO_ERROR -0x1000
00031 # endif
00032 
00033 /* The syscall cancellation mechanism requires userspace
00034    assistance, the following code does roughly this:
00035 
00036        do arguments (read arg5 and arg6 to registers)
00037        setup frame
00038        
00039        check if there are threads, yes jump to pseudo_cancel
00040        
00041        unthreaded:
00042               syscall
00043               check syscall return (jump to pre_end)
00044               set errno
00045               set return to -1
00046               (jump to pre_end)
00047               
00048        pseudo_cancel:
00049               cenable
00050               syscall
00051               cdisable
00052               check syscall return (jump to pre_end)
00053               set errno
00054               set return to -1
00055               
00056        pre_end
00057               restore stack
00058        
00059        It is expected that 'ret' and 'END' macros will
00060        append an 'undo arguments' and 'return' to the 
00061        this PSEUDO macro. */
00062    
00063 # undef PSEUDO
00064 # define PSEUDO(name, syscall_name, args)                      \
00065        ENTRY (name)                                            \
00066        DOARGS_##args                             ASM_LINE_SEP  \
00067        copy TREG, %r1                                   ASM_LINE_SEP  \
00068        copy %sp, TREG                                   ASM_LINE_SEP  \
00069        stwm %r1, 64(%sp)                         ASM_LINE_SEP  \
00070        stw %rp, -20(%sp)                         ASM_LINE_SEP  \
00071        stw TREG, -4(%sp)                         ASM_LINE_SEP  \
00072        /* Done setting up frame, continue... */  ASM_LINE_SEP  \
00073        SINGLE_THREAD_P                                  ASM_LINE_SEP  \
00074        cmpib,<>,n 0,%ret0,L(pseudo_cancel)              ASM_LINE_SEP  \
00075 L(unthreaded):                                          ASM_LINE_SEP  \
00076        /* Save r19 */                                   ASM_LINE_SEP  \
00077        SAVE_PIC(TREG)                                   ASM_LINE_SEP  \
00078        /* Do syscall, delay loads # */                  ASM_LINE_SEP  \
00079        ble  0x100(%sr2,%r0)                      ASM_LINE_SEP  \
00080        ldi SYS_ify (syscall_name), %r20 /* delay */     ASM_LINE_SEP  \
00081        ldi NO_ERROR,%r1                          ASM_LINE_SEP  \
00082        cmpb,>>=,n %r1,%ret0,L(pre_end)                  ASM_LINE_SEP  \
00083        /* Restore r19 from TREG */               ASM_LINE_SEP  \
00084        LOAD_PIC(TREG) /* delay */                ASM_LINE_SEP  \
00085        SYSCALL_ERROR_HANDLER                            ASM_LINE_SEP  \
00086        /* Use TREG for temp storage */                  ASM_LINE_SEP  \
00087        copy %ret0, TREG /* delay */                     ASM_LINE_SEP  \
00088        /* OPTIMIZE: Don't reload r19 */          ASM_LINE_SEP  \
00089        /* do a -1*syscall_ret0 */                ASM_LINE_SEP  \
00090        sub %r0, TREG, TREG                       ASM_LINE_SEP  \
00091        /* Store into errno location */                  ASM_LINE_SEP  \
00092        stw TREG, 0(%sr0,%ret0)                          ASM_LINE_SEP  \
00093        b L(pre_end)                              ASM_LINE_SEP  \
00094        /* return -1 as error */                  ASM_LINE_SEP  \
00095        ldo -1(%r0), %ret0 /* delay */                   ASM_LINE_SEP  \
00096 L(pseudo_cancel):                                ASM_LINE_SEP  \
00097        PUSHARGS_##args /* Save args */                  ASM_LINE_SEP  \
00098        /* Save r19 into TREG */                  ASM_LINE_SEP  \
00099        CENABLE /* FUNC CALL */                          ASM_LINE_SEP  \
00100        SAVE_PIC(TREG) /* delay */                ASM_LINE_SEP  \
00101        /* restore syscall args */                ASM_LINE_SEP  \
00102        POPARGS_##args                                   ASM_LINE_SEP  \
00103        /* save mask from cenable (use stub rp slot) */  ASM_LINE_SEP  \
00104        stw %ret0, -24(%sp)                       ASM_LINE_SEP  \
00105        /* ... SYSCALL ... */                            ASM_LINE_SEP  \
00106        ble 0x100(%sr2,%r0)                       ASM_LINE_SEP    \
00107        ldi SYS_ify (syscall_name), %r20 /* delay */     ASM_LINE_SEP  \
00108        /* ............... */                            ASM_LINE_SEP  \
00109        LOAD_PIC(TREG)                                   ASM_LINE_SEP  \
00110        /* pass mask as arg0 to cdisable */              ASM_LINE_SEP  \
00111        ldw -24(%sp), %r26                        ASM_LINE_SEP  \
00112        CDISABLE                                  ASM_LINE_SEP  \
00113        stw %ret0, -24(%sp) /* delay */                  ASM_LINE_SEP  \
00114        /* Restore syscall return */                     ASM_LINE_SEP  \
00115        ldw -24(%sp), %ret0                       ASM_LINE_SEP  \
00116        /* compare error */                       ASM_LINE_SEP  \
00117        ldi NO_ERROR,%r1                          ASM_LINE_SEP  \
00118        /* branch if no error */                  ASM_LINE_SEP  \
00119        cmpb,>>=,n %r1,%ret0,L(pre_end)                  ASM_LINE_SEP  \
00120        LOAD_PIC(TREG)       /* cond. nullify */         ASM_LINE_SEP  \
00121        copy %ret0, TREG /* save syscall return */       ASM_LINE_SEP  \
00122        SYSCALL_ERROR_HANDLER                            ASM_LINE_SEP  \
00123        /* make syscall res value positive */            ASM_LINE_SEP  \
00124        sub %r0, TREG, TREG  /* delay */          ASM_LINE_SEP  \
00125        /* No need to LOAD_PIC */                 ASM_LINE_SEP  \
00126        /* store into errno location */                  ASM_LINE_SEP  \
00127        stw TREG, 0(%sr0,%ret0)                          ASM_LINE_SEP  \
00128        /* return -1 */                                  ASM_LINE_SEP  \
00129        ldo -1(%r0), %ret0                        ASM_LINE_SEP  \
00130 L(pre_end):                                      ASM_LINE_SEP  \
00131        /* Restore rp before exit */                     ASM_LINE_SEP  \
00132        ldw -84(%sr0,%sp), %rp                           ASM_LINE_SEP  \
00133        /* Undo frame */                          ASM_LINE_SEP  \
00134        ldwm -64(%sp),TREG                        ASM_LINE_SEP  \
00135        /* No need to LOAD_PIC */                 ASM_LINE_SEP
00136 
00137 /* Save arguments into our frame */
00138 # define PUSHARGS_0  /* nothing to do */
00139 # define PUSHARGS_1  PUSHARGS_0 stw %r26, -36(%sr0,%sp) ASM_LINE_SEP
00140 # define PUSHARGS_2  PUSHARGS_1 stw %r25, -40(%sr0,%sp) ASM_LINE_SEP
00141 # define PUSHARGS_3  PUSHARGS_2 stw %r24, -44(%sr0,%sp) ASM_LINE_SEP
00142 # define PUSHARGS_4  PUSHARGS_3 stw %r23, -48(%sr0,%sp) ASM_LINE_SEP
00143 # define PUSHARGS_5  PUSHARGS_4 stw %r22, -52(%sr0,%sp) ASM_LINE_SEP 
00144 # define PUSHARGS_6  PUSHARGS_5 stw %r21, -56(%sr0,%sp) ASM_LINE_SEP
00145 
00146 /* Bring them back from the stack */
00147 # define POPARGS_0   /* nothing to do */
00148 # define POPARGS_1   POPARGS_0 ldw -36(%sr0,%sp), %r26  ASM_LINE_SEP
00149 # define POPARGS_2   POPARGS_1 ldw -40(%sr0,%sp), %r25  ASM_LINE_SEP
00150 # define POPARGS_3   POPARGS_2 ldw -44(%sr0,%sp), %r24  ASM_LINE_SEP
00151 # define POPARGS_4   POPARGS_3 ldw -48(%sr0,%sp), %r23  ASM_LINE_SEP
00152 # define POPARGS_5   POPARGS_4 ldw -52(%sr0,%sp), %r22  ASM_LINE_SEP
00153 # define POPARGS_6   POPARGS_5 ldw -56(%sr0,%sp), %r21  ASM_LINE_SEP
00154 
00155 # ifdef IS_IN_libpthread
00156 #  ifdef PIC
00157 #   define CENABLE .import __pthread_enable_asynccancel,code ASM_LINE_SEP \
00158                      bl __pthread_enable_asynccancel,%r2 ASM_LINE_SEP
00159 #   define CDISABLE .import __pthread_disable_asynccancel,code ASM_LINE_SEP \
00160                      bl __pthread_disable_asynccancel,%r2 ASM_LINE_SEP
00161 #  else
00162 #   define CENABLE .import __pthread_enable_asynccancel,code ASM_LINE_SEP \
00163                      bl __pthread_enable_asynccancel,%r2 ASM_LINE_SEP
00164 #   define CDISABLE .import __pthread_disable_asynccancel,code ASM_LINE_SEP \
00165                      bl __pthread_disable_asynccancel,%r2 ASM_LINE_SEP
00166 #  endif
00167 # elif !defined NOT_IN_libc
00168 #  ifdef PIC
00169 #   define CENABLE .import __libc_enable_asynccancel,code ASM_LINE_SEP \
00170                      bl __libc_enable_asynccancel,%r2 ASM_LINE_SEP
00171 #   define CDISABLE  .import __libc_disable_asynccancel,code ASM_LINE_SEP \
00172                      bl __libc_disable_asynccancel,%r2 ASM_LINE_SEP
00173 #  else
00174 #   define CENABLE .import __libc_enable_asynccancel,code ASM_LINE_SEP \
00175                      bl __libc_enable_asynccancel,%r2 ASM_LINE_SEP
00176 #   define CDISABLE  .import __libc_disable_asynccancel,code ASM_LINE_SEP \
00177                      bl __libc_disable_asynccancel,%r2 ASM_LINE_SEP
00178 #  endif
00179 # else
00180 #  ifdef PIC
00181 #   define CENABLE .import __librt_enable_asynccancel,code ASM_LINE_SEP \
00182                      bl __librt_enable_asynccancel,%r2 ASM_LINE_SEP
00183 #   define CDISABLE .import __librt_disable_asynccancel,code ASM_LINE_SEP \
00184                      bl __librt_disable_asynccancel,%r2 ASM_LINE_SEP
00185 #  else
00186 #   define CENABLE .import __librt_enable_asynccancel,code ASM_LINE_SEP \
00187                      bl __librt_enable_asynccancel,%r2 ASM_LINE_SEP
00188 #   define CDISABLE .import __librt_disable_asynccancel,code ASM_LINE_SEP \
00189                      bl __librt_disable_asynccancel,%r2 ASM_LINE_SEP
00190 #  endif
00191 # endif
00192 
00193 /* p_header.multiple_threads is +12 from the pthread_descr struct start,
00194    We could have called __get_cr27() but we really want less overhead */
00195 # define MULTIPLE_THREADS_OFFSET 0xC
00196 
00197 /* cr27 has been initialized to 0x0 by kernel */
00198 # define NO_THREAD_CR27 0x0
00199 
00200 # ifdef IS_IN_libpthread
00201 #  define __local_multiple_threads __pthread_multiple_threads
00202 # elif !defined NOT_IN_libc
00203 #  define __local_multiple_threads __libc_multiple_threads
00204 # else
00205 #  define __local_multiple_threads __librt_multiple_threads
00206 # endif
00207 
00208 # ifndef __ASSEMBLER__
00209 #  if !defined NOT_IN_libc || defined IS_IN_libpthread
00210 extern int __local_multiple_threads attribute_hidden;
00211 #  else
00212 extern int __local_multiple_threads;
00213 #  endif
00214 #  define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
00215 # else
00216 /* This ALT version requires newer kernel support */
00217 #  define SINGLE_THREAD_P_MFCTL                                       \
00218        mfctl %cr27, %ret0                               ASM_LINE_SEP  \
00219        cmpib,= NO_THREAD_CR27,%ret0,L(stp)                     ASM_LINE_SEP  \
00220        nop                                              ASM_LINE_SEP  \
00221        ldw MULTIPLE_THREADS_OFFSET(%sr0,%ret0),%ret0           ASM_LINE_SEP  \
00222 L(stp):                                                        ASM_LINE_SEP
00223 #  ifdef PIC
00224 /* Slower version uses GOT to get value of __local_multiple_threads */
00225 #   define SINGLE_THREAD_P                                            \
00226        addil LT%__local_multiple_threads, %r19                 ASM_LINE_SEP  \
00227        ldw RT%__local_multiple_threads(%sr0,%r1), %ret0 ASM_LINE_SEP  \
00228        ldw 0(%sr0,%ret0), %ret0                         ASM_LINE_SEP
00229 #  else
00230 /* Slow non-pic version using DP */
00231 #   define SINGLE_THREAD_P                                                   \
00232        addil LR%__local_multiple_threads-$global$,%r27                ASM_LINE_SEP  \
00233        ldw RR%__local_multiple_threads-$global$(%sr0,%r1),%ret0       ASM_LINE_SEP
00234 #  endif
00235 # endif
00236 #elif !defined __ASSEMBLER__
00237 
00238 /* This code should never be used but we define it anyhow.  */
00239 # define SINGLE_THREAD_P (1)
00240 
00241 #endif
00242 /* !defined NOT_IN_libc || defined IS_IN_libpthread */