1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-15 18:20:42 +02:00

Move a lot of mark_space state to heap

This commit is contained in:
Andy Wingo 2022-04-18 20:56:48 +02:00
parent 119e273fa4
commit 3ee2009de9

View file

@ -104,13 +104,6 @@ struct gcobj {
}; };
struct mark_space { struct mark_space {
pthread_mutex_t lock;
pthread_cond_t collector_cond;
pthread_cond_t mutator_cond;
int collecting;
int multithreaded;
size_t active_mutator_count;
size_t mutator_count;
struct gcobj_freelists small_objects; struct gcobj_freelists small_objects;
// Unordered list of medium objects. // Unordered list of medium objects.
struct gcobj_free_medium *medium_objects; struct gcobj_free_medium *medium_objects;
@ -119,16 +112,24 @@ struct mark_space {
uintptr_t heap_base; uintptr_t heap_base;
size_t heap_size; size_t heap_size;
uintptr_t sweep; uintptr_t sweep;
struct handle *global_roots;
struct mutator_mark_buf *mutator_roots;
void *mem; void *mem;
size_t mem_size; size_t mem_size;
long count;
struct mutator *deactivated_mutators;
}; };
struct heap { struct heap {
struct mark_space mark_space; struct mark_space mark_space;
pthread_mutex_t lock;
pthread_cond_t collector_cond;
pthread_cond_t mutator_cond;
size_t size;
int collecting;
int multithreaded;
size_t active_mutator_count;
size_t mutator_count;
struct handle *global_roots;
struct mutator_mark_buf *mutator_roots;
long count;
struct mutator *deactivated_mutators;
struct tracer tracer; struct tracer tracer;
}; };
@ -157,9 +158,6 @@ static inline struct mark_space* heap_mark_space(struct heap *heap) {
static inline struct heap* mutator_heap(struct mutator *mutator) { static inline struct heap* mutator_heap(struct mutator *mutator) {
return mutator->heap; return mutator->heap;
} }
static inline struct mark_space* mutator_mark_space(struct mutator *mutator) {
return heap_mark_space(mutator_heap(mutator));
}
static inline struct gcobj_free** static inline struct gcobj_free**
get_small_object_freelist(struct gcobj_freelists *freelists, get_small_object_freelist(struct gcobj_freelists *freelists,
@ -216,61 +214,59 @@ static void clear_global_freelists(struct mark_space *space) {
space->medium_objects = NULL; space->medium_objects = NULL;
} }
static int space_has_multiple_mutators(struct mark_space *space) { static int heap_has_multiple_mutators(struct heap *heap) {
return atomic_load_explicit(&space->multithreaded, memory_order_relaxed); return atomic_load_explicit(&heap->multithreaded, memory_order_relaxed);
} }
static int mutators_are_stopping(struct mark_space *space) { static int mutators_are_stopping(struct heap *heap) {
return atomic_load_explicit(&space->collecting, memory_order_relaxed); return atomic_load_explicit(&heap->collecting, memory_order_relaxed);
} }
static inline void mark_space_lock(struct mark_space *space) { static inline void heap_lock(struct heap *heap) {
pthread_mutex_lock(&space->lock); pthread_mutex_lock(&heap->lock);
} }
static inline void mark_space_unlock(struct mark_space *space) { static inline void heap_unlock(struct heap *heap) {
pthread_mutex_unlock(&space->lock); pthread_mutex_unlock(&heap->lock);
} }
static void add_mutator(struct heap *heap, struct mutator *mut) { static void add_mutator(struct heap *heap, struct mutator *mut) {
mut->heap = heap; mut->heap = heap;
struct mark_space *space = heap_mark_space(heap); heap_lock(heap);
mark_space_lock(space);
// We have no roots. If there is a GC currently in progress, we have // We have no roots. If there is a GC currently in progress, we have
// nothing to add. Just wait until it's done. // nothing to add. Just wait until it's done.
while (mutators_are_stopping(space)) while (mutators_are_stopping(heap))
pthread_cond_wait(&space->mutator_cond, &space->lock); pthread_cond_wait(&heap->mutator_cond, &heap->lock);
if (space->mutator_count == 1) if (heap->mutator_count == 1)
space->multithreaded = 1; heap->multithreaded = 1;
space->active_mutator_count++; heap->active_mutator_count++;
space->mutator_count++; heap->mutator_count++;
mark_space_unlock(space); heap_unlock(heap);
} }
static void remove_mutator(struct heap *heap, struct mutator *mut) { static void remove_mutator(struct heap *heap, struct mutator *mut) {
mut->heap = NULL; mut->heap = NULL;
struct mark_space *space = heap_mark_space(heap); heap_lock(heap);
mark_space_lock(space); heap->active_mutator_count--;
space->active_mutator_count--; heap->mutator_count--;
space->mutator_count--;
// We have no roots. If there is a GC stop currently in progress, // We have no roots. If there is a GC stop currently in progress,
// maybe tell the controller it can continue. // maybe tell the controller it can continue.
if (mutators_are_stopping(space) && space->active_mutator_count == 0) if (mutators_are_stopping(heap) && heap->active_mutator_count == 0)
pthread_cond_signal(&space->collector_cond); pthread_cond_signal(&heap->collector_cond);
mark_space_unlock(space); heap_unlock(heap);
} }
static void request_mutators_to_stop(struct mark_space *space) { static void request_mutators_to_stop(struct heap *heap) {
ASSERT(!mutators_are_stopping(space)); ASSERT(!mutators_are_stopping(heap));
atomic_store_explicit(&space->collecting, 1, memory_order_relaxed); atomic_store_explicit(&heap->collecting, 1, memory_order_relaxed);
} }
static void allow_mutators_to_continue(struct mark_space *space) { static void allow_mutators_to_continue(struct heap *heap) {
ASSERT(mutators_are_stopping(space)); ASSERT(mutators_are_stopping(heap));
ASSERT(space->active_mutator_count == 0); ASSERT(heap->active_mutator_count == 0);
space->active_mutator_count++; heap->active_mutator_count++;
atomic_store_explicit(&space->collecting, 0, memory_order_relaxed); atomic_store_explicit(&heap->collecting, 0, memory_order_relaxed);
ASSERT(!mutators_are_stopping(space)); ASSERT(!mutators_are_stopping(heap));
pthread_cond_broadcast(&space->mutator_cond); pthread_cond_broadcast(&heap->mutator_cond);
} }
static void mutator_mark_buf_grow(struct mutator_mark_buf *buf) { static void mutator_mark_buf_grow(struct mutator_mark_buf *buf) {
@ -318,7 +314,6 @@ static void mutator_mark_buf_destroy(struct mutator_mark_buf *buf) {
// enqueue them directly, so we send them to the controller in a buffer. // enqueue them directly, so we send them to the controller in a buffer.
static void mark_stopping_mutator_roots(struct mutator *mut) { static void mark_stopping_mutator_roots(struct mutator *mut) {
struct heap *heap = mutator_heap(mut); struct heap *heap = mutator_heap(mut);
struct mark_space *space = heap_mark_space(heap);
struct mutator_mark_buf *local_roots = &mut->mark_buf; struct mutator_mark_buf *local_roots = &mut->mark_buf;
for (struct handle *h = mut->roots; h; h = h->next) { for (struct handle *h = mut->roots; h; h = h->next) {
struct gcobj *root = h->v; struct gcobj *root = h->v;
@ -328,10 +323,10 @@ static void mark_stopping_mutator_roots(struct mutator *mut) {
// Post to global linked-list of thread roots. // Post to global linked-list of thread roots.
struct mutator_mark_buf *next = struct mutator_mark_buf *next =
atomic_load_explicit(&space->mutator_roots, memory_order_acquire); atomic_load_explicit(&heap->mutator_roots, memory_order_acquire);
do { do {
local_roots->next = next; local_roots->next = next;
} while (!atomic_compare_exchange_weak(&space->mutator_roots, } while (!atomic_compare_exchange_weak(&heap->mutator_roots,
&next, local_roots)); &next, local_roots));
} }
@ -349,77 +344,76 @@ static void release_stopping_mutator_roots(struct mutator *mut) {
mutator_mark_buf_release(&mut->mark_buf); mutator_mark_buf_release(&mut->mark_buf);
} }
static void wait_for_mutators_to_stop(struct mark_space *space) { static void wait_for_mutators_to_stop(struct heap *heap) {
space->active_mutator_count--; heap->active_mutator_count--;
while (space->active_mutator_count) while (heap->active_mutator_count)
pthread_cond_wait(&space->collector_cond, &space->lock); pthread_cond_wait(&heap->collector_cond, &heap->lock);
} }
static void mark_inactive_mutators(struct mark_space *space) { static void mark_inactive_mutators(struct heap *heap) {
for (struct mutator *mut = space->deactivated_mutators; mut; mut = mut->next) for (struct mutator *mut = heap->deactivated_mutators; mut; mut = mut->next)
mark_controlling_mutator_roots(mut); mark_controlling_mutator_roots(mut);
} }
static void mark_global_roots(struct heap *heap) { static void mark_global_roots(struct heap *heap) {
struct mark_space *space = heap_mark_space(heap); for (struct handle *h = heap->global_roots; h; h = h->next) {
for (struct handle *h = space->global_roots; h; h = h->next) {
struct gcobj *obj = h->v; struct gcobj *obj = h->v;
if (obj && trace_object(heap, obj)) if (obj && trace_object(heap, obj))
tracer_enqueue_root(&heap->tracer, obj); tracer_enqueue_root(&heap->tracer, obj);
} }
struct mutator_mark_buf *roots = atomic_load(&space->mutator_roots); struct mutator_mark_buf *roots = atomic_load(&heap->mutator_roots);
for (; roots; roots = roots->next) for (; roots; roots = roots->next)
tracer_enqueue_roots(&heap->tracer, roots->objects, roots->size); tracer_enqueue_roots(&heap->tracer, roots->objects, roots->size);
atomic_store(&space->mutator_roots, NULL); atomic_store(&heap->mutator_roots, NULL);
} }
static void pause_mutator_for_collection(struct mark_space *space) NEVER_INLINE; static void pause_mutator_for_collection(struct heap *heap) NEVER_INLINE;
static void pause_mutator_for_collection(struct mark_space *space) { static void pause_mutator_for_collection(struct heap *heap) {
ASSERT(mutators_are_stopping(space)); ASSERT(mutators_are_stopping(heap));
ASSERT(space->active_mutator_count); ASSERT(heap->active_mutator_count);
space->active_mutator_count--; heap->active_mutator_count--;
if (space->active_mutator_count == 0) if (heap->active_mutator_count == 0)
pthread_cond_signal(&space->collector_cond); pthread_cond_signal(&heap->collector_cond);
// Go to sleep and wake up when the collector is done. Note, // Go to sleep and wake up when the collector is done. Note,
// however, that it may be that some other mutator manages to // however, that it may be that some other mutator manages to
// trigger collection before we wake up. In that case we need to // trigger collection before we wake up. In that case we need to
// mark roots, not just sleep again. To detect a wakeup on this // mark roots, not just sleep again. To detect a wakeup on this
// collection vs a future collection, we use the global GC count. // collection vs a future collection, we use the global GC count.
// This is safe because the count is protected by the space lock, // This is safe because the count is protected by the heap lock,
// which we hold. // which we hold.
long epoch = space->count; long epoch = heap->count;
do do
pthread_cond_wait(&space->mutator_cond, &space->lock); pthread_cond_wait(&heap->mutator_cond, &heap->lock);
while (mutators_are_stopping(space) && space->count == epoch); while (mutators_are_stopping(heap) && heap->count == epoch);
space->active_mutator_count++; heap->active_mutator_count++;
} }
static void pause_mutator_for_collection_with_lock(struct mutator *mut) NEVER_INLINE; static void pause_mutator_for_collection_with_lock(struct mutator *mut) NEVER_INLINE;
static void pause_mutator_for_collection_with_lock(struct mutator *mut) { static void pause_mutator_for_collection_with_lock(struct mutator *mut) {
struct mark_space *space = mutator_mark_space(mut); struct heap *heap = mutator_heap(mut);
ASSERT(mutators_are_stopping(space)); ASSERT(mutators_are_stopping(heap));
mark_controlling_mutator_roots(mut); mark_controlling_mutator_roots(mut);
pause_mutator_for_collection(space); pause_mutator_for_collection(heap);
clear_mutator_freelists(mut); clear_mutator_freelists(mut);
} }
static void pause_mutator_for_collection_without_lock(struct mutator *mut) NEVER_INLINE; static void pause_mutator_for_collection_without_lock(struct mutator *mut) NEVER_INLINE;
static void pause_mutator_for_collection_without_lock(struct mutator *mut) { static void pause_mutator_for_collection_without_lock(struct mutator *mut) {
struct mark_space *space = mutator_mark_space(mut); struct heap *heap = mutator_heap(mut);
ASSERT(mutators_are_stopping(space)); ASSERT(mutators_are_stopping(heap));
mark_stopping_mutator_roots(mut); mark_stopping_mutator_roots(mut);
mark_space_lock(space); heap_lock(heap);
pause_mutator_for_collection(space); pause_mutator_for_collection(heap);
mark_space_unlock(space); heap_unlock(heap);
release_stopping_mutator_roots(mut); release_stopping_mutator_roots(mut);
clear_mutator_freelists(mut); clear_mutator_freelists(mut);
} }
static inline void maybe_pause_mutator_for_collection(struct mutator *mut) { static inline void maybe_pause_mutator_for_collection(struct mutator *mut) {
while (mutators_are_stopping(mutator_mark_space(mut))) while (mutators_are_stopping(mutator_heap(mut)))
pause_mutator_for_collection_without_lock(mut); pause_mutator_for_collection_without_lock(mut);
} }
@ -429,19 +423,19 @@ static void reset_sweeper(struct mark_space *space) {
static void collect(struct heap *heap, struct mutator *mut) { static void collect(struct heap *heap, struct mutator *mut) {
struct mark_space *space = heap_mark_space(heap); struct mark_space *space = heap_mark_space(heap);
DEBUG("start collect #%ld:\n", space->count); DEBUG("start collect #%ld:\n", heap->count);
tracer_prepare(heap); tracer_prepare(heap);
request_mutators_to_stop(space); request_mutators_to_stop(heap);
mark_controlling_mutator_roots(mut); mark_controlling_mutator_roots(mut);
wait_for_mutators_to_stop(space); wait_for_mutators_to_stop(heap);
mark_inactive_mutators(space); mark_inactive_mutators(heap);
mark_global_roots(heap); mark_global_roots(heap);
tracer_trace(heap); tracer_trace(heap);
tracer_release(heap); tracer_release(heap);
clear_global_freelists(space); clear_global_freelists(space);
reset_sweeper(space); reset_sweeper(space);
space->count++; heap->count++;
allow_mutators_to_continue(space); allow_mutators_to_continue(heap);
clear_mutator_freelists(mut); clear_mutator_freelists(mut);
DEBUG("collect done\n"); DEBUG("collect done\n");
} }
@ -618,15 +612,16 @@ static int sweep(struct mark_space *space,
static void* allocate_medium(struct mutator *mut, enum alloc_kind kind, static void* allocate_medium(struct mutator *mut, enum alloc_kind kind,
size_t granules) { size_t granules) {
struct mark_space *space = mutator_mark_space(mut); struct heap *heap = mutator_heap(mut);
struct gcobj_freelists *small_objects = space_has_multiple_mutators(space) ? struct mark_space *space = heap_mark_space(heap);
struct gcobj_freelists *small_objects = heap_has_multiple_mutators(heap) ?
&space->small_objects : &mut->small_objects; &space->small_objects : &mut->small_objects;
maybe_pause_mutator_for_collection(mut); maybe_pause_mutator_for_collection(mut);
mark_space_lock(space); heap_lock(heap);
while (mutators_are_stopping(space)) while (mutators_are_stopping(heap))
pause_mutator_for_collection_with_lock(mut); pause_mutator_for_collection_with_lock(mut);
int swept_from_beginning = 0; int swept_from_beginning = 0;
@ -640,7 +635,7 @@ static void* allocate_medium(struct mutator *mut, enum alloc_kind kind,
if (medium->granules >= granules) { if (medium->granules >= granules) {
unlink_medium_object(prev, medium); unlink_medium_object(prev, medium);
split_medium_object(space, small_objects, medium, granules); split_medium_object(space, small_objects, medium, granules);
mark_space_unlock(space); heap_unlock(heap);
struct gcobj *obj = (struct gcobj *)medium; struct gcobj *obj = (struct gcobj *)medium;
obj->tag = tag_live(kind); obj->tag = tag_live(kind);
return medium; return medium;
@ -651,7 +646,7 @@ static void* allocate_medium(struct mutator *mut, enum alloc_kind kind,
// No medium object, and we swept across the whole heap. Collect. // No medium object, and we swept across the whole heap. Collect.
if (swept_from_beginning) { if (swept_from_beginning) {
fprintf(stderr, "ran out of space, heap size %zu\n", space->heap_size); fprintf(stderr, "ran out of space, heap size %zu\n", heap->size);
abort(); abort();
} else { } else {
collect(mutator_heap(mut), mut); collect(mutator_heap(mut), mut);
@ -682,7 +677,7 @@ static int fill_small_from_local(struct gcobj_freelists *small_objects,
return 0; return 0;
} }
// with space lock // with heap lock
static int fill_small_from_medium(struct mark_space *space, static int fill_small_from_medium(struct mark_space *space,
struct gcobj_freelists *small_objects, struct gcobj_freelists *small_objects,
enum small_object_size kind) { enum small_object_size kind) {
@ -719,13 +714,14 @@ static void fill_small_from_global(struct mutator *mut,
static void fill_small_from_global(struct mutator *mut, static void fill_small_from_global(struct mutator *mut,
enum small_object_size kind) { enum small_object_size kind) {
struct gcobj_freelists *small_objects = &mut->small_objects; struct gcobj_freelists *small_objects = &mut->small_objects;
struct mark_space *space = mutator_mark_space(mut); struct heap *heap = mutator_heap(mut);
struct mark_space *space = heap_mark_space(heap);
maybe_pause_mutator_for_collection(mut); maybe_pause_mutator_for_collection(mut);
mark_space_lock(space); heap_lock(heap);
while (mutators_are_stopping(space)) while (mutators_are_stopping(heap))
pause_mutator_for_collection_with_lock(mut); pause_mutator_for_collection_with_lock(mut);
int swept_from_beginning = 0; int swept_from_beginning = 0;
@ -739,7 +735,7 @@ static void fill_small_from_global(struct mutator *mut,
// By default, pull in 16 kB of data at a time. // By default, pull in 16 kB of data at a time.
if (!sweep(space, small_objects, kind, 0)) { if (!sweep(space, small_objects, kind, 0)) {
if (swept_from_beginning) { if (swept_from_beginning) {
fprintf(stderr, "ran out of space, heap size %zu\n", space->heap_size); fprintf(stderr, "ran out of space, heap size %zu\n", heap->size);
abort(); abort();
} else { } else {
collect(mutator_heap(mut), mut); collect(mutator_heap(mut), mut);
@ -750,7 +746,7 @@ static void fill_small_from_global(struct mutator *mut,
if (*get_small_object_freelist(small_objects, kind)) if (*get_small_object_freelist(small_objects, kind))
break; break;
} }
mark_space_unlock(space); heap_unlock(heap);
} }
static void fill_small(struct mutator *mut, enum small_object_size kind) { static void fill_small(struct mutator *mut, enum small_object_size kind) {
@ -799,18 +795,8 @@ static inline void* get_field(void **addr) {
return *addr; return *addr;
} }
static int initialize_gc(size_t size, struct heap **heap, static int mark_space_init(struct mark_space *space, struct heap *heap) {
struct mutator **mut) { size_t size = align_up(heap->size, getpagesize());
#define SMALL_OBJECT_GRANULE_SIZE(i) \
ASSERT_EQ(SMALL_OBJECT_##i, small_object_sizes_for_granules[i]); \
ASSERT_EQ(SMALL_OBJECT_##i + 1, small_object_sizes_for_granules[i+1]);
FOR_EACH_SMALL_OBJECT_GRANULES(SMALL_OBJECT_GRANULE_SIZE);
#undef SMALL_OBJECT_GRANULE_SIZE
ASSERT_EQ(SMALL_OBJECT_SIZES - 1,
small_object_sizes_for_granules[MEDIUM_OBJECT_GRANULE_THRESHOLD]);
size = align_up(size, getpagesize());
void *mem = mmap(NULL, size, PROT_READ|PROT_WRITE, void *mem = mmap(NULL, size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
@ -819,9 +805,6 @@ static int initialize_gc(size_t size, struct heap **heap,
return 0; return 0;
} }
*heap = calloc(1, sizeof(struct heap));
if (!*heap) abort();
struct mark_space *space = heap_mark_space(*heap);
space->mem = mem; space->mem = mem;
space->mem_size = size; space->mem_size = size;
// If there is 1 mark byte per granule, and SIZE bytes available for // If there is 1 mark byte per granule, and SIZE bytes available for
@ -834,17 +817,42 @@ static int initialize_gc(size_t size, struct heap **heap,
size_t mark_bytes_size = (size + GRANULE_SIZE) / (GRANULE_SIZE + 1); size_t mark_bytes_size = (size + GRANULE_SIZE) / (GRANULE_SIZE + 1);
size_t overhead = align_up(mark_bytes_size, GRANULE_SIZE); size_t overhead = align_up(mark_bytes_size, GRANULE_SIZE);
pthread_mutex_init(&space->lock, NULL);
pthread_cond_init(&space->mutator_cond, NULL);
pthread_cond_init(&space->collector_cond, NULL);
space->heap_base = ((uintptr_t) mem) + overhead; space->heap_base = ((uintptr_t) mem) + overhead;
space->heap_size = size - overhead; space->heap_size = size - overhead;
space->sweep = space->heap_base + space->heap_size; space->sweep = space->heap_base + space->heap_size;
if (!tracer_init(*heap))
abort();
reclaim(space, NULL, NOT_SMALL_OBJECT, (void*)space->heap_base, reclaim(space, NULL, NOT_SMALL_OBJECT, (void*)space->heap_base,
size_to_granules(space->heap_size)); size_to_granules(space->heap_size));
return 1;
}
static int initialize_gc(size_t size, struct heap **heap,
struct mutator **mut) {
#define SMALL_OBJECT_GRANULE_SIZE(i) \
ASSERT_EQ(SMALL_OBJECT_##i, small_object_sizes_for_granules[i]); \
ASSERT_EQ(SMALL_OBJECT_##i + 1, small_object_sizes_for_granules[i+1]);
FOR_EACH_SMALL_OBJECT_GRANULES(SMALL_OBJECT_GRANULE_SIZE);
#undef SMALL_OBJECT_GRANULE_SIZE
ASSERT_EQ(SMALL_OBJECT_SIZES - 1,
small_object_sizes_for_granules[MEDIUM_OBJECT_GRANULE_THRESHOLD]);
*heap = calloc(1, sizeof(struct heap));
if (!*heap) abort();
pthread_mutex_init(&(*heap)->lock, NULL);
pthread_cond_init(&(*heap)->mutator_cond, NULL);
pthread_cond_init(&(*heap)->collector_cond, NULL);
(*heap)->size = size;
if (!tracer_init(*heap))
abort();
struct mark_space *space = heap_mark_space(*heap);
if (!mark_space_init(space, *heap)) {
free(*heap);
*heap = NULL;
return 0;
}
*mut = calloc(1, sizeof(struct mutator)); *mut = calloc(1, sizeof(struct mutator));
if (!*mut) abort(); if (!*mut) abort();
@ -867,28 +875,28 @@ static void finish_gc_for_thread(struct mutator *mut) {
free(mut); free(mut);
} }
static void deactivate_mutator(struct mark_space *space, struct mutator *mut) { static void deactivate_mutator(struct heap *heap, struct mutator *mut) {
ASSERT(mut->next == NULL); ASSERT(mut->next == NULL);
mark_space_lock(space); heap_lock(heap);
mut->next = space->deactivated_mutators; mut->next = heap->deactivated_mutators;
space->deactivated_mutators = mut; heap->deactivated_mutators = mut;
space->active_mutator_count--; heap->active_mutator_count--;
if (!space->active_mutator_count && mutators_are_stopping(space)) if (!heap->active_mutator_count && mutators_are_stopping(heap))
pthread_cond_signal(&space->collector_cond); pthread_cond_signal(&heap->collector_cond);
mark_space_unlock(space); heap_unlock(heap);
} }
static void reactivate_mutator(struct mark_space *space, struct mutator *mut) { static void reactivate_mutator(struct heap *heap, struct mutator *mut) {
mark_space_lock(space); heap_lock(heap);
while (mutators_are_stopping(space)) while (mutators_are_stopping(heap))
pthread_cond_wait(&space->mutator_cond, &space->lock); pthread_cond_wait(&heap->mutator_cond, &heap->lock);
struct mutator **prev = &space->deactivated_mutators; struct mutator **prev = &heap->deactivated_mutators;
while (*prev != mut) while (*prev != mut)
prev = &(*prev)->next; prev = &(*prev)->next;
*prev = mut->next; *prev = mut->next;
mut->next = NULL; mut->next = NULL;
space->active_mutator_count++; heap->active_mutator_count++;
mark_space_unlock(space); heap_unlock(heap);
} }
static void* call_without_gc(struct mutator *mut, void* (*f)(void*), static void* call_without_gc(struct mutator *mut, void* (*f)(void*),
@ -896,10 +904,10 @@ static void* call_without_gc(struct mutator *mut, void* (*f)(void*),
static void* call_without_gc(struct mutator *mut, static void* call_without_gc(struct mutator *mut,
void* (*f)(void*), void* (*f)(void*),
void *data) { void *data) {
struct mark_space *space = mutator_mark_space(mut); struct heap *heap = mutator_heap(mut);
deactivate_mutator(space, mut); deactivate_mutator(heap, mut);
void *ret = f(data); void *ret = f(data);
reactivate_mutator(space, mut); reactivate_mutator(heap, mut);
return ret; return ret;
} }
@ -907,6 +915,6 @@ static inline void print_start_gc_stats(struct heap *heap) {
} }
static inline void print_end_gc_stats(struct heap *heap) { static inline void print_end_gc_stats(struct heap *heap) {
printf("Completed %ld collections\n", heap_mark_space(heap)->count); printf("Completed %ld collections\n", heap->count);
printf("Heap size with overhead is %zd\n", heap_mark_space(heap)->mem_size); printf("Heap size with overhead is %zd\n", heap->size);
} }