Expose GC.config[:implementation], to query the currently active GC

And a default and readonly key to the GC.config hash that names the
current GC implementation.

This is provided by each implementation by the API function
rb_gc_impl_active_gc_name
This commit is contained in:
Matt Valentine-House 2024-10-08 12:16:14 +01:00
parent 8a4ce4e9a9
commit fa10441981
Notes: git 2024-11-14 10:46:55 +00:00
3 changed files with 37 additions and 3 deletions

19
gc.c
View File

@ -642,6 +642,8 @@ typedef struct gc_function_map {
bool (*garbage_object_p)(void *objspace_ptr, VALUE obj); bool (*garbage_object_p)(void *objspace_ptr, VALUE obj);
void (*set_event_hook)(void *objspace_ptr, const rb_event_flag_t event); void (*set_event_hook)(void *objspace_ptr, const rb_event_flag_t event);
void (*copy_attributes)(void *objspace_ptr, VALUE dest, VALUE obj); void (*copy_attributes)(void *objspace_ptr, VALUE dest, VALUE obj);
// GC Identification
const char *(*active_gc_name)(void);
} rb_gc_function_map_t; } rb_gc_function_map_t;
static rb_gc_function_map_t rb_gc_functions; static rb_gc_function_map_t rb_gc_functions;
@ -785,6 +787,8 @@ ruby_external_gc_init(void)
load_external_gc_func(garbage_object_p); load_external_gc_func(garbage_object_p);
load_external_gc_func(set_event_hook); load_external_gc_func(set_event_hook);
load_external_gc_func(copy_attributes); load_external_gc_func(copy_attributes);
//GC Identification
load_external_gc_func(active_gc_name);
# undef load_external_gc_func # undef load_external_gc_func
@ -864,6 +868,8 @@ ruby_external_gc_init(void)
# define rb_gc_impl_garbage_object_p rb_gc_functions.garbage_object_p # define rb_gc_impl_garbage_object_p rb_gc_functions.garbage_object_p
# define rb_gc_impl_set_event_hook rb_gc_functions.set_event_hook # define rb_gc_impl_set_event_hook rb_gc_functions.set_event_hook
# define rb_gc_impl_copy_attributes rb_gc_functions.copy_attributes # define rb_gc_impl_copy_attributes rb_gc_functions.copy_attributes
// GC Identification
# define rb_gc_impl_active_gc_name rb_gc_functions.active_gc_name
#endif #endif
static VALUE initial_stress = Qfalse; static VALUE initial_stress = Qfalse;
@ -2761,6 +2767,12 @@ rb_gc_copy_attributes(VALUE dest, VALUE obj)
rb_gc_impl_copy_attributes(rb_gc_get_objspace(), dest, obj); rb_gc_impl_copy_attributes(rb_gc_get_objspace(), dest, obj);
} }
const char *
rb_gc_active_gc_name(void)
{
return rb_gc_impl_active_gc_name();
}
// TODO: rearchitect this function to work for a generic GC // TODO: rearchitect this function to work for a generic GC
size_t size_t
rb_obj_gc_flags(VALUE obj, ID* flags, size_t max) rb_obj_gc_flags(VALUE obj, ID* flags, size_t max)
@ -3489,7 +3501,10 @@ gc_stat_heap(rb_execution_context_t *ec, VALUE self, VALUE heap_name, VALUE arg)
static VALUE static VALUE
gc_config_get(rb_execution_context_t *ec, VALUE self) gc_config_get(rb_execution_context_t *ec, VALUE self)
{ {
return rb_gc_impl_config_get(rb_gc_get_objspace()); VALUE cfg_hash = rb_gc_impl_config_get(rb_gc_get_objspace());
rb_hash_aset(cfg_hash, sym("implementation"), rb_fstring_cstr(rb_gc_impl_active_gc_name()));
return cfg_hash;
} }
static VALUE static VALUE
@ -3582,8 +3597,6 @@ gc_disable(rb_execution_context_t *ec, VALUE _)
return rb_gc_disable(); return rb_gc_disable();
} }
// TODO: think about moving ruby_gc_set_params into Init_heap or Init_gc // TODO: think about moving ruby_gc_set_params into Init_heap or Init_gc
void void
ruby_gc_set_params(void) ruby_gc_set_params(void)

View File

@ -6156,6 +6156,12 @@ rb_gc_impl_copy_attributes(void *objspace_ptr, VALUE dest, VALUE obj)
rb_gc_impl_copy_finalizer(objspace, dest, obj); rb_gc_impl_copy_finalizer(objspace, dest, obj);
} }
const char *
rb_gc_impl_active_gc_name(void)
{
return "default";
}
void void
rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj) rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj)
{ {

View File

@ -117,6 +117,21 @@ class TestGc < Test::Unit::TestCase
GC.start GC.start
end end
def test_gc_config_implementation
omit unless /darwin|linux/.match(RUBY_PLATFORM)
gc_name = (ENV['RUBY_GC_LIBRARY'] || "default")
assert_equal gc_name, GC.config[:implementation]
end
def test_gc_config_implementation_is_readonly
omit unless /darwin|linux/.match(RUBY_PLATFORM)
impl = GC.config[:implementation]
GC.config(implementation: "somethingelse")
assert_equal(impl, GC.config[:implementation])
end
def test_start_full_mark def test_start_full_mark
return unless use_rgengc? return unless use_rgengc?
omit 'stress' if GC.stress omit 'stress' if GC.stress