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

ruby-changes:74121

From: Samuel <ko1@a...>
Date: Wed, 19 Oct 2022 14:54:07 +0900 (JST)
Subject: [ruby-changes:74121] fc3137ef54 (master): Add support for anonymous shared IO buffers. (#6580)

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

From fc3137ef54562c3c3290245c0f62e0bb193c3145 Mon Sep 17 00:00:00 2001
From: Samuel Williams <samuel.williams@o...>
Date: Wed, 19 Oct 2022 18:53:38 +1300
Subject: Add support for anonymous shared IO buffers. (#6580)

---
 include/ruby/io/buffer.h    |  3 +++
 io_buffer.c                 | 37 ++++++++++++++++++++++++++++++++++---
 test/ruby/test_io_buffer.rb | 15 +++++++++++++++
 3 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/include/ruby/io/buffer.h b/include/ruby/io/buffer.h
index dd92db5bbe..88e5598066 100644
--- a/include/ruby/io/buffer.h
+++ b/include/ruby/io/buffer.h
@@ -37,6 +37,9 @@ enum rb_io_buffer_flags { https://github.com/ruby/ruby/blob/trunk/include/ruby/io/buffer.h#L37
     // A non-private mapping is marked as external.
     RB_IO_BUFFER_MAPPED = 4,
 
+    // A mapped buffer that is also shared.
+    RB_IO_BUFFER_SHARED = 8,
+
     // The buffer is locked and cannot be resized.
     // More specifically, it means we can't change the base address or size.
     // A buffer is typically locked before a system call that uses the data.
diff --git a/io_buffer.c b/io_buffer.c
index bc5fac8118..e252af3513 100644
--- a/io_buffer.c
+++ b/io_buffer.c
@@ -47,7 +47,7 @@ struct rb_io_buffer { https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L47
 };
 
 static inline void *
-io_buffer_map_memory(size_t size)
+io_buffer_map_memory(size_t size, int flags)
 {
 #if defined(_WIN32)
     void * base = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
@@ -56,7 +56,14 @@ io_buffer_map_memory(size_t size) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L56
         rb_sys_fail("io_buffer_map_memory:VirtualAlloc");
     }
 #else
-    void * base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+    int mmap_flags = MAP_ANONYMOUS;
+    if (flags & RB_IO_BUFFER_SHARED) {
+        mmap_flags |= MAP_SHARED;
+    } else {
+        mmap_flags |= MAP_PRIVATE;
+    }
+
+    void * base = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
 
     if (base == MAP_FAILED) {
         rb_sys_fail("io_buffer_map_memory:mmap");
@@ -93,6 +100,7 @@ io_buffer_map_file(struct rb_io_buffer *data, int descriptor, size_t size, rb_of https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L100
     else {
         // This buffer refers to external data.
         data->flags |= RB_IO_BUFFER_EXTERNAL;
+        data->flags |= RB_IO_BUFFER_SHARED;
     }
 
     void *base = MapViewOfFile(mapping, access, (DWORD)(offset >> 32), (DWORD)(offset & 0xFFFFFFFF), size);
@@ -119,6 +127,7 @@ io_buffer_map_file(struct rb_io_buffer *data, int descriptor, size_t size, rb_of https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L127
     else {
         // This buffer refers to external data.
         data->flags |= RB_IO_BUFFER_EXTERNAL;
+        data->flags |= RB_IO_BUFFER_SHARED;
         access |= MAP_SHARED;
     }
 
@@ -184,7 +193,7 @@ 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#L193
             base = calloc(size, 1);
         }
         else if (flags & RB_IO_BUFFER_MAPPED) {
-            base = io_buffer_map_memory(size);
+            base = io_buffer_map_memory(size, flags);
         }
 
         if (!base) {
@@ -655,6 +664,10 @@ rb_io_buffer_to_s(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L664
         rb_str_cat2(result, " MAPPED");
     }
 
+    if (data->flags & RB_IO_BUFFER_SHARED) {
+        rb_str_cat2(result, " SHARED");
+    }
+
     if (data->flags & RB_IO_BUFFER_LOCKED) {
         rb_str_cat2(result, " LOCKED");
     }
@@ -879,6 +892,22 @@ rb_io_buffer_mapped_p(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L892
     return RBOOL(data->flags & RB_IO_BUFFER_MAPPED);
 }
 
+/*
+ *  call-seq: shared? -> true or false
+ *
+ *  If the buffer is _shared_, meaning it references memory that can be shared
+ *  with other processes (and thus might change without being modified
+ *  locally).
+ */
+static VALUE
+rb_io_buffer_shared_p(VALUE self)
+{
+    struct rb_io_buffer *data = NULL;
+    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
+
+    return RBOOL(data->flags & RB_IO_BUFFER_SHARED);
+}
+
 /*
  *  call-seq: locked? -> true or false
  *
@@ -3176,6 +3205,7 @@ Init_IO_Buffer(void) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L3205
     rb_define_const(rb_cIOBuffer, "EXTERNAL", RB_INT2NUM(RB_IO_BUFFER_EXTERNAL));
     rb_define_const(rb_cIOBuffer, "INTERNAL", RB_INT2NUM(RB_IO_BUFFER_INTERNAL));
     rb_define_const(rb_cIOBuffer, "MAPPED", RB_INT2NUM(RB_IO_BUFFER_MAPPED));
+    rb_define_const(rb_cIOBuffer, "SHARED", RB_INT2NUM(RB_IO_BUFFER_SHARED));
     rb_define_const(rb_cIOBuffer, "LOCKED", RB_INT2NUM(RB_IO_BUFFER_LOCKED));
     rb_define_const(rb_cIOBuffer, "PRIVATE", RB_INT2NUM(RB_IO_BUFFER_PRIVATE));
     rb_define_const(rb_cIOBuffer, "READONLY", RB_INT2NUM(RB_IO_BUFFER_READONLY));
@@ -3191,6 +3221,7 @@ Init_IO_Buffer(void) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L3221
     rb_define_method(rb_cIOBuffer, "external?", rb_io_buffer_external_p, 0);
     rb_define_method(rb_cIOBuffer, "internal?", rb_io_buffer_internal_p, 0);
     rb_define_method(rb_cIOBuffer, "mapped?", rb_io_buffer_mapped_p, 0);
+    rb_define_method(rb_cIOBuffer, "shared?", rb_io_buffer_shared_p, 0);
     rb_define_method(rb_cIOBuffer, "locked?", rb_io_buffer_locked_p, 0);
     rb_define_method(rb_cIOBuffer, "readonly?", io_buffer_readonly_p, 0);
 
diff --git a/test/ruby/test_io_buffer.rb b/test/ruby/test_io_buffer.rb
index 95ed98e1f4..2204c3db09 100644
--- a/test/ruby/test_io_buffer.rb
+++ b/test/ruby/test_io_buffer.rb
@@ -403,4 +403,19 @@ class TestIOBuffer < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io_buffer.rb#L403
     assert_equal IO::Buffer.for("\x00\x01\x004\x00\x01\x004\x00\x01"), source.dup.xor!(mask)
     assert_equal IO::Buffer.for("\xce\xcd\xcc\xcb\xce\xcd\xcc\xcb\xce\xcd"), source.dup.not!
   end
+
+  def test_shared
+    message = "Hello World"
+    buffer = IO::Buffer.new(64, IO::Buffer::MAPPED | IO::Buffer::SHARED)
+
+    pid = fork do
+      buffer.set_string(message)
+    end
+
+    Process.wait(pid)
+    string = buffer.get_string(0, message.bytesize)
+    assert_equal message, string
+  rescue NotImplementedError
+    omit "Fork/shared memory is not supported."
+  end
 end
-- 
cgit v1.2.3


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

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