1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
/* Copyright (C) 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
# if !defined(IS_IN_librt) || !defined(PIC)
# define AC_STACK_SIZE 16 /* space for r15, async_cancel arg and 2 temp words */
# define AC_SET_GOT /* empty */
# define AC_RESTORE_GOT /* empty */
# else
# define AC_STACK_SIZE 20 /* extra 4 bytes for r20 */
# define AC_SET_GOT \
swi r20, r1, AC_STACK_SIZE-4; \
mfs r20, rpc; \
addik r20, r20, _GLOBAL_OFFSET_TABLE_+8;
# define AC_RESTORE_GOT \
lwi r20, r1, AC_STACK_SIZE-4;
# endif
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.text; \
ENTRY (name) \
SINGLE_THREAD_P(r12); \
bnei r12, L(pseudo_cancel); \
.globl __##syscall_name##_nocancel; \
.type __##syscall_name##_nocancel,@function; \
__##syscall_name##_nocancel: \
DO_CALL (syscall_name, args); \
addik r4, r0, -4095; \
cmpu r4, r4, r3; \
bgei r4, SYSCALL_ERROR_LABEL; \
rtsd r15, 8; \
nop; \
.size __##syscall_name##_nocancel, .-__##syscall_name##_nocancel; \
L(pseudo_cancel): \
addik r1, r1, -AC_STACK_SIZE; \
swi r15, r1, 0; \
AC_SET_GOT \
DOCARGS_##args \
CENABLE; \
swi r3, r1, 8; \
UNDOCARGS_##args \
DO_CALL (syscall_name, args); \
swi r3, r1, 12; \
lwi r5, r1, 8; \
CDISABLE; \
lwi r3, r1, 12; \
lwi r15, r1, 0; \
AC_RESTORE_GOT \
addik r1, r1, AC_STACK_SIZE; \
addik r4, r0, -4095; \
cmpu r4, r4, r3; \
bgei r4, SYSCALL_ERROR_LABEL; \
rtsd r15, 8; \
nop;
/*
* Macros to save/restore syscall arguments across CENABLE
* The arguments are saved into the caller's stack (original r1 + 4)
*/
# define DOCARGS_0
# define DOCARGS_1 swi r5, r1, AC_STACK_SIZE + 4;
# define DOCARGS_2 swi r6, r1, AC_STACK_SIZE + 8; DOCARGS_1
# define DOCARGS_3 swi r7, r1, AC_STACK_SIZE + 12; DOCARGS_2
# define DOCARGS_4 swi r8, r1, AC_STACK_SIZE + 16; DOCARGS_3
# define DOCARGS_5 swi r9, r1, AC_STACK_SIZE + 20; DOCARGS_4
# define DOCARGS_6 swi r10, r1, AC_STACK_SIZE + 24; DOCARGS_5
# define UNDOCARGS_0
# define UNDOCARGS_1 lwi r5, r1, AC_STACK_SIZE + 4;
# define UNDOCARGS_2 UNDOCARGS_1 lwi r6, r1, AC_STACK_SIZE + 8;
# define UNDOCARGS_3 UNDOCARGS_2 lwi r7, r1, AC_STACK_SIZE + 12;
# define UNDOCARGS_4 UNDOCARGS_3 lwi r8, r1, AC_STACK_SIZE + 16;
# define UNDOCARGS_5 UNDOCARGS_4 lwi r9, r1, AC_STACK_SIZE + 20;
# define UNDOCARGS_6 UNDOCARGS_5 lwi r10, r1, AC_STACK_SIZE + 24;
# ifdef PIC
# define PSEUDO_JMP(sym) brlid r15, sym##@PLTPC; addk r0, r0, r0
# else
# define PSEUDO_JMP(sym) brlid r15, sym; addk r0, r0, r0
# endif
# ifdef IS_IN_libpthread
# define CENABLE PSEUDO_JMP (__pthread_enable_asynccancel)
# define CDISABLE PSEUDO_JMP (__pthread_disable_asynccancel)
# define __local_multiple_threads __pthread_multiple_threads
# elif !defined NOT_IN_libc
# define CENABLE PSEUDO_JMP (__libc_enable_asynccancel)
# define CDISABLE PSEUDO_JMP (__libc_disable_asynccancel)
# define __local_multiple_threads __libc_multiple_threads
# elif defined IS_IN_librt
# define CENABLE PSEUDO_JMP (__librt_enable_asynccancel)
# define CDISABLE PSEUDO_JMP (__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
# if !defined PIC
# define SINGLE_THREAD_P(reg) lwi reg, r0, __local_multiple_threads;
# else
# define SINGLE_THREAD_P(reg) \
mfs reg, rpc; \
addik reg, reg, _GLOBAL_OFFSET_TABLE_+8; \
lwi reg, reg, __local_multiple_threads@GOT; \
lwi reg, reg, 0;
# endif
# endif
# else
# ifndef __ASSEMBLER__
# define SINGLE_THREAD_P \
__builtin_expect (THREAD_GETMEM (THREAD_SELF, \
header.multiple_threads) == 0, 1)
# else
# define SINGLE_THREAD_P(reg) \
lwi reg, r0, MULTIPLE_THREADS_OFFSET(reg)
# endif
# endif
#elif !defined __ASSEMBLER__
# 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
|