[前][次][番号順一覧][スレッド一覧]

ruby-changes:70321

From: Samuel <ko1@a...>
Date: Sun, 19 Dec 2021 20:17:42 +0900 (JST)
Subject: [ruby-changes:70321] 56811617ab (master): Improve IO::Buffer resize and introduce ownership transfer.

https://git.ruby-lang.org/ruby.git/commit/?id=56811617ab

From 56811617ab4b7007aad10c794366115a671e4f29 Mon Sep 17 00:00:00 2001
From: Samuel Williams <samuel.williams@o...>
Date: Sun, 19 Dec 2021 17:05:57 +1300
Subject: Improve IO::Buffer resize and introduce ownership transfer.

---
 include/ruby/io/buffer.h    |   3 +-
 io_buffer.c                 | 190 ++++++++++++++++++++++++++++++++++----------
 scheduler.c                 |   2 +
 test/ruby/test_io_buffer.rb |  16 ++--
 4 files changed, 163 insertions(+), 48 deletions(-)

diff --git a/include/ruby/io/buffer.h b/include/ruby/io/buffer.h
index 70dc9a5df88..0ee0a005e8d 100644
--- a/include/ruby/io/buffer.h
+++ b/include/ruby/io/buffer.h
@@ -71,7 +71,8 @@ void rb_io_buffer_get_mutable(VALUE self, void **base, size_t *size); https://github.com/ruby/ruby/blob/trunk/include/ruby/io/buffer.h#L71
 void rb_io_buffer_get_immutable(VALUE self, const void **base, size_t *size);
 
 size_t rb_io_buffer_copy(VALUE self, VALUE source, size_t offset);
-void rb_io_buffer_resize(VALUE self, size_t size, size_t preserve);
+VALUE rb_io_buffer_transfer(VALUE self);
+void rb_io_buffer_resize(VALUE self, size_t size);
 void rb_io_buffer_clear(VALUE self, uint8_t value, size_t offset, size_t length);
 
 RBIMPL_SYMBOL_EXPORT_END()
diff --git a/io_buffer.c b/io_buffer.c
index bb296f48ec1..524756e041f 100644
--- a/io_buffer.c
+++ b/io_buffer.c
@@ -147,8 +147,6 @@ io_buffer_experimental(void) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L147
 static void
 io_buffer_initialize(struct rb_io_buffer *data, void *base, size_t size, enum rb_io_buffer_flags flags, VALUE source)
 {
-    io_buffer_experimental();
-
     data->flags = flags;
     data->size = size;
 
@@ -171,6 +169,17 @@ io_buffer_initialize(struct rb_io_buffer *data, void *base, size_t size, enum rb https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L169
     data->source = source;
 }
 
+static void
+io_buffer_zero(struct rb_io_buffer *data)
+{
+    data->base = NULL;
+    data->size = 0;
+#if defined(_WIN32)
+    data->mapping = NULL;
+#endif
+    data->source = Qnil;
+}
+
 static int
 io_buffer_free(struct rb_io_buffer *data)
 {
@@ -196,6 +205,8 @@ io_buffer_free(struct rb_io_buffer *data) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L205
         }
 #endif
 
+        data->size = 0;
+
         return 1;
     }
 
@@ -249,10 +260,7 @@ rb_io_buffer_type_allocate(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L260
     struct rb_io_buffer *data = NULL;
     VALUE instance = TypedData_Make_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
 
-    data->base = NULL;
-    data->size = 0;
-    data->flags = 0;
-    data->source = Qnil;
+    io_buffer_zero(data);
 
     return instance;
 }
@@ -260,6 +268,8 @@ rb_io_buffer_type_allocate(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L268
 VALUE
 rb_io_buffer_type_for(VALUE klass, VALUE string)
 {
+    io_buffer_experimental();
+
     StringValue(string);
 
     VALUE instance = rb_io_buffer_type_allocate(klass);
@@ -282,7 +292,7 @@ rb_io_buffer_new(void *base, size_t size, enum rb_io_buffer_flags flags) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L292
     struct rb_io_buffer *data = NULL;
     TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, data);
 
-    io_buffer_initialize(data, base, size, 0, Qnil);
+    io_buffer_initialize(data, base, size, flags, Qnil);
 
     return instance;
 }
@@ -290,6 +300,8 @@ rb_io_buffer_new(void *base, size_t size, enum rb_io_buffer_flags flags) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L300
 VALUE
 rb_io_buffer_map(VALUE io, size_t size, off_t offset, enum rb_io_buffer_flags flags)
 {
+    io_buffer_experimental();
+
     VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
 
     struct rb_io_buffer *data = NULL;
@@ -345,9 +357,22 @@ io_buffer_map(int argc, VALUE *argv, VALUE klass) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L357
     return rb_io_buffer_map(io, size, offset, flags);
 }
 
+// Compute the optimal allocation flags for a buffer of the given size.
+static inline enum rb_io_buffer_flags
+io_flags_for_size(size_t size)
+{
+    if (size > RUBY_IO_BUFFER_PAGE_SIZE) {
+        return RB_IO_BUFFER_MAPPED;
+    }
+
+    return RB_IO_BUFFER_INTERNAL;
+}
+
 VALUE
 rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self)
 {
+    io_buffer_experimental();
+
     if (argc < 0 || argc > 2) {
         rb_error_arity(argc, 0, 2);
     }
@@ -368,12 +393,7 @@ rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L393
         flags = RB_NUM2UINT(argv[1]);
     }
     else {
-        if (size > RUBY_IO_BUFFER_PAGE_SIZE) {
-            flags |= RB_IO_BUFFER_MAPPED;
-        }
-        else {
-            flags |= RB_IO_BUFFER_INTERNAL;
-        }
+        flags |= io_flags_for_size(size);
     }
 
     io_buffer_initialize(data, NULL, size, flags, Qnil);
@@ -433,6 +453,10 @@ rb_io_buffer_to_s(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L453
     rb_str_append(result, rb_class_name(CLASS_OF(self)));
     rb_str_catf(result, " %p+%"PRIdSIZE, data->base, data->size);
 
+    if (data->base == NULL) {
+        rb_str_cat2(result, " NULL");
+    }
+
     if (data->flags & RB_IO_BUFFER_INTERNAL) {
         rb_str_cat2(result, " INTERNAL");
     }
@@ -505,7 +529,10 @@ rb_io_buffer_inspect(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L529
     VALUE result = rb_io_buffer_to_s(self);
 
     if (io_buffer_validate(data)) {
-        io_buffer_hexdump(result, 16, data->base, data->size);
+        // Limit the maximum size genearted by inspect.
+        if (data->size <= 256) {
+            io_buffer_hexdump(result, 16, data->base, data->size);
+        }
     }
 
     return result;
@@ -520,6 +547,15 @@ rb_io_buffer_size(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L547
     return SIZET2NUM(data->size);
 }
 
+static VALUE
+rb_io_buffer_null_p(VALUE self)
+{
+    struct rb_io_buffer *data = NULL;
+    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
+
+    return data->base ? Qfalse : Qtrue;
+}
+
 static VALUE
 rb_io_buffer_external_p(VALUE self)
 {
@@ -565,6 +601,12 @@ rb_io_buffer_immutable_p(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L601
     return data->flags & RB_IO_BUFFER_IMMUTABLE ? Qtrue : Qfalse;
 }
 
+static int
+io_buffer_external_p(enum rb_io_buffer_flags flags)
+{
+    return !(flags & (RB_IO_BUFFER_INTERNAL | RB_IO_BUFFER_MAPPED));
+}
+
 VALUE
 rb_io_buffer_lock(VALUE self)
 {
@@ -773,43 +815,113 @@ io_buffer_copy(VALUE self, VALUE source, VALUE offset) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L815
     return RB_SIZE2NUM(size);
 }
 
-static int
-io_buffer_external_p(enum rb_io_buffer_flags flags)
+VALUE
+rb_io_buffer_transfer(VALUE self)
 {
-    return !(flags & (RB_IO_BUFFER_INTERNAL | RB_IO_BUFFER_MAPPED));
+    struct rb_io_buffer *data = NULL;
+    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
+
+    if (data->flags & RB_IO_BUFFER_LOCKED) {
+        rb_raise(rb_eRuntimeError, "Cannot transfer ownership of locked buffer!");
+    }
+
+    VALUE instance = rb_io_buffer_type_allocate(rb_class_of(self));
+    struct rb_io_buffer *transferred;
+    TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, transferred);
+
+    *transferred = *data;
+    io_buffer_zero(data);
+
+    return instance;
 }
 
-void
-rb_io_buffer_resize(VALUE self, size_t size, size_t preserve)
+static void
+io_buffer_resize_clear(struct rb_io_buffer *data, void* base, size_t size)
 {
-    struct rb_io_buffer *data = NULL, updated;
-    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
-
-    if (preserve > data->size) {
-        rb_raise(rb_eRuntimeError, "Preservation size bigger than buffer size!");
+    if (size > data->size) {
+        memset((unsigned char*)base+data->size, 0, size - data->size);
     }
+}
+
+static void
+io_buffer_resize_copy(struct rb_io_buffer *data, size_t size)
+{
+    // Slow path:
+    struct rb_io_buffer resized;
+    io_buffer_initialize(&resized, NULL, size, io_flags_for_size(size), Qnil);
 
-    if (preserve > size) {
-        rb_raise(rb_eRuntimeError, "Preservation size bigger than destination size!");
+    if (data->base) {
+        size_t preserve = data->size;
+        if (preserve > size) preserve = size;
+        memcpy(resized.base, data->base, preserve);
+
+        io_buffer_resize_clear(data, resized.base, size);
     }
 
+    io_buffer_free(data);
+    *data = resized;
+}
+
+void
+rb_io_buffer_resize(VALUE self, size_t size)
+{
+    struct rb_io_buffer *data = NULL;
+    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
+
     if (data->flags & RB_IO_BUFFER_LOCKED) {
         rb_raise(rb_eRuntimeError, "Cannot resize locked buffer!");
     }
 
-    // By virtue of this passing, we don't need to do any further validation on the buffer:
+    if (data->base == NULL) {
+        io_buffer_initialize(data, NULL, size, io_flags_for_size(size), Qnil);
+        return;
+    }
+
     if (io_buffer_external_p(data->flags)) {
         rb_raise(rb_eRuntimeError, "Cannot resize external buffer!");
     }
 
-    io_buffer_initialize(&updated, NULL, size, data->flags, data->source);
+#ifdef MREMAP_MAYMOVE
+    if (data->flags & RB_IO_BUFFER_MAPPED) {
+        void *base = mremap(data->base, data->size, size, MREMAP_MAYMOVE);
+
+        if (base == MAP_FAILED) {
+            rb_sys_fail("rb_io_buffer_resize:mremap");
+        }
+
+        io_buffer_resize_clear(data, base, size);
+
+        data->base = base;
+        data->size = size;
+
+        return;
+    }
+#endif
+
+    if (data->flags & RB_IO_BUFFER_INTERNAL) {
+        void *base = realloc(data->base, size);
+
+        if (!base) {
+            rb_sys_fail("rb_io_buffer_resize:realloc");
+        }
+
+        io_buffer_resize_clear(data, base, size);
 
- (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]