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