mirror of
https://github.com/ruby/ruby.git
synced 2026-01-26 04:07:58 +00:00
ObjectSpace.{dump,dump_all,dump_shapes} needs vm barrier. (#15569)
This allows these methods to be called from ractors. Add new exported function `rb_vm_lock_with_barrier()` that requires users to include "vm_sync.h"
This commit is contained in:
parent
41e24aeb1a
commit
56b67f1684
Notes:
git
2025-12-17 17:17:58 +00:00
Merged-By: luke-gru <luke.gru@gmail.com>
@ -29,7 +29,7 @@
|
||||
#include "ruby/util.h"
|
||||
#include "ruby/io.h"
|
||||
#include "vm_callinfo.h"
|
||||
#include "vm_core.h"
|
||||
#include "vm_sync.h"
|
||||
|
||||
RUBY_EXTERN const char ruby_hexdigits[];
|
||||
|
||||
@ -771,15 +771,16 @@ dump_result(struct dump_config *dc)
|
||||
return dc->given_output;
|
||||
}
|
||||
|
||||
/* :nodoc: */
|
||||
static VALUE
|
||||
objspace_dump(VALUE os, VALUE obj, VALUE output)
|
||||
dump_locked(void *args_p)
|
||||
{
|
||||
struct dump_config dc = {0,};
|
||||
VALUE obj = ((VALUE*)args_p)[0];
|
||||
VALUE output = ((VALUE*)args_p)[1];
|
||||
|
||||
if (!RB_SPECIAL_CONST_P(obj)) {
|
||||
dc.cur_page_slot_size = rb_gc_obj_slot_size(obj);
|
||||
}
|
||||
|
||||
dump_output(&dc, output, Qnil, Qnil, Qnil);
|
||||
|
||||
dump_object(obj, &dc);
|
||||
@ -787,6 +788,16 @@ objspace_dump(VALUE os, VALUE obj, VALUE output)
|
||||
return dump_result(&dc);
|
||||
}
|
||||
|
||||
/* :nodoc: */
|
||||
static VALUE
|
||||
objspace_dump(VALUE os, VALUE obj, VALUE output)
|
||||
{
|
||||
VALUE args[2];
|
||||
args[0] = obj;
|
||||
args[1] = output;
|
||||
return rb_vm_lock_with_barrier(dump_locked, (void*)args);
|
||||
}
|
||||
|
||||
static void
|
||||
shape_id_i(shape_id_t shape_id, void *data)
|
||||
{
|
||||
@ -835,11 +846,15 @@ shape_id_i(shape_id_t shape_id, void *data)
|
||||
dump_append(dc, "}\n");
|
||||
}
|
||||
|
||||
/* :nodoc: */
|
||||
static VALUE
|
||||
objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
|
||||
dump_all_locked(void *args_p)
|
||||
{
|
||||
struct dump_config dc = {0,};
|
||||
VALUE output = ((VALUE*)args_p)[0];
|
||||
VALUE full = ((VALUE*)args_p)[1];
|
||||
VALUE since = ((VALUE*)args_p)[2];
|
||||
VALUE shapes = ((VALUE*)args_p)[3];
|
||||
|
||||
dump_output(&dc, output, full, since, shapes);
|
||||
|
||||
if (!dc.partial_dump || dc.since == 0) {
|
||||
@ -860,9 +875,23 @@ objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
|
||||
|
||||
/* :nodoc: */
|
||||
static VALUE
|
||||
objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
|
||||
objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
|
||||
{
|
||||
VALUE args[4];
|
||||
args[0] = output;
|
||||
args[1] = full;
|
||||
args[2] = since;
|
||||
args[3] = shapes;
|
||||
return rb_vm_lock_with_barrier(dump_all_locked, (void*)args);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
dump_shapes_locked(void *args_p)
|
||||
{
|
||||
struct dump_config dc = {0,};
|
||||
VALUE output = ((VALUE*)args_p)[0];
|
||||
VALUE shapes = ((VALUE*)args_p)[1];
|
||||
|
||||
dump_output(&dc, output, Qfalse, Qnil, shapes);
|
||||
|
||||
if (RTEST(shapes)) {
|
||||
@ -871,6 +900,16 @@ objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
|
||||
return dump_result(&dc);
|
||||
}
|
||||
|
||||
/* :nodoc: */
|
||||
static VALUE
|
||||
objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
|
||||
{
|
||||
VALUE args[2];
|
||||
args[0] = output;
|
||||
args[1] = shapes;
|
||||
return rb_vm_lock_with_barrier(dump_shapes_locked, (void*)args);
|
||||
}
|
||||
|
||||
void
|
||||
Init_objspace_dump(VALUE rb_mObjSpace)
|
||||
{
|
||||
@ -878,6 +917,9 @@ Init_objspace_dump(VALUE rb_mObjSpace)
|
||||
#if 0
|
||||
rb_mObjSpace = rb_define_module("ObjectSpace"); /* let rdoc know */
|
||||
#endif
|
||||
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
||||
RB_EXT_RACTOR_SAFE(true);
|
||||
#endif
|
||||
|
||||
rb_define_module_function(rb_mObjSpace, "_dump", objspace_dump, 2);
|
||||
rb_define_module_function(rb_mObjSpace, "_dump_all", objspace_dump_all, 4);
|
||||
|
||||
@ -827,6 +827,27 @@ class TestObjSpace < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
def test_dump_all_with_ractors
|
||||
assert_ractor("#{<<-"begin;"}#{<<-'end;'}")
|
||||
begin;
|
||||
require "objspace"
|
||||
require "tempfile"
|
||||
require "json"
|
||||
rs = 4.times.map do
|
||||
Ractor.new do
|
||||
Tempfile.create do |f|
|
||||
ObjectSpace.dump_all(output: f)
|
||||
f.close
|
||||
File.readlines(f.path).each do |line|
|
||||
JSON.parse(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rs.each(&:join)
|
||||
end;
|
||||
end
|
||||
|
||||
def test_dump_uninitialized_file
|
||||
assert_in_out_err(%[-robjspace], <<-RUBY) do |(output), (error)|
|
||||
puts ObjectSpace.dump(File.allocate)
|
||||
|
||||
11
vm_sync.c
11
vm_sync.c
@ -297,3 +297,14 @@ rb_ec_vm_lock_rec_release(const rb_execution_context_t *ec,
|
||||
|
||||
VM_ASSERT(recorded_lock_rec == rb_ec_vm_lock_rec(ec));
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_vm_lock_with_barrier(VALUE (*func)(void *args), void *args)
|
||||
{
|
||||
VALUE result = 0;
|
||||
RB_VM_LOCKING() {
|
||||
rb_vm_barrier();
|
||||
result = func(args);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -28,6 +28,10 @@ void rb_vm_lock_leave_body_nb(unsigned int *lev APPEND_LOCATION_ARGS);
|
||||
void rb_vm_lock_leave_body(unsigned int *lev APPEND_LOCATION_ARGS);
|
||||
void rb_vm_barrier(void);
|
||||
|
||||
RUBY_SYMBOL_EXPORT_BEGIN
|
||||
VALUE rb_vm_lock_with_barrier(VALUE (*func)(void *args), void *args);
|
||||
RUBY_SYMBOL_EXPORT_END
|
||||
|
||||
#if RUBY_DEBUG
|
||||
// GET_VM()
|
||||
#include "vm_core.h"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user