OSDN Git Service

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