1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Add support for anonymous shared IO buffers. (#6580)

This commit is contained in:
Samuel Williams 2022-10-19 18:53:38 +13:00 committed by GitHub
parent f982a26374
commit fc3137ef54
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
Notes: git 2022-10-19 05:54:07 +00:00
Merged-By: ioquatix <samuel@codeotaku.com>
3 changed files with 52 additions and 3 deletions

View file

@ -37,6 +37,9 @@ enum rb_io_buffer_flags {
// A non-private mapping is marked as external. // A non-private mapping is marked as external.
RB_IO_BUFFER_MAPPED = 4, 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. // The buffer is locked and cannot be resized.
// More specifically, it means we can't change the base address or size. // 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. // A buffer is typically locked before a system call that uses the data.

View file

@ -47,7 +47,7 @@ struct rb_io_buffer {
}; };
static inline void * static inline void *
io_buffer_map_memory(size_t size) io_buffer_map_memory(size_t size, int flags)
{ {
#if defined(_WIN32) #if defined(_WIN32)
void * base = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); void * base = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
@ -56,7 +56,14 @@ io_buffer_map_memory(size_t size)
rb_sys_fail("io_buffer_map_memory:VirtualAlloc"); rb_sys_fail("io_buffer_map_memory:VirtualAlloc");
} }
#else #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) { if (base == MAP_FAILED) {
rb_sys_fail("io_buffer_map_memory:mmap"); 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
else { else {
// This buffer refers to external data. // This buffer refers to external data.
data->flags |= RB_IO_BUFFER_EXTERNAL; data->flags |= RB_IO_BUFFER_EXTERNAL;
data->flags |= RB_IO_BUFFER_SHARED;
} }
void *base = MapViewOfFile(mapping, access, (DWORD)(offset >> 32), (DWORD)(offset & 0xFFFFFFFF), size); 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
else { else {
// This buffer refers to external data. // This buffer refers to external data.
data->flags |= RB_IO_BUFFER_EXTERNAL; data->flags |= RB_IO_BUFFER_EXTERNAL;
data->flags |= RB_IO_BUFFER_SHARED;
access |= MAP_SHARED; access |= MAP_SHARED;
} }
@ -184,7 +193,7 @@ io_buffer_initialize(struct rb_io_buffer *data, void *base, size_t size, enum rb
base = calloc(size, 1); base = calloc(size, 1);
} }
else if (flags & RB_IO_BUFFER_MAPPED) { else if (flags & RB_IO_BUFFER_MAPPED) {
base = io_buffer_map_memory(size); base = io_buffer_map_memory(size, flags);
} }
if (!base) { if (!base) {
@ -655,6 +664,10 @@ rb_io_buffer_to_s(VALUE self)
rb_str_cat2(result, " MAPPED"); rb_str_cat2(result, " MAPPED");
} }
if (data->flags & RB_IO_BUFFER_SHARED) {
rb_str_cat2(result, " SHARED");
}
if (data->flags & RB_IO_BUFFER_LOCKED) { if (data->flags & RB_IO_BUFFER_LOCKED) {
rb_str_cat2(result, " LOCKED"); rb_str_cat2(result, " LOCKED");
} }
@ -879,6 +892,22 @@ rb_io_buffer_mapped_p(VALUE self)
return RBOOL(data->flags & RB_IO_BUFFER_MAPPED); 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 * call-seq: locked? -> true or false
* *
@ -3176,6 +3205,7 @@ Init_IO_Buffer(void)
rb_define_const(rb_cIOBuffer, "EXTERNAL", RB_INT2NUM(RB_IO_BUFFER_EXTERNAL)); 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, "INTERNAL", RB_INT2NUM(RB_IO_BUFFER_INTERNAL));
rb_define_const(rb_cIOBuffer, "MAPPED", RB_INT2NUM(RB_IO_BUFFER_MAPPED)); 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, "LOCKED", RB_INT2NUM(RB_IO_BUFFER_LOCKED));
rb_define_const(rb_cIOBuffer, "PRIVATE", RB_INT2NUM(RB_IO_BUFFER_PRIVATE)); rb_define_const(rb_cIOBuffer, "PRIVATE", RB_INT2NUM(RB_IO_BUFFER_PRIVATE));
rb_define_const(rb_cIOBuffer, "READONLY", RB_INT2NUM(RB_IO_BUFFER_READONLY)); rb_define_const(rb_cIOBuffer, "READONLY", RB_INT2NUM(RB_IO_BUFFER_READONLY));
@ -3191,6 +3221,7 @@ Init_IO_Buffer(void)
rb_define_method(rb_cIOBuffer, "external?", rb_io_buffer_external_p, 0); 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, "internal?", rb_io_buffer_internal_p, 0);
rb_define_method(rb_cIOBuffer, "mapped?", rb_io_buffer_mapped_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, "locked?", rb_io_buffer_locked_p, 0);
rb_define_method(rb_cIOBuffer, "readonly?", io_buffer_readonly_p, 0); rb_define_method(rb_cIOBuffer, "readonly?", io_buffer_readonly_p, 0);

View file

@ -403,4 +403,19 @@ class TestIOBuffer < Test::Unit::TestCase
assert_equal IO::Buffer.for("\x00\x01\x004\x00\x01\x004\x00\x01"), source.dup.xor!(mask) 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! assert_equal IO::Buffer.for("\xce\xcd\xcc\xcb\xce\xcd\xcc\xcb\xce\xcd"), source.dup.not!
end 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 end