Mercurial > hg > CbC > CbC_gcc
comparison libmudflap/mf-hooks3.c @ 0:a06113de4d67
first commit
author | kent <kent@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2009 14:47:48 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a06113de4d67 |
---|---|
1 /* Mudflap: narrow-pointer bounds-checking by tree rewriting. | |
2 Copyright (C) 2002, 2003, 2004, 2005, 2009 | |
3 Free Software Foundation, Inc. | |
4 Contributed by Frank Ch. Eigler <fche@redhat.com> | |
5 and Graydon Hoare <graydon@redhat.com> | |
6 | |
7 This file is part of GCC. | |
8 | |
9 GCC is free software; you can redistribute it and/or modify it under | |
10 the terms of the GNU General Public License as published by the Free | |
11 Software Foundation; either version 3, or (at your option) any later | |
12 version. | |
13 | |
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 Under Section 7 of GPL version 3, you are granted additional | |
20 permissions described in the GCC Runtime Library Exception, version | |
21 3.1, as published by the Free Software Foundation. | |
22 | |
23 You should have received a copy of the GNU General Public License and | |
24 a copy of the GCC Runtime Library Exception along with this program; | |
25 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
26 <http://www.gnu.org/licenses/>. */ | |
27 | |
28 | |
29 #include "config.h" | |
30 | |
31 #ifndef HAVE_SOCKLEN_T | |
32 #define socklen_t int | |
33 #endif | |
34 | |
35 /* These attempt to coax various unix flavours to declare all our | |
36 needed tidbits in the system headers. */ | |
37 #if !defined(__FreeBSD__) && !defined(__APPLE__) | |
38 #define _POSIX_SOURCE | |
39 #endif /* Some BSDs break <sys/socket.h> if this is defined. */ | |
40 #define _GNU_SOURCE | |
41 #define _XOPEN_SOURCE | |
42 #define _BSD_TYPES | |
43 #define __EXTENSIONS__ | |
44 #define _ALL_SOURCE | |
45 #define _LARGE_FILE_API | |
46 #define _XOPEN_SOURCE_EXTENDED 1 | |
47 | |
48 #include <string.h> | |
49 #include <stdio.h> | |
50 #include <stdlib.h> | |
51 #include <unistd.h> | |
52 #include <assert.h> | |
53 #include <errno.h> | |
54 #include <stdbool.h> | |
55 | |
56 #include "mf-runtime.h" | |
57 #include "mf-impl.h" | |
58 | |
59 #ifdef _MUDFLAP | |
60 #error "Do not compile this file with -fmudflap!" | |
61 #endif | |
62 | |
63 #ifndef LIBMUDFLAPTH | |
64 #error "pthreadstuff is to be included only in libmudflapth" | |
65 #endif | |
66 | |
67 /* ??? Why isn't this done once in the header files. */ | |
68 DECLARE(void *, malloc, size_t sz); | |
69 DECLARE(void, free, void *ptr); | |
70 DECLARE(int, pthread_create, pthread_t *thr, const pthread_attr_t *attr, | |
71 void * (*start) (void *), void *arg); | |
72 | |
73 | |
74 /* Multithreading support hooks. */ | |
75 | |
76 | |
77 #if !defined(HAVE_TLS) || defined(USE_EMUTLS) | |
78 /* We don't have TLS. Ordinarily we could use pthread keys, but since we're | |
79 commandeering malloc/free that presents a few problems. The first is that | |
80 we'll recurse from __mf_get_state to pthread_setspecific to malloc back to | |
81 __mf_get_state during thread startup. This can be solved with clever uses | |
82 of a mutex. The second problem is that thread shutdown is indistinguishable | |
83 from thread startup, since libpthread is deallocating our state variable. | |
84 I've no good solution for this. | |
85 | |
86 Which leaves us to handle this mess by totally by hand. */ | |
87 | |
88 /* Yes, we want this prime. If pthread_t is a pointer, it's almost always | |
89 page aligned, and if we use a smaller power of 2, this results in "%N" | |
90 being the worst possible hash -- all threads hash to zero. */ | |
91 #define LIBMUDFLAPTH_THREADS_MAX 1021 | |
92 | |
93 struct mf_thread_data | |
94 { | |
95 pthread_t self; | |
96 unsigned char used_p; | |
97 unsigned char state; | |
98 }; | |
99 | |
100 static struct mf_thread_data mf_thread_data[LIBMUDFLAPTH_THREADS_MAX]; | |
101 static pthread_mutex_t mf_thread_data_lock = PTHREAD_MUTEX_INITIALIZER; | |
102 | |
103 #define PTHREAD_HASH(p) ((unsigned long) (p) % LIBMUDFLAPTH_THREADS_MAX) | |
104 | |
105 static struct mf_thread_data * | |
106 __mf_find_threadinfo (int alloc) | |
107 { | |
108 pthread_t self = pthread_self (); | |
109 unsigned long hash = PTHREAD_HASH (self); | |
110 unsigned long rehash; | |
111 | |
112 #ifdef __alpha__ | |
113 /* Alpha has the loosest memory ordering rules of all. We need a memory | |
114 barrier to flush the reorder buffer before considering a *read* of a | |
115 shared variable. Since we're not always taking a lock, we have to do | |
116 this by hand. */ | |
117 __sync_synchronize (); | |
118 #endif | |
119 | |
120 rehash = hash; | |
121 while (1) | |
122 { | |
123 if (mf_thread_data[rehash].used_p && mf_thread_data[rehash].self == self) | |
124 return &mf_thread_data[rehash]; | |
125 | |
126 rehash += 7; | |
127 if (rehash >= LIBMUDFLAPTH_THREADS_MAX) | |
128 rehash -= LIBMUDFLAPTH_THREADS_MAX; | |
129 if (rehash == hash) | |
130 break; | |
131 } | |
132 | |
133 if (alloc) | |
134 { | |
135 pthread_mutex_lock (&mf_thread_data_lock); | |
136 | |
137 rehash = hash; | |
138 while (1) | |
139 { | |
140 if (!mf_thread_data[rehash].used_p) | |
141 { | |
142 mf_thread_data[rehash].self = self; | |
143 __sync_synchronize (); | |
144 mf_thread_data[rehash].used_p = 1; | |
145 | |
146 pthread_mutex_unlock (&mf_thread_data_lock); | |
147 return &mf_thread_data[rehash]; | |
148 } | |
149 | |
150 rehash += 7; | |
151 if (rehash >= LIBMUDFLAPTH_THREADS_MAX) | |
152 rehash -= LIBMUDFLAPTH_THREADS_MAX; | |
153 if (rehash == hash) | |
154 break; | |
155 } | |
156 | |
157 pthread_mutex_unlock (&mf_thread_data_lock); | |
158 } | |
159 | |
160 return NULL; | |
161 } | |
162 | |
163 enum __mf_state_enum | |
164 __mf_get_state (void) | |
165 { | |
166 struct mf_thread_data *data = __mf_find_threadinfo (0); | |
167 if (data) | |
168 return data->state; | |
169 | |
170 /* If we've never seen this thread before, consider it to be in the | |
171 reentrant state. The state gets reset to active for the main thread | |
172 in __mf_init, and for child threads in __mf_pthread_spawner. | |
173 | |
174 The trickiest bit here is that the LinuxThreads pthread_manager thread | |
175 should *always* be considered to be reentrant, so that none of our | |
176 hooks actually do anything. Why? Because that thread isn't a real | |
177 thread from the point of view of the thread library, and so lots of | |
178 stuff isn't initialized, leading to SEGV very quickly. Even calling | |
179 pthread_self is a bit suspect, but it happens to work. */ | |
180 | |
181 return reentrant; | |
182 } | |
183 | |
184 void | |
185 __mf_set_state (enum __mf_state_enum new_state) | |
186 { | |
187 struct mf_thread_data *data = __mf_find_threadinfo (1); | |
188 data->state = new_state; | |
189 } | |
190 #endif | |
191 | |
192 /* The following two functions are used only with __mf_opts.heur_std_data. | |
193 We're interested in recording the location of the thread-local errno | |
194 variable. | |
195 | |
196 Note that this doesn't handle TLS references in general; we have no | |
197 visibility into __tls_get_data for when that memory is allocated at | |
198 runtime. Hopefully we get to see the malloc or mmap operation that | |
199 eventually allocates the backing store. */ | |
200 | |
201 /* Describe the startup information for a new user thread. */ | |
202 struct mf_thread_start_info | |
203 { | |
204 /* The user's thread entry point and argument. */ | |
205 void * (*user_fn)(void *); | |
206 void *user_arg; | |
207 }; | |
208 | |
209 | |
210 static void | |
211 __mf_pthread_cleanup (void *arg) | |
212 { | |
213 if (__mf_opts.heur_std_data) | |
214 __mf_unregister (&errno, sizeof (errno), __MF_TYPE_GUESS); | |
215 | |
216 #if !defined(HAVE_TLS) || defined(USE_EMUTLS) | |
217 struct mf_thread_data *data = __mf_find_threadinfo (0); | |
218 if (data) | |
219 data->used_p = 0; | |
220 #endif | |
221 } | |
222 | |
223 | |
224 static void * | |
225 __mf_pthread_spawner (void *arg) | |
226 { | |
227 void *result = NULL; | |
228 | |
229 __mf_set_state (active); | |
230 | |
231 /* NB: We could use __MF_TYPE_STATIC here, but we guess that the thread | |
232 errno is coming out of some dynamically allocated pool that we already | |
233 know of as __MF_TYPE_HEAP. */ | |
234 if (__mf_opts.heur_std_data) | |
235 __mf_register (&errno, sizeof (errno), __MF_TYPE_GUESS, | |
236 "errno area (thread)"); | |
237 | |
238 /* We considered using pthread_key_t objects instead of these | |
239 cleanup stacks, but they were less cooperative with the | |
240 interposed malloc hooks in libmudflap. */ | |
241 /* ??? The pthread_key_t problem is solved above... */ | |
242 pthread_cleanup_push (__mf_pthread_cleanup, NULL); | |
243 | |
244 /* Extract given entry point and argument. */ | |
245 struct mf_thread_start_info *psi = arg; | |
246 void * (*user_fn)(void *) = psi->user_fn; | |
247 void *user_arg = psi->user_arg; | |
248 CALL_REAL (free, arg); | |
249 | |
250 result = (*user_fn)(user_arg); | |
251 | |
252 pthread_cleanup_pop (1 /* execute */); | |
253 | |
254 return result; | |
255 } | |
256 | |
257 | |
258 #if PIC | |
259 /* A special bootstrap variant. */ | |
260 int | |
261 __mf_0fn_pthread_create (pthread_t *thr, const pthread_attr_t *attr, | |
262 void * (*start) (void *), void *arg) | |
263 { | |
264 return -1; | |
265 } | |
266 #endif | |
267 | |
268 | |
269 #undef pthread_create | |
270 WRAPPER(int, pthread_create, pthread_t *thr, const pthread_attr_t *attr, | |
271 void * (*start) (void *), void *arg) | |
272 { | |
273 struct mf_thread_start_info *si; | |
274 | |
275 TRACE ("pthread_create\n"); | |
276 | |
277 /* Fill in startup-control fields. */ | |
278 si = CALL_REAL (malloc, sizeof (*si)); | |
279 si->user_fn = start; | |
280 si->user_arg = arg; | |
281 | |
282 /* Actually create the thread. */ | |
283 return CALL_REAL (pthread_create, thr, attr, __mf_pthread_spawner, si); | |
284 } |