~ubuntu-branches/ubuntu/raring/boost-build/raring

« back to all changes in this revision

Viewing changes to jam_src/boehm_gc/thread_local_alloc.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2008-08-06 00:38:31 UTC
  • mfrom: (4.1.1 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080806003831-zr65893244swds0b
Tags: 2.0-m12-2
* debian/rules: Do not install /etc/user-config.jam.
* debian/site-config.jam: New.  Install into /etc instead of empty
  example.  Closes: #493323.

* debian/control: Update homepage.  Update description.  Closes:
  #493510.  Update Standards-Version to 3.8.0; no changes.

* debian/compat: New.  Set compat level to 7.
* debian/rules: Remove DH_COMPAT setting.
* debian/control: Change debhelper build-dep to version >= 7.

* debian/control: Remove docbook-to-man, bison from build-deps.

* debian/rules: Clean up upstream source by removing debian/conffiles.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * Copyright (c) 2000-2005 by Hewlett-Packard Company.  All rights reserved.
 
3
 *
 
4
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 
5
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 
6
 *
 
7
 * Permission is hereby granted to use or copy this program
 
8
 * for any purpose,  provided the above notices are retained on all copies.
 
9
 * Permission to modify the code and to distribute modified code is granted,
 
10
 * provided the above notices are retained, and a notice that the code was
 
11
 * modified is included with the above copyright notice.
 
12
 */
 
13
#include "private/gc_priv.h"
 
14
 
 
15
# if defined(THREAD_LOCAL_ALLOC)
 
16
 
 
17
#include "private/thread_local_alloc.h"
 
18
#include "gc_inline.h"
 
19
 
 
20
# include <stdlib.h>
 
21
 
 
22
#if defined(USE_COMPILER_TLS)
 
23
  __thread
 
24
#elif defined(USE_WIN32_COMPILER_TLS)
 
25
  __declspec(thread)
 
26
#endif
 
27
GC_key_t GC_thread_key;
 
28
 
 
29
static GC_bool keys_initialized;
 
30
 
 
31
/* Return a single nonempty freelist fl to the global one pointed to    */
 
32
/* by gfl.      */
 
33
 
 
34
static void return_single_freelist(void *fl, void **gfl)
 
35
{
 
36
    void *q, **qptr;
 
37
 
 
38
    if (*gfl == 0) {
 
39
      *gfl = fl;
 
40
    } else {
 
41
      GC_ASSERT(GC_size(fl) == GC_size(*gfl));
 
42
      /* Concatenate: */
 
43
        for (qptr = &(obj_link(fl)), q = *qptr;
 
44
             (word)q >= HBLKSIZE; qptr = &(obj_link(q)), q = *qptr);
 
45
        GC_ASSERT(0 == q);
 
46
        *qptr = *gfl;
 
47
        *gfl = fl;
 
48
    }
 
49
}
 
50
 
 
51
/* Recover the contents of the freelist array fl into the global one gfl.*/
 
52
/* We hold the allocator lock.                                          */
 
53
static void return_freelists(void **fl, void **gfl)
 
54
{
 
55
    int i;
 
56
 
 
57
    for (i = 1; i < TINY_FREELISTS; ++i) {
 
58
        if ((word)(fl[i]) >= HBLKSIZE) {
 
59
          return_single_freelist(fl[i], gfl+i);
 
60
        }
 
61
        /* Clear fl[i], since the thread structure may hang around.     */
 
62
        /* Do it in a way that is likely to trap if we access it.       */
 
63
        fl[i] = (ptr_t)HBLKSIZE;
 
64
    }
 
65
    /* The 0 granule freelist really contains 1 granule objects.        */
 
66
#   ifdef GC_GCJ_SUPPORT
 
67
      if (fl[0] == ERROR_FL) return;
 
68
#   endif
 
69
    if ((word)(fl[0]) >= HBLKSIZE) {
 
70
        return_single_freelist(fl[0], gfl+1);
 
71
    }
 
72
}
 
73
 
 
74
/* Each thread structure must be initialized.   */
 
75
/* This call must be made from the new thread.  */
 
76
/* Caller holds allocation lock.                */
 
77
void GC_init_thread_local(GC_tlfs p)
 
78
{
 
79
    int i;
 
80
 
 
81
    if (!keys_initialized) {
 
82
        if (0 != GC_key_create(&GC_thread_key, 0)) {
 
83
            ABORT("Failed to create key for local allocator");
 
84
        }
 
85
        keys_initialized = TRUE;
 
86
    }
 
87
    if (0 != GC_setspecific(GC_thread_key, p)) {
 
88
        ABORT("Failed to set thread specific allocation pointers");
 
89
    }
 
90
    for (i = 1; i < TINY_FREELISTS; ++i) {
 
91
        p -> ptrfree_freelists[i] = (void *)1;
 
92
        p -> normal_freelists[i] = (void *)1;
 
93
#       ifdef GC_GCJ_SUPPORT
 
94
          p -> gcj_freelists[i] = (void *)1;
 
95
#       endif
 
96
    }   
 
97
    /* Set up the size 0 free lists.    */
 
98
    /* We now handle most of them like regular free lists, to ensure    */
 
99
    /* That explicit deallocation works.  However, allocation of a      */
 
100
    /* size 0 "gcj" object is always an error.                          */
 
101
    p -> ptrfree_freelists[0] = (void *)1;
 
102
    p -> normal_freelists[0] = (void *)1;
 
103
#   ifdef GC_GCJ_SUPPORT
 
104
        p -> gcj_freelists[0] = ERROR_FL;
 
105
#   endif
 
106
}
 
107
 
 
108
#ifdef GC_GCJ_SUPPORT
 
109
  extern void ** GC_gcjobjfreelist;
 
110
#endif
 
111
 
 
112
/* We hold the allocator lock.  */
 
113
void GC_destroy_thread_local(GC_tlfs p)
 
114
{
 
115
    /* We currently only do this from the thread itself or from */
 
116
    /* the fork handler for a child process.                    */
 
117
#   ifndef HANDLE_FORK
 
118
      GC_ASSERT(GC_getspecific(GC_thread_key) == (void *)p);
 
119
#   endif
 
120
    return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
 
121
    return_freelists(p -> normal_freelists, GC_objfreelist);
 
122
#   ifdef GC_GCJ_SUPPORT
 
123
        return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
 
124
#   endif
 
125
}
 
126
 
 
127
#if defined(GC_ASSERTIONS) && defined(GC_PTHREADS) && !defined(CYGWIN32) \
 
128
    && !defined(GC_WIN32_PTHREADS)
 
129
# include <pthread.h>
 
130
  extern char * GC_lookup_thread(pthread_t id);
 
131
#endif
 
132
 
 
133
#if defined(GC_ASSERTIONS) && defined(GC_WIN32_THREADS)
 
134
  extern char * GC_lookup_thread(int id);
 
135
#endif
 
136
 
 
137
void * GC_malloc(size_t bytes)
 
138
{
 
139
    size_t granules = ROUNDED_UP_GRANULES(bytes);
 
140
    void *tsd;
 
141
    void *result;
 
142
    void **tiny_fl;
 
143
 
 
144
#   if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
 
145
      GC_key_t k = GC_thread_key;
 
146
      if (EXPECT(0 == k, 0)) {
 
147
        /* We haven't yet run GC_init_parallel.  That means     */
 
148
        /* we also aren't locking, so this is fairly cheap.     */
 
149
        return GC_core_malloc(bytes);
 
150
      }
 
151
      tsd = GC_getspecific(k);
 
152
#   else
 
153
      GC_ASSERT(GC_is_initialized);
 
154
      tsd = GC_getspecific(GC_thread_key);
 
155
#   endif
 
156
#   if defined(REDIRECT_MALLOC) && defined(USE_PTHREAD_SPECIFIC)
 
157
      if (EXPECT(NULL == tsd, 0)) {
 
158
        return GC_core_malloc(bytes);
 
159
      }
 
160
#   endif
 
161
#   ifdef GC_ASSERTIONS
 
162
      /* We can't check tsd correctly, since we don't have access to    */
 
163
      /* the right declarations.  But we can check that it's close.     */
 
164
      LOCK();
 
165
      {
 
166
#       if defined(GC_WIN32_THREADS)
 
167
          char * me = (char *)GC_lookup_thread_inner(GetCurrentThreadId());
 
168
#       else
 
169
          char * me = GC_lookup_thread(pthread_self());
 
170
#       endif
 
171
        GC_ASSERT((char *)tsd > me && (char *)tsd < me + 1000);
 
172
      }
 
173
      UNLOCK();
 
174
#   endif
 
175
    tiny_fl = ((GC_tlfs)tsd) -> normal_freelists;
 
176
    GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
 
177
                         NORMAL, GC_core_malloc(bytes), obj_link(result)=0);
 
178
    return result;
 
179
}
 
180
 
 
181
void * GC_malloc_atomic(size_t bytes)
 
182
{
 
183
    size_t granules = ROUNDED_UP_GRANULES(bytes);
 
184
    void *result;
 
185
    void **tiny_fl;
 
186
 
 
187
    GC_ASSERT(GC_is_initialized);
 
188
    tiny_fl = ((GC_tlfs)GC_getspecific(GC_thread_key))
 
189
                                        -> ptrfree_freelists;
 
190
    GC_FAST_MALLOC_GRANS(result, bytes, tiny_fl, DIRECT_GRANULES,
 
191
                         PTRFREE, GC_core_malloc_atomic(bytes), 0/* no init */);
 
192
    return result;
 
193
}
 
194
 
 
195
#ifdef GC_GCJ_SUPPORT
 
196
 
 
197
#include "include/gc_gcj.h"
 
198
 
 
199
#ifdef GC_ASSERTIONS
 
200
  extern GC_bool GC_gcj_malloc_initialized;
 
201
#endif
 
202
 
 
203
extern int GC_gcj_kind;
 
204
 
 
205
/* Gcj-style allocation without locks is extremely tricky.  The         */
 
206
/* fundamental issue is that we may end up marking a free list, which   */
 
207
/* has freelist links instead of "vtable" pointers.  That is usually    */
 
208
/* OK, since the next object on the free list will be cleared, and      */
 
209
/* will thus be interpreted as containg a zero descriptor.  That's fine */
 
210
/* if the object has not yet been initialized.  But there are           */
 
211
/* interesting potential races.                                         */
 
212
/* In the case of incremental collection, this seems hopeless, since    */
 
213
/* the marker may run asynchronously, and may pick up the pointer to    */
 
214
/* the next freelist entry (which it thinks is a vtable pointer), get   */
 
215
/* suspended for a while, and then see an allocated object instead      */
 
216
/* of the vtable.  This made be avoidable with either a handshake with  */
 
217
/* the collector or, probably more easily, by moving the free list      */
 
218
/* links to the second word of each object.  The latter isn't a         */
 
219
/* universal win, since on architecture like Itanium, nonzero offsets   */
 
220
/* are not necessarily free.  And there may be cache fill order issues. */
 
221
/* For now, we punt with incremental GC.  This probably means that      */
 
222
/* incremental GC should be enabled before we fork a second thread.     */
 
223
void * GC_gcj_malloc(size_t bytes,
 
224
                     void * ptr_to_struct_containing_descr)
 
225
{
 
226
  if (GC_EXPECT(GC_incremental, 0)) {
 
227
    return GC_core_gcj_malloc(bytes, ptr_to_struct_containing_descr);
 
228
  } else {
 
229
    size_t granules = ROUNDED_UP_GRANULES(bytes);
 
230
    void *result;
 
231
    void **tiny_fl = ((GC_tlfs)GC_getspecific(GC_thread_key))
 
232
                                        -> gcj_freelists;
 
233
    GC_ASSERT(GC_gcj_malloc_initialized);
 
234
    GC_FAST_MALLOC_GRANS(result, bytes, tiny_fl, DIRECT_GRANULES,
 
235
                         GC_gcj_kind,
 
236
                         GC_core_gcj_malloc(bytes,
 
237
                                            ptr_to_struct_containing_descr),
 
238
                         {AO_compiler_barrier();
 
239
                          *(void **)result = ptr_to_struct_containing_descr;});
 
240
        /* This forces the initialization of the "method ptr".          */
 
241
        /* This is necessary to ensure some very subtle properties      */
 
242
        /* required if a GC is run in the middle of such an allocation. */
 
243
        /* Here we implicitly also assume atomicity for the free list.  */
 
244
        /* and method pointer assignments.                              */
 
245
        /* We must update the freelist before we store the pointer.     */
 
246
        /* Otherwise a GC at this point would see a corrupted           */
 
247
        /* free list.                                                   */
 
248
        /* A real memory barrier is not needed, since the               */
 
249
        /* action of stopping this thread will cause prior writes       */
 
250
        /* to complete.                                                 */
 
251
        /* We assert that any concurrent marker will stop us.           */
 
252
        /* Thus it is impossible for a mark procedure to see the        */
 
253
        /* allocation of the next object, but to see this object        */
 
254
        /* still containing a free list pointer.  Otherwise the         */
 
255
        /* marker, by misinterpreting the freelist link as a vtable     */
 
256
        /* pointer, might find a random "mark descriptor" in the next   */
 
257
        /* object.                                                      */
 
258
    return result;
 
259
  }
 
260
}
 
261
 
 
262
#endif /* GC_GCJ_SUPPORT */
 
263
 
 
264
/* The thread support layer must arrange to mark thread-local   */
 
265
/* free lists explicitly, since the link field is often         */
 
266
/* invisible to the marker.  It knows hoe to find all threads;  */
 
267
/* we take care of an individual thread freelist structure.     */
 
268
void GC_mark_thread_local_fls_for(GC_tlfs p)
 
269
{
 
270
    ptr_t q;
 
271
    int j;
 
272
    
 
273
    for (j = 1; j < TINY_FREELISTS; ++j) {
 
274
      q = p -> ptrfree_freelists[j];
 
275
      if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
 
276
      q = p -> normal_freelists[j];
 
277
      if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
 
278
#     ifdef GC_GCJ_SUPPORT
 
279
        q = p -> gcj_freelists[j];
 
280
        if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
 
281
#     endif /* GC_GCJ_SUPPORT */
 
282
    }
 
283
}
 
284
 
 
285
#if defined(GC_ASSERTIONS)
 
286
    /* Check that all thread-local free-lists in p are completely marked.       */
 
287
    void GC_check_tls_for(GC_tlfs p)
 
288
    {
 
289
        ptr_t q;
 
290
        int j;
 
291
        
 
292
        for (j = 1; j < TINY_FREELISTS; ++j) {
 
293
          q = p -> ptrfree_freelists[j];
 
294
          if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
 
295
          q = p -> normal_freelists[j];
 
296
          if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
 
297
#         ifdef GC_GCJ_SUPPORT
 
298
            q = p -> gcj_freelists[j];
 
299
            if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
 
300
#         endif /* GC_GCJ_SUPPORT */
 
301
        }
 
302
    }
 
303
#endif /* GC_ASSERTIONS */
 
304
 
 
305
# else  /* !THREAD_LOCAL_ALLOC  */
 
306
 
 
307
#   define GC_destroy_thread_local(t)
 
308
 
 
309
# endif /* !THREAD_LOCAL_ALLOC */
 
310