Consolidate NPTL configury for ARM/Linux.
[platform/upstream/glibc.git] / sysdeps / unix / sysv / linux / arm / nptl / sysdep-cancel.h
1 /* Copyright (C) 2003-2014 Free Software Foundation, Inc.
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
15    License along with the GNU C Library.  If not, see
16    <http://www.gnu.org/licenses/>.  */
17
18 #include <sysdep.h>
19 #include <tls.h>
20 #ifndef __ASSEMBLER__
21 # include <nptl/pthreadP.h>
22 #endif
23
24 #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
25
26 /* NOTE: We do mark syscalls with unwind annotations, for the benefit of
27    cancellation; but they're really only accurate at the point of the
28    syscall.  The ARM unwind directives are not rich enough without adding
29    a custom personality function.  */
30
31 # undef PSEUDO
32 # define PSEUDO(name, syscall_name, args)                               \
33         .text;                                                          \
34   ENTRY (__##syscall_name##_nocancel);                                  \
35         CFI_SECTIONS;                                                   \
36         DO_CALL (syscall_name, args);                                   \
37         cmn     r0, $4096;                                              \
38         PSEUDO_RET;                                                     \
39   END (__##syscall_name##_nocancel);                                    \
40   ENTRY (name);                                                         \
41         SINGLE_THREAD_P;                                                \
42         DOARGS_##args;                                                  \
43         bne .Lpseudo_cancel;                                            \
44         cfi_remember_state;                                             \
45         ldr     r7, =SYS_ify (syscall_name);                            \
46         swi     0x0;                                                    \
47         UNDOARGS_##args;                                                \
48         cmn     r0, $4096;                                              \
49         PSEUDO_RET;                                                     \
50         cfi_restore_state;                                              \
51   .Lpseudo_cancel:                                                      \
52         .fnstart;       /* matched by the .fnend in UNDOARGS below.  */ \
53         DOCARGS_##args; /* save syscall args etc. around CENABLE.  */   \
54         CENABLE;                                                        \
55         mov ip, r0;             /* put mask in safe place.  */          \
56         UNDOCARGS_##args;       /* restore syscall args.  */            \
57         ldr     r7, =SYS_ify (syscall_name);                            \
58         swi     0x0;            /* do the call.  */                     \
59         mov     r7, r0;         /* save syscall return value.  */       \
60         mov     r0, ip;         /* get mask back.  */                   \
61         CDISABLE;                                                       \
62         mov     r0, r7;         /* retrieve return value.  */           \
63         RESTORE_LR_##args;                                              \
64         UNDOARGS_##args;                                                \
65         cmn     r0, $4096
66
67 /* DOARGS pushes eight bytes on the stack for five arguments, twelve bytes for
68    six arguments, and four bytes for fewer.  In order to preserve doubleword
69    alignment, sometimes we must save an extra register.  */
70
71 # define RESTART_UNWIND                         \
72         .fnend;                                 \
73         .fnstart;                               \
74         .save   {r7};                           \
75         .save   {lr}
76
77 # define DOCARGS_0                              \
78         .save {r7};                             \
79         push    {lr};                           \
80         cfi_adjust_cfa_offset (4);              \
81         cfi_rel_offset (lr, 0);                 \
82         .save   {lr}
83 # define UNDOCARGS_0
84 # define RESTORE_LR_0                           \
85         pop     {lr};                           \
86         cfi_adjust_cfa_offset (-4);             \
87         cfi_restore (lr)
88
89 # define DOCARGS_1                              \
90         .save   {r7};                           \
91         push    {r0, r1, lr};                   \
92         cfi_adjust_cfa_offset (12);             \
93         cfi_rel_offset (lr, 8);                 \
94         .save   {lr};                           \
95         .pad    #8
96 # define UNDOCARGS_1                            \
97         ldr r0, [sp], #8;                       \
98         cfi_adjust_cfa_offset (-8);             \
99         RESTART_UNWIND
100 # define RESTORE_LR_1                           \
101         RESTORE_LR_0
102
103 # define DOCARGS_2                              \
104         .save   {r7};                           \
105         push    {r0, r1, lr};                   \
106         cfi_adjust_cfa_offset (12);             \
107         cfi_rel_offset (lr, 8);                 \
108         .save   {lr};                           \
109         .pad    #8
110 # define UNDOCARGS_2                            \
111         pop     {r0, r1};                       \
112         cfi_adjust_cfa_offset (-8);             \
113         RESTART_UNWIND
114 # define RESTORE_LR_2                           \
115         RESTORE_LR_0
116
117 # define DOCARGS_3                              \
118         .save   {r7};                           \
119         push    {r0, r1, r2, r3, lr};           \
120         cfi_adjust_cfa_offset (20);             \
121         cfi_rel_offset (lr, 16);                \
122         .save   {lr};                           \
123         .pad    #16
124 # define UNDOCARGS_3                            \
125         pop     {r0, r1, r2, r3};               \
126         cfi_adjust_cfa_offset (-16);            \
127         RESTART_UNWIND
128 # define RESTORE_LR_3                           \
129         RESTORE_LR_0
130
131 # define DOCARGS_4                              \
132         .save   {r7};                           \
133         push    {r0, r1, r2, r3, lr};           \
134         cfi_adjust_cfa_offset (20);             \
135         cfi_rel_offset (lr, 16);                \
136         .save   {lr};                           \
137         .pad    #16
138 # define UNDOCARGS_4                            \
139         pop     {r0, r1, r2, r3};               \
140         cfi_adjust_cfa_offset (-16);            \
141         RESTART_UNWIND
142 # define RESTORE_LR_4                           \
143         RESTORE_LR_0
144
145 /* r4 is only stmfd'ed for correct stack alignment.  */
146 # define DOCARGS_5                              \
147         .save   {r4, r7};                       \
148         push    {r0, r1, r2, r3, r4, lr};       \
149         cfi_adjust_cfa_offset (24);             \
150         cfi_rel_offset (lr, 20);                \
151         .save   {lr};                           \
152         .pad    #20
153 # define UNDOCARGS_5                            \
154         pop     {r0, r1, r2, r3};               \
155         cfi_adjust_cfa_offset (-16);            \
156         .fnend;                                 \
157         .fnstart;                               \
158         .save   {r4, r7};                       \
159         .save   {lr};                           \
160         .pad    #4
161 # define RESTORE_LR_5                           \
162         pop     {r4, lr};                       \
163         cfi_adjust_cfa_offset (-8);             \
164         /* r4 will be marked as restored later.  */ \
165         cfi_restore (lr)
166
167 # define DOCARGS_6                              \
168         .save   {r4, r5, r7};                   \
169         push    {r0, r1, r2, r3, lr};           \
170         cfi_adjust_cfa_offset (20);             \
171         cfi_rel_offset (lr, 16);                \
172         .save   {lr};                           \
173         .pad    #16
174 # define UNDOCARGS_6                            \
175         pop     {r0, r1, r2, r3};               \
176         cfi_adjust_cfa_offset (-16);            \
177         .fnend;                                 \
178         .fnstart;                               \
179         .save   {r4, r5, r7};                   \
180         .save   {lr};
181 # define RESTORE_LR_6                           \
182         RESTORE_LR_0
183
184 # ifdef IS_IN_libpthread
185 #  define CENABLE       bl PLTJMP(__pthread_enable_asynccancel)
186 #  define CDISABLE      bl PLTJMP(__pthread_disable_asynccancel)
187 #  define __local_multiple_threads __pthread_multiple_threads
188 # elif !defined NOT_IN_libc
189 #  define CENABLE       bl PLTJMP(__libc_enable_asynccancel)
190 #  define CDISABLE      bl PLTJMP(__libc_disable_asynccancel)
191 #  define __local_multiple_threads __libc_multiple_threads
192 # elif defined IS_IN_librt
193 #  define CENABLE       bl PLTJMP(__librt_enable_asynccancel)
194 #  define CDISABLE      bl PLTJMP(__librt_disable_asynccancel)
195 # else
196 #  error Unsupported library
197 # endif
198
199 # if defined IS_IN_libpthread || !defined NOT_IN_libc
200 #  ifndef __ASSEMBLER__
201 extern int __local_multiple_threads attribute_hidden;
202 #   define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
203 #  else
204 #   define SINGLE_THREAD_P                                              \
205         LDST_PCREL(ldr, ip, ip, __local_multiple_threads);              \
206         teq ip, #0
207 #  endif
208 # else
209 /*  There is no __local_multiple_threads for librt, so use the TCB.  */
210 #  ifndef __ASSEMBLER__
211 #   define SINGLE_THREAD_P                                              \
212   __builtin_expect (THREAD_GETMEM (THREAD_SELF,                         \
213                                    header.multiple_threads) == 0, 1)
214 #  else
215 #   define SINGLE_THREAD_P                                              \
216         push    {r0, lr};                                               \
217         cfi_adjust_cfa_offset (8);                                      \
218         cfi_rel_offset (lr, 4);                                         \
219         GET_TLS (lr);                                                   \
220         NEGOFF_ADJ_BASE (r0, MULTIPLE_THREADS_OFFSET);                  \
221         ldr     ip, NEGOFF_OFF1 (r0, MULTIPLE_THREADS_OFFSET);          \
222         pop     {r0, lr};                                               \
223         cfi_adjust_cfa_offset (-8);                                     \
224         cfi_restore (lr);                                               \
225         teq     ip, #0
226 #   define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P
227 #  endif
228 # endif
229
230 #elif !defined __ASSEMBLER__
231
232 /* For rtld, et cetera.  */
233 # define SINGLE_THREAD_P 1
234 # define NO_CANCELLATION 1
235
236 #endif
237
238 #ifndef __ASSEMBLER__
239 # define RTLD_SINGLE_THREAD_P \
240   __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
241                                    header.multiple_threads) == 0, 1)
242 #endif