diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2018-03-23 21:29:28 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2018-03-23 21:32:44 +0300 |
commit | effa229cd92c83abef1180155d48cd5e69f439f1 (patch) | |
tree | 966edb9606694e71a1d95f63567cf20c09d75c10 | |
parent | 877e5ea565b7afd1890f33c89c3cff148ccd32a6 (diff) | |
download | bdwgc-effa229cd92c83abef1180155d48cd5e69f439f1.tar.gz |
Avoid potential race between malloc_kind and mark_thread_local_fls_for
Issue #214 (bdwgc).
* include/gc_inline.h (GC_FAST_M_AO_STORE): New internal macro.
* include/gc_inline.h (GC_FAST_MALLOC_GRANS): Use GC_FAST_M_AO_STORE.
* thread_local_alloc.c [THREAD_LOCAL_ALLOC]
(GC_mark_thread_local_fls_for): Use AO_load to get _freelists[i][j]
value; add comment.
* thread_local_alloc.c [THREAD_LOCAL_ALLOC && GC_GCJ_SUPPORT]
(GC_mark_thread_local_fls_for): Use AO_load to get gcj_freelists[j].
-rw-r--r-- | include/gc_inline.h | 14 | ||||
-rw-r--r-- | thread_local_alloc.c | 6 |
2 files changed, 16 insertions, 4 deletions
diff --git a/include/gc_inline.h b/include/gc_inline.h index cafb71a5..f28dcfcc 100644 --- a/include/gc_inline.h +++ b/include/gc_inline.h @@ -83,6 +83,15 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL # define GC_malloc_kind_global GC_malloc_kind #endif +/* An internal macro to update the free list pointer atomically (if */ +/* the AO primitives are available) to avoid race with the marker. */ +#ifdef AO_HAVE_store +# define GC_FAST_M_AO_STORE(my_fl, next) \ + AO_store((volatile AO_t *)(my_fl), (AO_t)(next)) +#else +# define GC_FAST_M_AO_STORE(my_fl, next) (void)(*(my_fl) = (next)) +#endif + /* The ultimately general inline allocation macro. Allocate an object */ /* of size granules, putting the resulting pointer in result. Tiny_fl */ /* is a "tiny" free list array, which will be used first, if the size */ @@ -116,7 +125,7 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL > (num_direct) + GC_TINY_FREELISTS + 1, 1)) { \ next = *(void **)(my_entry); \ result = (void *)my_entry; \ - *my_fl = next; \ + GC_FAST_M_AO_STORE(my_fl, next); \ init; \ GC_PREFETCH_FOR_WRITE(next); \ GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \ @@ -129,7 +138,8 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL /* (GC_word)my_entry <= (num_direct) */ \ && my_entry != NULL) { \ /* Small counter value, not NULL */ \ - *my_fl = (char *)my_entry + (granules) + 1; \ + GC_FAST_M_AO_STORE(my_fl, (char *)my_entry \ + + (granules) + 1); \ result = (default_expr); \ break; \ } else { \ diff --git a/thread_local_alloc.c b/thread_local_alloc.c index aaebd3a8..3a04fbe8 100644 --- a/thread_local_alloc.c +++ b/thread_local_alloc.c @@ -266,13 +266,15 @@ GC_INNER void GC_mark_thread_local_fls_for(GC_tlfs p) for (j = 0; j < TINY_FREELISTS; ++j) { for (i = 0; i < THREAD_FREELISTS_KINDS; ++i) { - q = (ptr_t)p->_freelists[i][j]; + /* Load the pointer atomically as it might be updated */ + /* concurrently by GC_FAST_MALLOC_GRANS. */ + q = (ptr_t)AO_load((volatile AO_t *)&p->_freelists[i][j]); if ((word)q > HBLKSIZE) GC_set_fl_marks(q); } # ifdef GC_GCJ_SUPPORT if (EXPECT(j > 0, TRUE)) { - q = (ptr_t)p->gcj_freelists[j]; + q = (ptr_t)AO_load((volatile AO_t *)&p->gcj_freelists[j]); if ((word)q > HBLKSIZE) GC_set_fl_marks(q); } |