]>
Commit | Line | Data |
---|---|---|
d4697bc9 | 1 | /* Copyright (C) 2005-2014 Free Software Foundation, Inc. |
da1ea0f0 CD |
2 | This file is part of the GNU C Library. |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
5 | modify it under the terms of the GNU Lesser General Public | |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
8 | ||
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | Lesser General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU Lesser General Public | |
ab84e3ff PE |
15 | License along with the GNU C Library. If not, see |
16 | <http://www.gnu.org/licenses/>. */ | |
da1ea0f0 CD |
17 | |
18 | #include <sysdep.h> | |
19 | #include <sysdeps/generic/sysdep.h> | |
20 | #include <tls.h> | |
21 | #ifndef __ASSEMBLER__ | |
22 | # include <nptl/pthreadP.h> | |
23 | #endif | |
24 | ||
25 | #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt | |
26 | ||
27 | # ifndef NO_ERROR | |
28 | # define NO_ERROR -0x1000 | |
29 | # endif | |
30 | ||
31 | /* The syscall cancellation mechanism requires userspace | |
32 | assistance, the following code does roughly this: | |
33 | ||
34 | do arguments (read arg5 and arg6 to registers) | |
35 | setup frame | |
5556231d | 36 | |
da1ea0f0 | 37 | check if there are threads, yes jump to pseudo_cancel |
5556231d | 38 | |
da1ea0f0 CD |
39 | unthreaded: |
40 | syscall | |
41 | check syscall return (jump to pre_end) | |
42 | set errno | |
43 | set return to -1 | |
44 | (jump to pre_end) | |
5556231d | 45 | |
da1ea0f0 CD |
46 | pseudo_cancel: |
47 | cenable | |
48 | syscall | |
49 | cdisable | |
50 | check syscall return (jump to pre_end) | |
51 | set errno | |
52 | set return to -1 | |
5556231d | 53 | |
da1ea0f0 CD |
54 | pre_end |
55 | restore stack | |
5556231d | 56 | |
da1ea0f0 | 57 | It is expected that 'ret' and 'END' macros will |
5556231d | 58 | append an 'undo arguments' and 'return' to the |
da1ea0f0 | 59 | this PSEUDO macro. */ |
5556231d | 60 | |
da1ea0f0 CD |
61 | # undef PSEUDO |
62 | # define PSEUDO(name, syscall_name, args) \ | |
8cb8321f CD |
63 | ENTRY (__##syscall_name##_nocancel) \ |
64 | DOARGS_##args ASM_LINE_SEP \ | |
65 | stwm TREG, 64(%sp) ASM_LINE_SEP \ | |
66 | .cfi_offset TREG, 0 ASM_LINE_SEP \ | |
67 | .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ | |
68 | stw %sp, -4(%sp) ASM_LINE_SEP \ | |
69 | .cfi_offset 30, -4 ASM_LINE_SEP \ | |
70 | stw %r19, -32(%sp) ASM_LINE_SEP \ | |
71 | .cfi_offset 19, -32 ASM_LINE_SEP \ | |
72 | /* Save r19 */ ASM_LINE_SEP \ | |
73 | SAVE_PIC(TREG) ASM_LINE_SEP \ | |
74 | /* Do syscall, delay loads # */ ASM_LINE_SEP \ | |
75 | ble 0x100(%sr2,%r0) ASM_LINE_SEP \ | |
76 | ldi SYS_ify (syscall_name), %r20 /* delay */ ASM_LINE_SEP \ | |
77 | ldi NO_ERROR,%r1 ASM_LINE_SEP \ | |
78 | cmpb,>>=,n %r1,%ret0,L(pre_nc_end) ASM_LINE_SEP \ | |
79 | /* Restore r19 from TREG */ ASM_LINE_SEP \ | |
80 | LOAD_PIC(TREG) /* delay */ ASM_LINE_SEP \ | |
81 | SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ | |
82 | /* Use TREG for temp storage */ ASM_LINE_SEP \ | |
83 | copy %ret0, TREG /* delay */ ASM_LINE_SEP \ | |
84 | /* OPTIMIZE: Don't reload r19 */ ASM_LINE_SEP \ | |
85 | /* do a -1*syscall_ret0 */ ASM_LINE_SEP \ | |
86 | sub %r0, TREG, TREG ASM_LINE_SEP \ | |
87 | /* Store into errno location */ ASM_LINE_SEP \ | |
88 | stw TREG, 0(%sr0,%ret0) ASM_LINE_SEP \ | |
89 | /* return -1 as error */ ASM_LINE_SEP \ | |
90 | ldi -1, %ret0 ASM_LINE_SEP \ | |
91 | L(pre_nc_end): ASM_LINE_SEP \ | |
92 | /* No need to LOAD_PIC */ ASM_LINE_SEP \ | |
93 | /* Undo frame */ ASM_LINE_SEP \ | |
94 | ldwm -64(%sp),TREG ASM_LINE_SEP \ | |
95 | .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ | |
96 | /* Restore rp before exit */ ASM_LINE_SEP \ | |
97 | ldw -20(%sp), %rp ASM_LINE_SEP \ | |
98 | .cfi_restore 2 ASM_LINE_SEP \ | |
99 | ret ASM_LINE_SEP \ | |
100 | END(__##syscall_name##_nocancel) ASM_LINE_SEP \ | |
101 | /**********************************************/ASM_LINE_SEP \ | |
da1ea0f0 CD |
102 | ENTRY (name) \ |
103 | DOARGS_##args ASM_LINE_SEP \ | |
0daa0500 | 104 | stwm TREG, 64(%sp) ASM_LINE_SEP \ |
8cb8321f | 105 | .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ |
0daa0500 | 106 | stw %sp, -4(%sp) ASM_LINE_SEP \ |
8cb8321f | 107 | .cfi_offset 30, -4 ASM_LINE_SEP \ |
0daa0500 | 108 | stw %r19, -32(%sp) ASM_LINE_SEP \ |
8cb8321f | 109 | .cfi_offset 19, -32 ASM_LINE_SEP \ |
da1ea0f0 CD |
110 | /* Done setting up frame, continue... */ ASM_LINE_SEP \ |
111 | SINGLE_THREAD_P ASM_LINE_SEP \ | |
112 | cmpib,<>,n 0,%ret0,L(pseudo_cancel) ASM_LINE_SEP \ | |
113 | L(unthreaded): ASM_LINE_SEP \ | |
114 | /* Save r19 */ ASM_LINE_SEP \ | |
115 | SAVE_PIC(TREG) ASM_LINE_SEP \ | |
116 | /* Do syscall, delay loads # */ ASM_LINE_SEP \ | |
117 | ble 0x100(%sr2,%r0) ASM_LINE_SEP \ | |
118 | ldi SYS_ify (syscall_name), %r20 /* delay */ ASM_LINE_SEP \ | |
119 | ldi NO_ERROR,%r1 ASM_LINE_SEP \ | |
120 | cmpb,>>=,n %r1,%ret0,L(pre_end) ASM_LINE_SEP \ | |
121 | /* Restore r19 from TREG */ ASM_LINE_SEP \ | |
122 | LOAD_PIC(TREG) /* delay */ ASM_LINE_SEP \ | |
123 | SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ | |
124 | /* Use TREG for temp storage */ ASM_LINE_SEP \ | |
125 | copy %ret0, TREG /* delay */ ASM_LINE_SEP \ | |
126 | /* OPTIMIZE: Don't reload r19 */ ASM_LINE_SEP \ | |
127 | /* do a -1*syscall_ret0 */ ASM_LINE_SEP \ | |
128 | sub %r0, TREG, TREG ASM_LINE_SEP \ | |
129 | /* Store into errno location */ ASM_LINE_SEP \ | |
130 | stw TREG, 0(%sr0,%ret0) ASM_LINE_SEP \ | |
131 | b L(pre_end) ASM_LINE_SEP \ | |
132 | /* return -1 as error */ ASM_LINE_SEP \ | |
0daa0500 | 133 | ldi -1, %ret0 /* delay */ ASM_LINE_SEP \ |
da1ea0f0 CD |
134 | L(pseudo_cancel): ASM_LINE_SEP \ |
135 | PUSHARGS_##args /* Save args */ ASM_LINE_SEP \ | |
136 | /* Save r19 into TREG */ ASM_LINE_SEP \ | |
137 | CENABLE /* FUNC CALL */ ASM_LINE_SEP \ | |
138 | SAVE_PIC(TREG) /* delay */ ASM_LINE_SEP \ | |
139 | /* restore syscall args */ ASM_LINE_SEP \ | |
140 | POPARGS_##args ASM_LINE_SEP \ | |
141 | /* save mask from cenable (use stub rp slot) */ ASM_LINE_SEP \ | |
142 | stw %ret0, -24(%sp) ASM_LINE_SEP \ | |
143 | /* ... SYSCALL ... */ ASM_LINE_SEP \ | |
144 | ble 0x100(%sr2,%r0) ASM_LINE_SEP \ | |
145 | ldi SYS_ify (syscall_name), %r20 /* delay */ ASM_LINE_SEP \ | |
146 | /* ............... */ ASM_LINE_SEP \ | |
147 | LOAD_PIC(TREG) ASM_LINE_SEP \ | |
148 | /* pass mask as arg0 to cdisable */ ASM_LINE_SEP \ | |
149 | ldw -24(%sp), %r26 ASM_LINE_SEP \ | |
150 | CDISABLE ASM_LINE_SEP \ | |
151 | stw %ret0, -24(%sp) /* delay */ ASM_LINE_SEP \ | |
152 | /* Restore syscall return */ ASM_LINE_SEP \ | |
153 | ldw -24(%sp), %ret0 ASM_LINE_SEP \ | |
154 | /* compare error */ ASM_LINE_SEP \ | |
155 | ldi NO_ERROR,%r1 ASM_LINE_SEP \ | |
156 | /* branch if no error */ ASM_LINE_SEP \ | |
157 | cmpb,>>=,n %r1,%ret0,L(pre_end) ASM_LINE_SEP \ | |
158 | LOAD_PIC(TREG) /* cond. nullify */ ASM_LINE_SEP \ | |
159 | copy %ret0, TREG /* save syscall return */ ASM_LINE_SEP \ | |
160 | SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ | |
161 | /* make syscall res value positive */ ASM_LINE_SEP \ | |
162 | sub %r0, TREG, TREG /* delay */ ASM_LINE_SEP \ | |
163 | /* No need to LOAD_PIC */ ASM_LINE_SEP \ | |
164 | /* store into errno location */ ASM_LINE_SEP \ | |
165 | stw TREG, 0(%sr0,%ret0) ASM_LINE_SEP \ | |
166 | /* return -1 */ ASM_LINE_SEP \ | |
0daa0500 | 167 | ldi -1, %ret0 ASM_LINE_SEP \ |
da1ea0f0 | 168 | L(pre_end): ASM_LINE_SEP \ |
0daa0500 | 169 | /* No need to LOAD_PIC */ ASM_LINE_SEP \ |
da1ea0f0 CD |
170 | /* Undo frame */ ASM_LINE_SEP \ |
171 | ldwm -64(%sp),TREG ASM_LINE_SEP \ | |
8cb8321f | 172 | .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ |
0daa0500 | 173 | /* Restore rp before exit */ ASM_LINE_SEP \ |
8cb8321f CD |
174 | ldw -20(%sp), %rp ASM_LINE_SEP \ |
175 | .cfi_restore 2 ASM_LINE_SEP | |
da1ea0f0 CD |
176 | |
177 | /* Save arguments into our frame */ | |
178 | # define PUSHARGS_0 /* nothing to do */ | |
8cb8321f CD |
179 | # define PUSHARGS_1 PUSHARGS_0 stw %r26, -36(%sr0,%sp) ASM_LINE_SEP \ |
180 | .cfi_offset 26, -36 ASM_LINE_SEP | |
181 | # define PUSHARGS_2 PUSHARGS_1 stw %r25, -40(%sr0,%sp) ASM_LINE_SEP \ | |
182 | .cfi_offset 25, -40 ASM_LINE_SEP | |
183 | # define PUSHARGS_3 PUSHARGS_2 stw %r24, -44(%sr0,%sp) ASM_LINE_SEP \ | |
184 | .cfi_offset 24, -44 ASM_LINE_SEP | |
185 | # define PUSHARGS_4 PUSHARGS_3 stw %r23, -48(%sr0,%sp) ASM_LINE_SEP \ | |
186 | .cfi_offset 23, -48 ASM_LINE_SEP | |
187 | # define PUSHARGS_5 PUSHARGS_4 stw %r22, -52(%sr0,%sp) ASM_LINE_SEP \ | |
188 | .cfi_offset 22, -52 ASM_LINE_SEP | |
189 | # define PUSHARGS_6 PUSHARGS_5 stw %r21, -56(%sr0,%sp) ASM_LINE_SEP \ | |
190 | .cfi_offset 21, -56 ASM_LINE_SEP | |
da1ea0f0 CD |
191 | |
192 | /* Bring them back from the stack */ | |
193 | # define POPARGS_0 /* nothing to do */ | |
8cb8321f CD |
194 | # define POPARGS_1 POPARGS_0 ldw -36(%sr0,%sp), %r26 ASM_LINE_SEP \ |
195 | .cfi_restore 26 ASM_LINE_SEP | |
196 | # define POPARGS_2 POPARGS_1 ldw -40(%sr0,%sp), %r25 ASM_LINE_SEP \ | |
197 | .cfi_restore 25 ASM_LINE_SEP | |
198 | # define POPARGS_3 POPARGS_2 ldw -44(%sr0,%sp), %r24 ASM_LINE_SEP \ | |
199 | .cfi_restore 24 ASM_LINE_SEP | |
200 | # define POPARGS_4 POPARGS_3 ldw -48(%sr0,%sp), %r23 ASM_LINE_SEP \ | |
201 | .cfi_restore 23 ASM_LINE_SEP | |
202 | # define POPARGS_5 POPARGS_4 ldw -52(%sr0,%sp), %r22 ASM_LINE_SEP \ | |
203 | .cfi_restore 22 ASM_LINE_SEP | |
204 | # define POPARGS_6 POPARGS_5 ldw -56(%sr0,%sp), %r21 ASM_LINE_SEP \ | |
205 | .cfi_restore 21 ASM_LINE_SEP | |
da1ea0f0 CD |
206 | |
207 | # ifdef IS_IN_libpthread | |
208 | # ifdef PIC | |
209 | # define CENABLE .import __pthread_enable_asynccancel,code ASM_LINE_SEP \ | |
210 | bl __pthread_enable_asynccancel,%r2 ASM_LINE_SEP | |
211 | # define CDISABLE .import __pthread_disable_asynccancel,code ASM_LINE_SEP \ | |
212 | bl __pthread_disable_asynccancel,%r2 ASM_LINE_SEP | |
213 | # else | |
214 | # define CENABLE .import __pthread_enable_asynccancel,code ASM_LINE_SEP \ | |
215 | bl __pthread_enable_asynccancel,%r2 ASM_LINE_SEP | |
216 | # define CDISABLE .import __pthread_disable_asynccancel,code ASM_LINE_SEP \ | |
217 | bl __pthread_disable_asynccancel,%r2 ASM_LINE_SEP | |
218 | # endif | |
219 | # elif !defined NOT_IN_libc | |
220 | # ifdef PIC | |
221 | # define CENABLE .import __libc_enable_asynccancel,code ASM_LINE_SEP \ | |
222 | bl __libc_enable_asynccancel,%r2 ASM_LINE_SEP | |
223 | # define CDISABLE .import __libc_disable_asynccancel,code ASM_LINE_SEP \ | |
224 | bl __libc_disable_asynccancel,%r2 ASM_LINE_SEP | |
225 | # else | |
226 | # define CENABLE .import __libc_enable_asynccancel,code ASM_LINE_SEP \ | |
227 | bl __libc_enable_asynccancel,%r2 ASM_LINE_SEP | |
228 | # define CDISABLE .import __libc_disable_asynccancel,code ASM_LINE_SEP \ | |
229 | bl __libc_disable_asynccancel,%r2 ASM_LINE_SEP | |
230 | # endif | |
cd153083 | 231 | # elif defined IS_IN_librt |
da1ea0f0 CD |
232 | # ifdef PIC |
233 | # define CENABLE .import __librt_enable_asynccancel,code ASM_LINE_SEP \ | |
234 | bl __librt_enable_asynccancel,%r2 ASM_LINE_SEP | |
235 | # define CDISABLE .import __librt_disable_asynccancel,code ASM_LINE_SEP \ | |
236 | bl __librt_disable_asynccancel,%r2 ASM_LINE_SEP | |
237 | # else | |
238 | # define CENABLE .import __librt_enable_asynccancel,code ASM_LINE_SEP \ | |
239 | bl __librt_enable_asynccancel,%r2 ASM_LINE_SEP | |
240 | # define CDISABLE .import __librt_disable_asynccancel,code ASM_LINE_SEP \ | |
241 | bl __librt_disable_asynccancel,%r2 ASM_LINE_SEP | |
242 | # endif | |
cd153083 CD |
243 | # else |
244 | # error Unsupported library | |
da1ea0f0 CD |
245 | # endif |
246 | ||
247 | # ifdef IS_IN_libpthread | |
248 | # define __local_multiple_threads __pthread_multiple_threads | |
249 | # elif !defined NOT_IN_libc | |
250 | # define __local_multiple_threads __libc_multiple_threads | |
cd153083 | 251 | # elif IS_IN_librt |
da1ea0f0 | 252 | # define __local_multiple_threads __librt_multiple_threads |
cd153083 CD |
253 | # else |
254 | # error Unsupported library | |
da1ea0f0 CD |
255 | # endif |
256 | ||
257 | # ifndef __ASSEMBLER__ | |
258 | # define SINGLE_THREAD_P \ | |
259 | __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ | |
260 | header.multiple_threads) == 0, 1) | |
261 | # else | |
262 | /* Read the value of header.multiple_threads from the thread pointer */ | |
263 | # define SINGLE_THREAD_P \ | |
264 | mfctl %cr27, %ret0 ASM_LINE_SEP \ | |
265 | ldw MULTIPLE_THREADS_THREAD_OFFSET(%sr0,%ret0),%ret0 ASM_LINE_SEP | |
266 | # endif | |
267 | #elif !defined __ASSEMBLER__ | |
268 | ||
269 | /* This code should never be used but we define it anyhow. */ | |
270 | # define SINGLE_THREAD_P (1) | |
271 | # define NO_CANCELLATION 1 | |
272 | ||
273 | #endif | |
d396ccd5 CD |
274 | /* !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt */ |
275 | ||
276 | #ifndef __ASSEMBLER__ | |
277 | # define RTLD_SINGLE_THREAD_P \ | |
278 | __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ | |
279 | header.multiple_threads) == 0, 1) | |
280 | #endif | |
281 |