Skip to content

Commit 56b67f1

Browse files
authored
ObjectSpace.{dump,dump_all,dump_shapes} needs vm barrier. (ruby#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"
1 parent 41e24ae commit 56b67f1

File tree

4 files changed

+85
-7
lines changed

4 files changed

+85
-7
lines changed

ext/objspace/objspace_dump.c

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#include "ruby/util.h"
3030
#include "ruby/io.h"
3131
#include "vm_callinfo.h"
32-
#include "vm_core.h"
32+
#include "vm_sync.h"
3333

3434
RUBY_EXTERN const char ruby_hexdigits[];
3535

@@ -771,22 +771,33 @@ dump_result(struct dump_config *dc)
771771
return dc->given_output;
772772
}
773773

774-
/* :nodoc: */
775774
static VALUE
776-
objspace_dump(VALUE os, VALUE obj, VALUE output)
775+
dump_locked(void *args_p)
777776
{
778777
struct dump_config dc = {0,};
778+
VALUE obj = ((VALUE*)args_p)[0];
779+
VALUE output = ((VALUE*)args_p)[1];
780+
779781
if (!RB_SPECIAL_CONST_P(obj)) {
780782
dc.cur_page_slot_size = rb_gc_obj_slot_size(obj);
781783
}
782-
783784
dump_output(&dc, output, Qnil, Qnil, Qnil);
784785

785786
dump_object(obj, &dc);
786787

787788
return dump_result(&dc);
788789
}
789790

791+
/* :nodoc: */
792+
static VALUE
793+
objspace_dump(VALUE os, VALUE obj, VALUE output)
794+
{
795+
VALUE args[2];
796+
args[0] = obj;
797+
args[1] = output;
798+
return rb_vm_lock_with_barrier(dump_locked, (void*)args);
799+
}
800+
790801
static void
791802
shape_id_i(shape_id_t shape_id, void *data)
792803
{
@@ -835,11 +846,15 @@ shape_id_i(shape_id_t shape_id, void *data)
835846
dump_append(dc, "}\n");
836847
}
837848

838-
/* :nodoc: */
839849
static VALUE
840-
objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
850+
dump_all_locked(void *args_p)
841851
{
842852
struct dump_config dc = {0,};
853+
VALUE output = ((VALUE*)args_p)[0];
854+
VALUE full = ((VALUE*)args_p)[1];
855+
VALUE since = ((VALUE*)args_p)[2];
856+
VALUE shapes = ((VALUE*)args_p)[3];
857+
843858
dump_output(&dc, output, full, since, shapes);
844859

845860
if (!dc.partial_dump || dc.since == 0) {
@@ -860,9 +875,23 @@ objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
860875

861876
/* :nodoc: */
862877
static VALUE
863-
objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
878+
objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
879+
{
880+
VALUE args[4];
881+
args[0] = output;
882+
args[1] = full;
883+
args[2] = since;
884+
args[3] = shapes;
885+
return rb_vm_lock_with_barrier(dump_all_locked, (void*)args);
886+
}
887+
888+
static VALUE
889+
dump_shapes_locked(void *args_p)
864890
{
865891
struct dump_config dc = {0,};
892+
VALUE output = ((VALUE*)args_p)[0];
893+
VALUE shapes = ((VALUE*)args_p)[1];
894+
866895
dump_output(&dc, output, Qfalse, Qnil, shapes);
867896

868897
if (RTEST(shapes)) {
@@ -871,13 +900,26 @@ objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
871900
return dump_result(&dc);
872901
}
873902

903+
/* :nodoc: */
904+
static VALUE
905+
objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
906+
{
907+
VALUE args[2];
908+
args[0] = output;
909+
args[1] = shapes;
910+
return rb_vm_lock_with_barrier(dump_shapes_locked, (void*)args);
911+
}
912+
874913
void
875914
Init_objspace_dump(VALUE rb_mObjSpace)
876915
{
877916
#undef rb_intern
878917
#if 0
879918
rb_mObjSpace = rb_define_module("ObjectSpace"); /* let rdoc know */
880919
#endif
920+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
921+
RB_EXT_RACTOR_SAFE(true);
922+
#endif
881923

882924
rb_define_module_function(rb_mObjSpace, "_dump", objspace_dump, 2);
883925
rb_define_module_function(rb_mObjSpace, "_dump_all", objspace_dump_all, 4);

test/objspace/test_objspace.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,27 @@ def dump_my_heap_please
827827
end
828828
end
829829

830+
def test_dump_all_with_ractors
831+
assert_ractor("#{<<-"begin;"}#{<<-'end;'}")
832+
begin;
833+
require "objspace"
834+
require "tempfile"
835+
require "json"
836+
rs = 4.times.map do
837+
Ractor.new do
838+
Tempfile.create do |f|
839+
ObjectSpace.dump_all(output: f)
840+
f.close
841+
File.readlines(f.path).each do |line|
842+
JSON.parse(line)
843+
end
844+
end
845+
end
846+
end
847+
rs.each(&:join)
848+
end;
849+
end
850+
830851
def test_dump_uninitialized_file
831852
assert_in_out_err(%[-robjspace], <<-RUBY) do |(output), (error)|
832853
puts ObjectSpace.dump(File.allocate)

vm_sync.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,14 @@ rb_ec_vm_lock_rec_release(const rb_execution_context_t *ec,
297297

298298
VM_ASSERT(recorded_lock_rec == rb_ec_vm_lock_rec(ec));
299299
}
300+
301+
VALUE
302+
rb_vm_lock_with_barrier(VALUE (*func)(void *args), void *args)
303+
{
304+
VALUE result = 0;
305+
RB_VM_LOCKING() {
306+
rb_vm_barrier();
307+
result = func(args);
308+
}
309+
return result;
310+
}

vm_sync.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ void rb_vm_lock_leave_body_nb(unsigned int *lev APPEND_LOCATION_ARGS);
2828
void rb_vm_lock_leave_body(unsigned int *lev APPEND_LOCATION_ARGS);
2929
void rb_vm_barrier(void);
3030

31+
RUBY_SYMBOL_EXPORT_BEGIN
32+
VALUE rb_vm_lock_with_barrier(VALUE (*func)(void *args), void *args);
33+
RUBY_SYMBOL_EXPORT_END
34+
3135
#if RUBY_DEBUG
3236
// GET_VM()
3337
#include "vm_core.h"

0 commit comments

Comments
 (0)