Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to using the GC_finalize API for off-thread finalisation #22

Merged
merged 4 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .buildbot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,3 @@ sh rustup.sh --default-host x86_64-unknown-linux-gnu \
--profile minimal \
-y
export PATH=`pwd`/.cargo/bin/:$PATH
BDWGC_SRC=`pwd`

git clone https://github.com/softdevteam/alloy
cd alloy
BDWGC=${BDWGC_SRC} ENABLE_GC_ASSERTIONS=true /usr/bin/time -v python3 x.py test --stage 2 \
--config .buildbot.config.toml --exclude rustdoc-json --exclude debuginfo
12 changes: 0 additions & 12 deletions alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1861,15 +1861,3 @@ GC_INNER ptr_t GC_allocobj(size_t lg, int k)
GC_fail_count = 0;
return (ptr_t)(*flh);
}

STATIC __thread void* tls_rootset = NULL;

GC_INNER void GC_init_tls_rootset(void * rootset)
{
tls_rootset = rootset;
}

GC_INNER void* GC_tls_rootset()
{
return tls_rootset;
}
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 */
3 changes: 0 additions & 3 deletions include/gc/gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2358,7 +2358,4 @@ GC_API void GC_CALL GC_win32_free_heap(void);
} /* extern "C" */
#endif

GC_API void GC_init_tls_rootset(void * rootset);
GC_API void * GC_tls_rootset();

#endif /* GC_H */
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
37 changes: 4 additions & 33 deletions include/private/gc_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,22 +341,7 @@ typedef struct hblkhdr hdr;

#include "gc/gc_inline.h"

#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();

#endif
GC_INNER void GC_maybe_wake_finalizer_thread();

/*********************************/
/* */
Expand Down Expand Up @@ -402,11 +387,7 @@ GC_INNER void GC_maybe_spawn_finalize_thread();
EXTERN_C_BEGIN

#ifndef GC_NO_FINALIZATION
#ifdef BUFFERED_FINALIZATION
# define GC_INVOKE_FINALIZERS() GC_maybe_spawn_finalize_thread()
#else
# define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
#endif
# define GC_INVOKE_FINALIZERS() GC_maybe_wake_finalizer_thread()
GC_INNER void GC_notify_or_invoke_finalizers(void);
/* If GC_finalize_on_demand is not set, invoke */
/* eligible finalizers. Otherwise: */
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
2 changes: 0 additions & 2 deletions pthread_stop_world.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,6 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy, void *context)
}
crtn = me -> crtn;
GC_store_stack_ptr(crtn);
crtn -> tls_rootset = GC_tls_rootset();
get_thread_local_roots(&tlr);
crtn -> compiler_thread_roots = tlr;

Expand Down Expand Up @@ -834,7 +833,6 @@ GC_INNER void GC_push_all_stacks(void)
if (me != NULL) {
struct GC_ThreadLocalRoots tlr;
get_thread_local_roots(&tlr);
me -> crtn -> tls_rootset = GC_tls_rootset();
me -> crtn -> compiler_thread_roots = tlr;
}

Expand Down
Loading
Loading