Skip to content

Commit

Permalink
Use separate thread for finalisation
Browse files Browse the repository at this point in the history
This commit creates a finalisation thread in the GC_INIT() routine. The
thread spins indefinitely waiting to process objects in the finaliser
buffers.

This commit also makes sure that once an object has been finalised, its
finalised bit is set so that it is not re-added to the buffer the next
time it becomes unreachable.
  • Loading branch information
jacob-hughes committed Apr 16, 2024
1 parent 29d65b9 commit 92f2fc0
Showing 1 changed file with 21 additions and 3 deletions.
24 changes: 21 additions & 3 deletions fnlz_mlc.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
/* The first bit is already used for a debug purpose. */
# define FINALIZER_CLOSURE_FLAG 0x2
# define HAS_BEEN_FINALIZED_FLAG 0x3
#else
# define FINALIZER_CLOSURE_FLAG 0x1
# define HAS_BEEN_FINALIZED_FLAG 0x2
#endif

STATIC int GC_CALLBACK GC_finalized_disclaim(void *obj)
Expand Down Expand Up @@ -135,19 +137,24 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t lb,
STATIC GC_finalization_buffer_hdr* start_buffer;
STATIC struct GC_current_buffer cur_buffer;

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());
GC_disable();
void* ptr = GC_os_get_mem(GC_page_size);
GC_enable();
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_ASSERT(I_HOLD_LOCK());
GC_remove_roots((void*) buffer, (void*) buffer + GC_page_size);
GC_unmap((void*)buffer, GC_page_size);

Expand All @@ -162,6 +169,13 @@ STATIC int GC_CALLBACK GC_push_object_to_fin_buffer(void *obj)
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 (start_buffer == NULL) {
/* This can happen for two reasons:
* 1) This is first time a finalizable object is unreachable and no
Expand Down Expand Up @@ -211,6 +225,8 @@ GC_API void GC_CALL GC_init_buffered_finalization(void)

GC_register_disclaim_proc_inner(GC_fin_q_kind, GC_push_object_to_fin_buffer, TRUE);
UNLOCK();
pthread_t t;
pthread_create(&t, NULL, init_finalize_thread, NULL /* arg */);
}

void GC_finalize_buffer(GC_finalization_buffer_hdr* buffer) {
Expand All @@ -225,6 +241,8 @@ void GC_finalize_buffer(GC_finalization_buffer_hdr* buffer) {
word finalizer_word = (*(word *)obj) & ~(word)FINALIZER_CLOSURE_FLAG;
GC_disclaim_proc finalizer = (GC_disclaim_proc) finalizer_word;
(finalizer)(obj);
/* Prevent the object from being re-added to the finalization queue */
*(word *)obj = finalizer_word | HAS_BEEN_FINALIZED_FLAG;
cursor++;
}
}
Expand Down

0 comments on commit 92f2fc0

Please sign in to comment.