2 * Copyright (c) 2000-2005 by Hewlett-Packard Company. All rights reserved.
4 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
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.
16 #include "private/gc_priv.h"
18 # if defined(THREAD_LOCAL_ALLOC)
20 #include "private/thread_local_alloc.h"
21 #include "gc_inline.h"
25 #if defined(USE_COMPILER_TLS)
27 #elif defined(USE_WIN32_COMPILER_TLS)
30 GC_key_t GC_thread_key;
32 static GC_bool keys_initialized;
34 /* Return a single nonempty freelist fl to the global one pointed to */
37 static void return_single_freelist(void *fl, void **gfl)
44 GC_ASSERT(GC_size(fl) == GC_size(*gfl));
46 for (qptr = &(obj_link(fl)), q = *qptr;
47 (word)q >= HBLKSIZE; qptr = &(obj_link(q)), q = *qptr);
54 /* Recover the contents of the freelist array fl into the global one gfl.*/
55 /* We hold the allocator lock. */
56 static void return_freelists(void **fl, void **gfl)
60 for (i = 1; i < TINY_FREELISTS; ++i) {
61 if ((word)(fl[i]) >= HBLKSIZE) {
62 return_single_freelist(fl[i], gfl+i);
64 /* Clear fl[i], since the thread structure may hang around. */
65 /* Do it in a way that is likely to trap if we access it. */
66 fl[i] = (ptr_t)HBLKSIZE;
68 /* The 0 granule freelist really contains 1 granule objects. */
69 # ifdef GC_GCJ_SUPPORT
70 if (fl[0] == ERROR_FL) return;
72 if ((word)(fl[0]) >= HBLKSIZE) {
73 return_single_freelist(fl[0], gfl+1);
77 /* Each thread structure must be initialized. */
78 /* This call must be made from the new thread. */
79 void GC_init_thread_local(GC_tlfs p)
83 GC_ASSERT(I_HOLD_LOCK());
84 if (!keys_initialized) {
85 if (0 != GC_key_create(&GC_thread_key, 0)) {
86 ABORT("Failed to create key for local allocator");
88 keys_initialized = TRUE;
90 if (0 != GC_setspecific(GC_thread_key, p)) {
91 ABORT("Failed to set thread specific allocation pointers");
93 for (i = 1; i < TINY_FREELISTS; ++i) {
94 p -> ptrfree_freelists[i] = (void *)1;
95 p -> normal_freelists[i] = (void *)1;
96 # ifdef GC_GCJ_SUPPORT
97 p -> gcj_freelists[i] = (void *)1;
100 /* Set up the size 0 free lists. */
101 /* We now handle most of them like regular free lists, to ensure */
102 /* That explicit deallocation works. However, allocation of a */
103 /* size 0 "gcj" object is always an error. */
104 p -> ptrfree_freelists[0] = (void *)1;
105 p -> normal_freelists[0] = (void *)1;
106 # ifdef GC_GCJ_SUPPORT
107 p -> gcj_freelists[0] = ERROR_FL;
111 #ifdef GC_GCJ_SUPPORT
112 extern void ** GC_gcjobjfreelist;
115 /* We hold the allocator lock. */
116 void GC_destroy_thread_local(GC_tlfs p)
118 /* We currently only do this from the thread itself or from */
119 /* the fork handler for a child process. */
121 GC_ASSERT(GC_getspecific(GC_thread_key) == (void *)p);
123 return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
124 return_freelists(p -> normal_freelists, GC_objfreelist);
125 # ifdef GC_GCJ_SUPPORT
126 return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
130 #if defined(GC_ASSERTIONS) && defined(GC_PTHREADS) && !defined(CYGWIN32) \
131 && !defined(GC_WIN32_PTHREADS)
132 # include <pthread.h>
133 extern char * GC_lookup_thread(pthread_t id);
136 #if defined(GC_ASSERTIONS) && defined(GC_WIN32_THREADS)
137 extern char * GC_lookup_thread(int id);
140 void * GC_malloc(size_t bytes)
142 size_t granules = ROUNDED_UP_GRANULES(bytes);
147 # if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC)
148 GC_key_t k = GC_thread_key;
149 if (EXPECT(0 == k, 0)) {
150 /* We haven't yet run GC_init_parallel. That means */
151 /* we also aren't locking, so this is fairly cheap. */
152 return GC_core_malloc(bytes);
154 tsd = GC_getspecific(k);
156 tsd = GC_getspecific(GC_thread_key);
158 # if defined(USE_PTHREAD_SPECIFIC) || defined(USE_WIN32_SPECIFIC)
159 if (EXPECT(0 == tsd, 0)) {
160 return GC_core_malloc(bytes);
163 GC_ASSERT(GC_is_initialized);
164 # ifdef GC_ASSERTIONS
165 /* We can't check tsd correctly, since we don't have access to */
166 /* the right declarations. But we can check that it's close. */
169 # if defined(GC_WIN32_THREADS)
170 char * me = (char *)GC_lookup_thread_inner(GetCurrentThreadId());
172 char * me = GC_lookup_thread(pthread_self());
174 GC_ASSERT((char *)tsd > me && (char *)tsd < me + 1000);
178 tiny_fl = ((GC_tlfs)tsd) -> normal_freelists;
179 GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
180 NORMAL, GC_core_malloc(bytes), obj_link(result)=0);
182 GC_err_printf("GC_malloc(%d) = %p : %d\n", bytes, result, GC_gc_no);
187 void * GC_malloc_atomic(size_t bytes)
189 size_t granules = ROUNDED_UP_GRANULES(bytes);
194 # if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC)
195 GC_key_t k = GC_thread_key;
196 if (EXPECT(0 == k, 0)) {
197 /* We haven't yet run GC_init_parallel. That means */
198 /* we also aren't locking, so this is fairly cheap. */
199 return GC_core_malloc(bytes);
201 tsd = GC_getspecific(k);
203 tsd = GC_getspecific(GC_thread_key);
205 # if defined(USE_PTHREAD_SPECIFIC) || defined(USE_WIN32_SPECIFIC)
206 if (EXPECT(0 == tsd, 0)) {
207 return GC_core_malloc(bytes);
210 GC_ASSERT(GC_is_initialized);
211 tiny_fl = ((GC_tlfs)tsd) -> ptrfree_freelists;
212 GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
213 PTRFREE, GC_core_malloc_atomic(bytes), 0/* no init */);
217 #ifdef GC_GCJ_SUPPORT
219 #include "include/gc_gcj.h"
222 extern GC_bool GC_gcj_malloc_initialized;
225 extern int GC_gcj_kind;
227 /* Gcj-style allocation without locks is extremely tricky. The */
228 /* fundamental issue is that we may end up marking a free list, which */
229 /* has freelist links instead of "vtable" pointers. That is usually */
230 /* OK, since the next object on the free list will be cleared, and */
231 /* will thus be interpreted as containg a zero descriptor. That's fine */
232 /* if the object has not yet been initialized. But there are */
233 /* interesting potential races. */
234 /* In the case of incremental collection, this seems hopeless, since */
235 /* the marker may run asynchronously, and may pick up the pointer to */
236 /* the next freelist entry (which it thinks is a vtable pointer), get */
237 /* suspended for a while, and then see an allocated object instead */
238 /* of the vtable. This made be avoidable with either a handshake with */
239 /* the collector or, probably more easily, by moving the free list */
240 /* links to the second word of each object. The latter isn't a */
241 /* universal win, since on architecture like Itanium, nonzero offsets */
242 /* are not necessarily free. And there may be cache fill order issues. */
243 /* For now, we punt with incremental GC. This probably means that */
244 /* incremental GC should be enabled before we fork a second thread. */
245 /* Unlike the other thread local allocation calls, we assume that the */
246 /* collector has been explicitly initialized. */
247 void * GC_gcj_malloc(size_t bytes,
248 void * ptr_to_struct_containing_descr)
250 if (GC_EXPECT(GC_incremental, 0)) {
251 return GC_core_gcj_malloc(bytes, ptr_to_struct_containing_descr);
253 size_t granules = ROUNDED_UP_GRANULES(bytes);
255 void **tiny_fl = ((GC_tlfs)GC_getspecific(GC_thread_key))
257 GC_ASSERT(GC_gcj_malloc_initialized);
258 GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
260 GC_core_gcj_malloc(bytes,
261 ptr_to_struct_containing_descr),
262 {AO_compiler_barrier();
263 *(void **)result = ptr_to_struct_containing_descr;});
264 /* This forces the initialization of the "method ptr". */
265 /* This is necessary to ensure some very subtle properties */
266 /* required if a GC is run in the middle of such an allocation. */
267 /* Here we implicitly also assume atomicity for the free list. */
268 /* and method pointer assignments. */
269 /* We must update the freelist before we store the pointer. */
270 /* Otherwise a GC at this point would see a corrupted */
272 /* A real memory barrier is not needed, since the */
273 /* action of stopping this thread will cause prior writes */
275 /* We assert that any concurrent marker will stop us. */
276 /* Thus it is impossible for a mark procedure to see the */
277 /* allocation of the next object, but to see this object */
278 /* still containing a free list pointer. Otherwise the */
279 /* marker, by misinterpreting the freelist link as a vtable */
280 /* pointer, might find a random "mark descriptor" in the next */
286 #endif /* GC_GCJ_SUPPORT */
288 /* The thread support layer must arrange to mark thread-local */
289 /* free lists explicitly, since the link field is often */
290 /* invisible to the marker. It knows hoe to find all threads; */
291 /* we take care of an individual thread freelist structure. */
292 void GC_mark_thread_local_fls_for(GC_tlfs p)
297 for (j = 1; j < TINY_FREELISTS; ++j) {
298 q = p -> ptrfree_freelists[j];
299 if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
300 q = p -> normal_freelists[j];
301 if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
302 # ifdef GC_GCJ_SUPPORT
303 q = p -> gcj_freelists[j];
304 if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
305 # endif /* GC_GCJ_SUPPORT */
309 #if defined(GC_ASSERTIONS)
310 /* Check that all thread-local free-lists in p are completely marked. */
311 void GC_check_tls_for(GC_tlfs p)
316 for (j = 1; j < TINY_FREELISTS; ++j) {
317 q = p -> ptrfree_freelists[j];
318 if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
319 q = p -> normal_freelists[j];
320 if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
321 # ifdef GC_GCJ_SUPPORT
322 q = p -> gcj_freelists[j];
323 if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
324 # endif /* GC_GCJ_SUPPORT */
327 #endif /* GC_ASSERTIONS */
329 # else /* !THREAD_LOCAL_ALLOC */
331 # define GC_destroy_thread_local(t)
333 # endif /* !THREAD_LOCAL_ALLOC */