summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKasumi Hanazuki <[email protected]>2025-04-01 19:45:37 +0000
committerJean Boussier <[email protected]>2025-06-17 07:57:02 +0200
commit8aac19d5987150cf5c45fee73c7a949ca472f488 ()
tree9534d20eaf5accf6efbb99f9a36d71a96318c6f4
parent4cc58c3a6fdb70de36f585e4ce8ad66b5db43938 (diff)
io_buffer: Reimplement dcompact for IO::Buffer
The `source` field in IO::Buffer can have a String or an IO::Buffer object, if not nil. - When the `source` is a String object. The `base` field points to the memory location of the String content, which can be embedded in RSTRING, and in that case, GC compaction can move the memory region along with the String object. Thus, IO::Buffer needs to pin the `source` object to prevent `base` pointer from becoming invalid. - When the `source` is an IO::Buffer, then `base` is a pointer to a malloced or mmapped memory region, managed by the source IO::Buffer. In this case, we don't need to pin the source IO::Buffer object, since the referred memory region won't get moved by GC. Closes: [Bug #21210]
Notes: Merged: https://.com/ruby/ruby/pull/13033
-rw-r--r--io_buffer.c15
-rw-r--r--test/ruby/test_io_buffer.rb13
2 files changed, 25 insertions, 3 deletions
@@ -273,10 +273,18 @@ io_buffer_free(struct rb_io_buffer *buffer)
}
static void
-rb_io_buffer_type_mark(void *_buffer)
{
struct rb_io_buffer *buffer = _buffer;
- rb_gc_mark(buffer->source);
}
static void
@@ -303,9 +311,10 @@ rb_io_buffer_type_size(const void *_buffer)
static const rb_data_type_t rb_io_buffer_type = {
.wrap_struct_name = "IO::Buffer",
.function = {
- .dmark = rb_io_buffer_type_mark,
.dfree = rb_io_buffer_type_free,
.dsize = rb_io_buffer_type_size,
},
.data = NULL,
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
@@ -693,4 +693,17 @@ class TestIOBuffer < Test::Unit::TestCase
buf.set_string('a', 0, 0)
assert_predicate buf, :empty?
end
end