Skip to content

Commit

Permalink
Remove buffered disclaim finalisation
Browse files Browse the repository at this point in the history
This was replaced with the GC_finalize mechanism in e093be9.
  • Loading branch information
jacob-hughes committed Aug 22, 2024
1 parent 2aeecee commit 43d97f6
Show file tree
Hide file tree
Showing 5 changed files with 2 additions and 303 deletions.
196 changes: 0 additions & 196 deletions fnlz_mlc.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,200 +131,4 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t lb,
return (word *)op + 1;
}

# ifdef BUFFERED_FINALIZATION

static void* init_finalize_thread(void *arg)
{
while (1) {
GC_finalize_objects();
}
return arg;
}

GC_finalization_buffer_hdr* GC_new_buffer() {
GC_ASSERT(I_HOLD_LOCK());
void* ptr = GC_os_get_mem(GC_page_size);
if (NULL == ptr)
ABORT("Insufficient memory for finalization buffer.");
GC_add_roots_inner(ptr, ptr + GC_page_size, FALSE);
return ptr;
}

void GC_delete_buffer(GC_finalization_buffer_hdr* buffer) {
GC_remove_roots((void*) buffer, (void*) buffer + GC_page_size);
GC_unmap((void*)buffer, GC_page_size);

}

STATIC int GC_CALLBACK GC_push_object_to_fin_buffer(void *obj)
{
GC_ASSERT(I_HOLD_LOCK());

word finalizer_word = *(word *)obj;
if ((finalizer_word & FINALIZER_CLOSURE_FLAG) == 0) {
return 0;
}

if (finalizer_word & HAS_BEEN_FINALIZED_FLAG) {
/* The object has already been finalized. Return 0 ensures it is
* immediately reclaimed.
*/
return 0;
}

if (GC_finalizer_buffer_head == NULL) {
/* This can happen for two reasons:
* 1) This is first time a finalizable object is unreachable and no
* finalization buffers have been created yet.
*
* 2) The buffer(s) have already passed to a finalization thread
* which is processing them. We must start again. */
GC_finalizer_buffer_head = GC_new_buffer();
GC_finalizer_buffer_current.hdr = GC_finalizer_buffer_head;
GC_finalizer_buffer_current.cursor = (void**) (GC_finalizer_buffer_head + 1);
}

void** last = (void**) ((void *)GC_finalizer_buffer_current.hdr + GC_page_size);
if (GC_finalizer_buffer_current.cursor == last) {
GC_finalization_buffer_hdr* next = GC_new_buffer();
GC_finalizer_buffer_current.hdr->next = next;
GC_finalizer_buffer_current.hdr = next;
GC_finalizer_buffer_current.cursor = (void**) (next + 1);
}

*GC_finalizer_buffer_current.cursor = obj;
GC_finalizer_buffer_current.cursor++;

return 1;
}


GC_API GC_ATTR_MALLOC void * GC_CALL GC_buffered_finalize_malloc(size_t lb)
{
void *op;

GC_ASSERT(GC_fin_q_kind != 0);
op = GC_malloc_kind(lb, (int)GC_fin_q_kind);
if (EXPECT(NULL == op, FALSE))
return NULL;
return (word *)op;
}

GC_API GC_ATTR_MALLOC void * GC_CALL GC_buffered_finalize_memalign(size_t align, size_t lb)
{
size_t offset;
ptr_t result;
size_t align_m1 = align - 1;

/* Check the alignment argument. */
if (EXPECT(0 == align || (align & align_m1) != 0, FALSE)) return NULL;
if (align <= GC_GRANULE_BYTES) return GC_buffered_finalize_malloc(lb);

if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) {
return GC_clear_stack(GC_generic_malloc_aligned(lb, GC_fin_q_kind,
0 /* flags */, align_m1));
}

result = (ptr_t)GC_buffered_finalize_malloc(SIZET_SAT_ADD(lb, align_m1));
offset = (size_t)(word)result & align_m1;
if (offset != 0) {
offset = align - offset;
if (!GC_all_interior_pointers) {
GC_STATIC_ASSERT(VALID_OFFSET_SZ <= HBLKSIZE);
GC_ASSERT(offset < VALID_OFFSET_SZ);
GC_register_displacement(offset);
}
result += offset;
}
GC_ASSERT(((word)result & align_m1) == 0);
return result;
}

GC_API int GC_CALL GC_buffered_finalize_posix_memalign(void **memptr, size_t align, size_t lb)
{
size_t align_minus_one = align - 1; /* to workaround a cppcheck warning */

/* Check alignment properly. */
if (EXPECT(align < sizeof(void *)
|| (align_minus_one & align) != 0, FALSE)) {
return EINVAL;
}

if ((*memptr = GC_buffered_finalize_memalign(align, lb)) == NULL) {
return ENOMEM;
}
return 0;
}


GC_API void GC_CALL GC_init_buffered_finalization(void)
{
LOCK();
GC_new_buffer();
GC_fin_q_kind = GC_new_kind_inner(GC_new_free_list_inner(),
GC_DS_LENGTH, TRUE, TRUE);
GC_ASSERT(GC_fin_q_kind != 0);

GC_register_disclaim_proc_inner(GC_fin_q_kind, GC_push_object_to_fin_buffer, TRUE);
UNLOCK();
}

void GC_finalize_buffer(GC_finalization_buffer_hdr* buffer) {
void** cursor = (void**) (buffer + 1);
void** last = (void**) ((void *)buffer + GC_page_size);
while (cursor != last)
{
if (*cursor == NULL) {
break;
}
void* obj = *cursor;
word finalizer_word = (*(word *)obj) & ~(word)FINALIZER_CLOSURE_FLAG;
GC_disclaim_proc finalizer = (GC_disclaim_proc) finalizer_word;
(finalizer)(obj);
GC_num_finalized++;
/* Prevent the object from being re-added to the finalization queue */
*(word *)obj = finalizer_word | HAS_BEEN_FINALIZED_FLAG;
cursor++;
}
}

GC_API void GC_CALL GC_finalize_objects(void) {
/* This is safe to do without locking because this global is only ever
* mutated from within a collection where all mutator threads (including
* this finalisation thread) are paused. It is not possible for them to race.
*
* In addition, a memory barrier synchronises threads at the end of a
* collection, so the finalisation thread will always load the up-to-date
* version of this global. */
GC_disable();
GC_finalization_buffer_hdr* buffer = GC_finalizer_buffer_head;
GC_finalizer_buffer_head = NULL;
GC_enable();

while(buffer != NULL)
{
GC_finalize_buffer(buffer);
GC_finalization_buffer_hdr* next = buffer->next;

GC_delete_buffer(buffer);
buffer = next;
}
}

GC_INNER void GC_maybe_spawn_finalize_thread()
{
if (GC_finalizer_thread_exists || !GC_finalizer_buffer_head)
return;

pthread_t t;
pthread_create(&t, NULL, init_finalize_thread, NULL /* arg */);
GC_finalizer_thread_exists = 1;
}

GC_API size_t GC_finalized_total(void) {
return GC_num_finalized;
}

# endif

#endif /* ENABLE_DISCLAIM */
39 changes: 0 additions & 39 deletions include/gc/gc_disclaim.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,45 +69,6 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
const struct GC_finalizer_closure * /* fc */) GC_ATTR_NONNULL(2);


#ifdef BUFFERED_FINALIZATION
/* This API is defined only if the library has been suitably compiled */
/* (i.e. with ENABLE_DISCLAIM defined). */

/* Prepare the object kind used by GC_buffered_finalize_malloc. Call */
/* it from your initialization code or, at least, at some point before */
/* finalized allocations. The function is thread-safe. */
GC_API void GC_CALL GC_init_buffered_finalization(void);

/* Allocate an object which is to be finalized. */
/* This function assumes the first word in the allocated block will */
/* store the function pointer to the finalizer. */
/* Allocations of this kind are added to a buffer which, when full, is */
/* passed to a user supplied closure to invoke their finalizers. It is */
/* the responsibility of the user to ensure these objects are finalized.*/
/* This uses a dedicated object kind with a disclaim procedure, and is */
/* more efficient than GC_register_finalizer and friends. */
/* GC_init_buffered_finalization must be called before using this. */
/* The collector will not reclaim the object during the GC cycle where */
/* it was considered unreachable. In addition, objects reachable from */
/* the finalizer will be protected from collection until the finalizer */
/* has been run. */
/* The disclaim procedure is not invoked in the leak-finding mode. */
/* There is no debugging version of this allocation API. */
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
GC_buffered_finalize_malloc(size_t);

GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(2) void * GC_CALL
GC_buffered_finalize_memalign(size_t /* align */, size_t /* lb */);

GC_API int GC_CALL GC_buffered_finalize_posix_memalign(void ** /* memptr */, size_t /* align */,
size_t /* lb */) GC_ATTR_NONNULL(1);

GC_API void GC_CALL GC_finalize_objects(void);

GC_API size_t GC_finalized_total(void);

#endif

#ifdef __cplusplus
} /* extern "C" */
#endif
Expand Down
33 changes: 2 additions & 31 deletions include/private/gc_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,26 +341,7 @@ typedef struct hblkhdr hdr;

#include "gc/gc_inline.h"

<<<<<<< HEAD
#ifdef BUFFERED_FINALIZATION

typedef struct GC_finalization_buffer_hdr GC_finalization_buffer_hdr;

struct GC_finalization_buffer_hdr {
GC_finalization_buffer_hdr* next;
};

struct GC_current_buffer {
GC_finalization_buffer_hdr* hdr;
void** cursor;
};

GC_INNER void GC_maybe_spawn_finalize_thread();
=======
GC_INNER void GC_maybe_wake_finalizer_thread();
>>>>>>> b44b0a3e (Revert to using old GC_finalize mechanism)

#endif

/*********************************/
/* */
Expand Down Expand Up @@ -1597,21 +1578,11 @@ struct _GC_arrays {
# define GC_trace_buf_ptr GC_arrays._trace_buf_ptr
int _trace_buf_ptr;
# endif
# define GC_finalizer_thread_exists GC_arrays._fin_thread_exists
int _fin_thread_exists;
# ifdef ENABLE_DISCLAIM
# define GC_finalized_kind GC_arrays._finalized_kind
unsigned _finalized_kind;
# ifdef BUFFERED_FINALIZATION
# define GC_fin_q_kind GC_arrays._fin_q_kind
unsigned _fin_q_kind;
# define GC_finalizer_buffer_head GC_arrays._fin_buffer_head
GC_finalization_buffer_hdr* _fin_buffer_head;
# define GC_finalizer_buffer_current GC_arrays._fin_buffer_current
struct GC_current_buffer _fin_buffer_current;
# define GC_finalizer_thread_exists GC_arrays._fin_thread_exists
int _fin_thread_exists;
# define GC_num_finalized GC_arrays._fin_total
unsigned _fin_total;
# endif
# endif
# define n_root_sets GC_arrays._n_root_sets
# define GC_excl_table_entries GC_arrays._excl_table_entries
Expand Down
8 changes: 0 additions & 8 deletions misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1481,9 +1481,6 @@ GC_API void GC_CALL GC_init(void)
GC_ASSERT(GC_bytes_allocd + GC_bytes_allocd_before_gc == 0);
# endif

# ifdef BUFFERED_FINALIZATION
GC_init_buffered_finalization();
# endif
}

GC_API void GC_CALL GC_enable_incremental(void)
Expand Down Expand Up @@ -2136,11 +2133,6 @@ GC_API void GC_CALL GC_enable(void)
LOCK();
GC_ASSERT(GC_dont_gc != 0); /* ensure no counter underflow */
GC_dont_gc--;
#ifndef BUFFERED_FINALIZATION
if (!GC_dont_gc && GC_heapsize > GC_heapsize_on_gc_disable)
WARN("Heap grown by %" WARN_PRIuPTR " KiB while GC was disabled\n",
(GC_heapsize - GC_heapsize_on_gc_disable) >> 10);
#endif
UNLOCK();
}

Expand Down
29 changes: 0 additions & 29 deletions tests/gctest.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,6 @@
# define INIT_PERF_MEASUREMENT GC_start_performance_measurement()
#endif

# ifdef BUFFERED_FINALIZATION
# include "gc/gc_disclaim.h"
# endif

#define GC_COND_INIT() \
INIT_FORK_SUPPORT; INIT_MANUAL_VDB_ALLOWED; INIT_PAGES_EXECUTABLE; \
GC_OPT_INIT; CHECK_GCLIB_VERSION; \
Expand Down Expand Up @@ -1674,31 +1670,6 @@ static void run_one_test(void)
NOOP1_PTR(p);
AO_fetch_and_add1(&collectable_count);
}
# ifdef BUFFERED_FINALIZATION
{
size_t i;
void *p;

GC_init();

p = GC_buffered_finalize_malloc(17);
CHECK_OUT_OF_MEMORY(p);
AO_fetch_and_add1(&collectable_count);

for (i = sizeof(GC_word); i <= HBLKSIZE * 4; i *= 2) {
p = checkOOM(GC_buffered_finalize_memalign(i, 17));
AO_fetch_and_add1(&collectable_count);
if ((GC_word)p % i != 0 || *(int *)p != 0) {
GC_printf("GC_buffered_finalize_posix_memalign(%u,17) produced incorrect result: %p\n",
(unsigned)i, p);
FAIL;
}
}
(void)GC_buffered_finalize_posix_memalign(&p, 64, 1);
CHECK_OUT_OF_MEMORY(p);
AO_fetch_and_add1(&collectable_count);
}
# endif
# ifndef GC_NO_VALLOC
{
void *p = checkOOM(GC_valloc(78));
Expand Down

0 comments on commit 43d97f6

Please sign in to comment.