summaryrefslogtreecommitdiff
path: root/thread_local_alloc.c
diff options
context:
space:
mode:
authorivmai <ivmai>2009-09-16 16:43:37 +0200
committerIvan Maidanski <ivmai@mail.ru>2011-07-26 19:06:46 +0200
commitdb2565100a193fa71336be2951b342ef7596f828 (patch)
tree4214eb726e4912fa34628655dc41ae247213caf8 /thread_local_alloc.c
parentd70b0280af3c3d53e2a794b26aa7a3127943b8c3 (diff)
2009-09-16 Ivan Maidanski <ivmai@mail.ru>
* ChangeLog: Remove trailing spaces at EOLn; insert blank lines where missed. * doc/README: Expand all tabs to spaces; remove trailing spaces at EOLn; remove multiple trailing blank lines. * doc/README.autoconf: Ditto. * doc/README.DGUX386: Ditto. * doc/README.environment: Ditto. * doc/README.macros: Ditto. * doc/README.win32: Ditto. * tests/test.c: Ditto. * tests/test_cpp.cc: Ditto. * backgraph.c: Ditto. * blacklst.c: Ditto. * checksums.c: Ditto. * darwin_stop_world.c: Ditto. * dbg_mlc.c: Ditto. * dyn_load.c: Ditto. * finalize.c: Ditto. * gc_dlopen.c: Ditto. * gcj_mlc.c: Ditto. * headers.c: Ditto. * mach_dep.c: Ditto. * malloc.c: Ditto. * mallocx.c: Ditto. * new_hblk.c: Ditto. * obj_map.c: Ditto. * ptr_chck.c: Ditto. * real_malloc.c: Ditto. * reclaim.c: Ditto. * stubborn.c: Ditto. * thread_local_alloc.c: Ditto. * typd_mlc.c: Ditto. * gc_cpp.cc: Ditto. * include/gc_allocator.h: Ditto. * include/gc_backptr.h: Ditto. * include/gc_config_macros.h: Ditto. * include/gc_cpp.h: Ditto. * include/gc_gcj.h: Ditto. * include/gc_inline.h: Ditto. * include/gc_mark.h: Ditto. * include/gc_pthread_redirects.h: Ditto. * include/gc_typed.h: Ditto. * include/gc_version.h: Ditto. * include/javaxfc.h: Ditto. * include/new_gc_alloc.h: Ditto. * include/private/darwin_semaphore.h: Ditto. * include/private/dbg_mlc.h: Ditto. * include/private/gc_hdrs.h: Ditto. * include/private/gc_locks.h: Ditto. * include/private/gc_pmark.h: Ditto. * include/private/gcconfig.h: Ditto. * include/private/pthread_support.h: Ditto. * include/private/thread_local_alloc.h: Ditto. * darwin_stop_world.c: Add copyright header. * include/gc_backptr.h: Ditto. * include/gc_config_macros.h: Ditto. * include/gc_pthread_redirects.h: Ditto. * include/gc_version.h: Ditto. * include/javaxfc.h: Ditto. * include/private/darwin_semaphore.h: Ditto. * include/private/pthread_support.h: Ditto. * gc_cpp.cc: Make copyright header uniform across the package. * include/gc_cpp.h: Ditto.
Diffstat (limited to 'thread_local_alloc.c')
-rw-r--r--thread_local_alloc.c241
1 files changed, 120 insertions, 121 deletions
diff --git a/thread_local_alloc.c b/thread_local_alloc.c
index db217c2..f45b08d 100644
--- a/thread_local_alloc.c
+++ b/thread_local_alloc.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2000-2005 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
@@ -32,8 +32,8 @@ GC_key_t GC_thread_key;
static GC_bool keys_initialized;
-/* Return a single nonempty freelist fl to the global one pointed to */
-/* by gfl. */
+/* Return a single nonempty freelist fl to the global one pointed to */
+/* by gfl. */
static void return_single_freelist(void *fl, void **gfl)
{
@@ -44,30 +44,30 @@ static void return_single_freelist(void *fl, void **gfl)
} else {
GC_ASSERT(GC_size(fl) == GC_size(*gfl));
/* Concatenate: */
- qptr = &(obj_link(fl));
- while ((word)(q = *qptr) >= HBLKSIZE)
- qptr = &(obj_link(q));
- GC_ASSERT(0 == q);
- *qptr = *gfl;
- *gfl = fl;
+ qptr = &(obj_link(fl));
+ while ((word)(q = *qptr) >= HBLKSIZE)
+ qptr = &(obj_link(q));
+ GC_ASSERT(0 == q);
+ *qptr = *gfl;
+ *gfl = fl;
}
}
/* Recover the contents of the freelist array fl into the global one gfl.*/
-/* We hold the allocator lock. */
+/* We hold the allocator lock. */
static void return_freelists(void **fl, void **gfl)
{
int i;
for (i = 1; i < TINY_FREELISTS; ++i) {
- if ((word)(fl[i]) >= HBLKSIZE) {
- return_single_freelist(fl[i], gfl+i);
- }
- /* Clear fl[i], since the thread structure may hang around. */
- /* Do it in a way that is likely to trap if we access it. */
- fl[i] = (ptr_t)HBLKSIZE;
+ if ((word)(fl[i]) >= HBLKSIZE) {
+ return_single_freelist(fl[i], gfl+i);
+ }
+ /* Clear fl[i], since the thread structure may hang around. */
+ /* Do it in a way that is likely to trap if we access it. */
+ fl[i] = (ptr_t)HBLKSIZE;
}
- /* The 0 granule freelist really contains 1 granule objects. */
+ /* The 0 granule freelist really contains 1 granule objects. */
# ifdef GC_GCJ_SUPPORT
if (fl[0] == ERROR_FL) return;
# endif
@@ -76,33 +76,33 @@ static void return_freelists(void **fl, void **gfl)
}
}
-/* Each thread structure must be initialized. */
-/* This call must be made from the new thread. */
+/* Each thread structure must be initialized. */
+/* This call must be made from the new thread. */
void GC_init_thread_local(GC_tlfs p)
{
int i;
GC_ASSERT(I_HOLD_LOCK());
if (!keys_initialized) {
- if (0 != GC_key_create(&GC_thread_key, 0)) {
- ABORT("Failed to create key for local allocator");
+ if (0 != GC_key_create(&GC_thread_key, 0)) {
+ ABORT("Failed to create key for local allocator");
}
- keys_initialized = TRUE;
+ keys_initialized = TRUE;
}
if (0 != GC_setspecific(GC_thread_key, p)) {
- ABORT("Failed to set thread specific allocation pointers");
+ ABORT("Failed to set thread specific allocation pointers");
}
for (i = 1; i < TINY_FREELISTS; ++i) {
- p -> ptrfree_freelists[i] = (void *)(word)1;
- p -> normal_freelists[i] = (void *)(word)1;
-# ifdef GC_GCJ_SUPPORT
- p -> gcj_freelists[i] = (void *)(word)1;
-# endif
- }
- /* Set up the size 0 free lists. */
- /* We now handle most of them like regular free lists, to ensure */
- /* That explicit deallocation works. However, allocation of a */
- /* size 0 "gcj" object is always an error. */
+ p -> ptrfree_freelists[i] = (void *)(word)1;
+ p -> normal_freelists[i] = (void *)(word)1;
+# ifdef GC_GCJ_SUPPORT
+ p -> gcj_freelists[i] = (void *)(word)1;
+# endif
+ }
+ /* Set up the size 0 free lists. */
+ /* We now handle most of them like regular free lists, to ensure */
+ /* That explicit deallocation works. However, allocation of a */
+ /* size 0 "gcj" object is always an error. */
p -> ptrfree_freelists[0] = (void *)(word)1;
p -> normal_freelists[0] = (void *)(word)1;
# ifdef GC_GCJ_SUPPORT
@@ -114,18 +114,18 @@ void GC_init_thread_local(GC_tlfs p)
extern void ** GC_gcjobjfreelist;
#endif
-/* We hold the allocator lock. */
+/* We hold the allocator lock. */
void GC_destroy_thread_local(GC_tlfs p)
{
- /* We currently only do this from the thread itself or from */
- /* the fork handler for a child process. */
+ /* We currently only do this from the thread itself or from */
+ /* the fork handler for a child process. */
# ifndef HANDLE_FORK
GC_ASSERT(GC_getspecific(GC_thread_key) == (void *)p);
# endif
return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
return_freelists(p -> normal_freelists, GC_objfreelist);
# ifdef GC_GCJ_SUPPORT
- return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
+ return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
# endif
}
@@ -149,9 +149,9 @@ GC_API void * GC_CALL GC_malloc(size_t bytes)
# if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC)
GC_key_t k = GC_thread_key;
if (EXPECT(0 == k, 0)) {
- /* We haven't yet run GC_init_parallel. That means */
- /* we also aren't locking, so this is fairly cheap. */
- return GC_core_malloc(bytes);
+ /* We haven't yet run GC_init_parallel. That means */
+ /* we also aren't locking, so this is fairly cheap. */
+ return GC_core_malloc(bytes);
}
tsd = GC_getspecific(k);
# else
@@ -159,30 +159,30 @@ GC_API void * GC_CALL GC_malloc(size_t bytes)
# endif
# if defined(USE_PTHREAD_SPECIFIC) || defined(USE_WIN32_SPECIFIC)
if (EXPECT(0 == tsd, 0)) {
- return GC_core_malloc(bytes);
+ return GC_core_malloc(bytes);
}
# endif
GC_ASSERT(GC_is_initialized);
# ifdef GC_ASSERTIONS
- /* We can't check tsd correctly, since we don't have access to */
- /* the right declarations. But we can check that it's close. */
+ /* We can't check tsd correctly, since we don't have access to */
+ /* the right declarations. But we can check that it's close. */
LOCK();
{
-# if defined(GC_WIN32_THREADS)
- char * me = (char *)GC_lookup_thread_inner(GetCurrentThreadId());
+# if defined(GC_WIN32_THREADS)
+ char * me = (char *)GC_lookup_thread_inner(GetCurrentThreadId());
# else
- char * me = GC_lookup_thread(pthread_self());
-# endif
+ char * me = GC_lookup_thread(pthread_self());
+# endif
GC_ASSERT((char *)tsd > me && (char *)tsd < me + 1000);
}
UNLOCK();
# endif
tiny_fl = ((GC_tlfs)tsd) -> normal_freelists;
GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
- NORMAL, GC_core_malloc(bytes), obj_link(result)=0);
+ NORMAL, GC_core_malloc(bytes), obj_link(result)=0);
# ifdef LOG_ALLOCS
GC_err_printf("GC_malloc(%u) = %p : %u\n",
- (unsigned)bytes, result, (unsigned)GC_gc_no);
+ (unsigned)bytes, result, (unsigned)GC_gc_no);
# endif
return result;
}
@@ -197,9 +197,9 @@ GC_API void * GC_CALL GC_malloc_atomic(size_t bytes)
# if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC)
GC_key_t k = GC_thread_key;
if (EXPECT(0 == k, 0)) {
- /* We haven't yet run GC_init_parallel. That means */
- /* we also aren't locking, so this is fairly cheap. */
- return GC_core_malloc(bytes);
+ /* We haven't yet run GC_init_parallel. That means */
+ /* we also aren't locking, so this is fairly cheap. */
+ return GC_core_malloc(bytes);
}
tsd = GC_getspecific(k);
# else
@@ -207,13 +207,13 @@ GC_API void * GC_CALL GC_malloc_atomic(size_t bytes)
# endif
# if defined(USE_PTHREAD_SPECIFIC) || defined(USE_WIN32_SPECIFIC)
if (EXPECT(0 == tsd, 0)) {
- return GC_core_malloc(bytes);
+ return GC_core_malloc(bytes);
}
# endif
GC_ASSERT(GC_is_initialized);
tiny_fl = ((GC_tlfs)tsd) -> ptrfree_freelists;
GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES, PTRFREE,
- GC_core_malloc_atomic(bytes), (void)0 /* no init */);
+ GC_core_malloc_atomic(bytes), (void)0 /* no init */);
return result;
}
@@ -229,28 +229,28 @@ GC_API void * GC_CALL GC_malloc_atomic(size_t bytes)
extern int GC_gcj_kind;
-/* Gcj-style allocation without locks is extremely tricky. The */
-/* fundamental issue is that we may end up marking a free list, which */
-/* has freelist links instead of "vtable" pointers. That is usually */
-/* OK, since the next object on the free list will be cleared, and */
-/* will thus be interpreted as containing a zero descriptor. That's */
-/* fine if the object has not yet been initialized. But there are */
-/* interesting potential races. */
-/* In the case of incremental collection, this seems hopeless, since */
-/* the marker may run asynchronously, and may pick up the pointer to */
-/* the next freelist entry (which it thinks is a vtable pointer), get */
-/* suspended for a while, and then see an allocated object instead */
-/* of the vtable. This may be avoidable with either a handshake with */
-/* the collector or, probably more easily, by moving the free list */
-/* links to the second word of each object. The latter isn't a */
-/* universal win, since on architecture like Itanium, nonzero offsets */
-/* are not necessarily free. And there may be cache fill order issues. */
-/* For now, we punt with incremental GC. This probably means that */
-/* incremental GC should be enabled before we fork a second thread. */
-/* Unlike the other thread local allocation calls, we assume that the */
-/* collector has been explicitly initialized. */
+/* Gcj-style allocation without locks is extremely tricky. The */
+/* fundamental issue is that we may end up marking a free list, which */
+/* has freelist links instead of "vtable" pointers. That is usually */
+/* OK, since the next object on the free list will be cleared, and */
+/* will thus be interpreted as containing a zero descriptor. That's */
+/* fine if the object has not yet been initialized. But there are */
+/* interesting potential races. */
+/* In the case of incremental collection, this seems hopeless, since */
+/* the marker may run asynchronously, and may pick up the pointer to */
+/* the next freelist entry (which it thinks is a vtable pointer), get */
+/* suspended for a while, and then see an allocated object instead */
+/* of the vtable. This may be avoidable with either a handshake with */
+/* the collector or, probably more easily, by moving the free list */
+/* links to the second word of each object. The latter isn't a */
+/* universal win, since on architecture like Itanium, nonzero offsets */
+/* are not necessarily free. And there may be cache fill order issues. */
+/* For now, we punt with incremental GC. This probably means that */
+/* incremental GC should be enabled before we fork a second thread. */
+/* Unlike the other thread local allocation calls, we assume that the */
+/* collector has been explicitly initialized. */
GC_API void * GC_CALL GC_gcj_malloc(size_t bytes,
- void * ptr_to_struct_containing_descr)
+ void * ptr_to_struct_containing_descr)
{
if (GC_EXPECT(GC_incremental, 0)) {
return GC_core_gcj_malloc(bytes, ptr_to_struct_containing_descr);
@@ -258,80 +258,79 @@ GC_API void * GC_CALL GC_gcj_malloc(size_t bytes,
size_t granules = ROUNDED_UP_GRANULES(bytes);
void *result;
void **tiny_fl = ((GC_tlfs)GC_getspecific(GC_thread_key))
- -> gcj_freelists;
+ -> gcj_freelists;
GC_ASSERT(GC_gcj_malloc_initialized);
GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
- GC_gcj_kind,
- GC_core_gcj_malloc(bytes,
- ptr_to_struct_containing_descr),
- {AO_compiler_barrier();
- *(void **)result = ptr_to_struct_containing_descr;});
- /* This forces the initialization of the "method ptr". */
- /* This is necessary to ensure some very subtle properties */
- /* required if a GC is run in the middle of such an allocation. */
- /* Here we implicitly also assume atomicity for the free list. */
- /* and method pointer assignments. */
- /* We must update the freelist before we store the pointer. */
- /* Otherwise a GC at this point would see a corrupted */
- /* free list. */
- /* A real memory barrier is not needed, since the */
- /* action of stopping this thread will cause prior writes */
- /* to complete. */
- /* We assert that any concurrent marker will stop us. */
- /* Thus it is impossible for a mark procedure to see the */
- /* allocation of the next object, but to see this object */
- /* still containing a free list pointer. Otherwise the */
- /* marker, by misinterpreting the freelist link as a vtable */
- /* pointer, might find a random "mark descriptor" in the next */
- /* object. */
+ GC_gcj_kind,
+ GC_core_gcj_malloc(bytes,
+ ptr_to_struct_containing_descr),
+ {AO_compiler_barrier();
+ *(void **)result = ptr_to_struct_containing_descr;});
+ /* This forces the initialization of the "method ptr". */
+ /* This is necessary to ensure some very subtle properties */
+ /* required if a GC is run in the middle of such an allocation. */
+ /* Here we implicitly also assume atomicity for the free list. */
+ /* and method pointer assignments. */
+ /* We must update the freelist before we store the pointer. */
+ /* Otherwise a GC at this point would see a corrupted */
+ /* free list. */
+ /* A real memory barrier is not needed, since the */
+ /* action of stopping this thread will cause prior writes */
+ /* to complete. */
+ /* We assert that any concurrent marker will stop us. */
+ /* Thus it is impossible for a mark procedure to see the */
+ /* allocation of the next object, but to see this object */
+ /* still containing a free list pointer. Otherwise the */
+ /* marker, by misinterpreting the freelist link as a vtable */
+ /* pointer, might find a random "mark descriptor" in the next */
+ /* object. */
return result;
}
}
#endif /* GC_GCJ_SUPPORT */
-/* The thread support layer must arrange to mark thread-local */
-/* free lists explicitly, since the link field is often */
-/* invisible to the marker. It knows how to find all threads; */
-/* we take care of an individual thread freelist structure. */
+/* The thread support layer must arrange to mark thread-local */
+/* free lists explicitly, since the link field is often */
+/* invisible to the marker. It knows how to find all threads; */
+/* we take care of an individual thread freelist structure. */
void GC_mark_thread_local_fls_for(GC_tlfs p)
{
ptr_t q;
int j;
-
+
for (j = 0; j < TINY_FREELISTS; ++j) {
q = p -> ptrfree_freelists[j];
if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
q = p -> normal_freelists[j];
if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
# ifdef GC_GCJ_SUPPORT
- if (j > 0) {
+ if (j > 0) {
q = p -> gcj_freelists[j];
if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
- }
+ }
# endif /* GC_GCJ_SUPPORT */
}
}
#if defined(GC_ASSERTIONS)
- /* Check that all thread-local free-lists in p are completely marked. */
+ /* Check that all thread-local free-lists in p are completely marked. */
void GC_check_tls_for(GC_tlfs p)
{
- ptr_t q;
- int j;
-
- for (j = 1; j < TINY_FREELISTS; ++j) {
- q = p -> ptrfree_freelists[j];
- if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
- q = p -> normal_freelists[j];
- if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
-# ifdef GC_GCJ_SUPPORT
- q = p -> gcj_freelists[j];
- if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
-# endif /* GC_GCJ_SUPPORT */
- }
+ ptr_t q;
+ int j;
+
+ for (j = 1; j < TINY_FREELISTS; ++j) {
+ q = p -> ptrfree_freelists[j];
+ if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
+ q = p -> normal_freelists[j];
+ if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
+# ifdef GC_GCJ_SUPPORT
+ q = p -> gcj_freelists[j];
+ if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
+# endif /* GC_GCJ_SUPPORT */
+ }
}
#endif /* GC_ASSERTIONS */
# endif /* THREAD_LOCAL_ALLOC */
-