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:
parent
f982a26374
commit
fc3137ef54
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
|
@ -37,6 +37,9 @@ enum rb_io_buffer_flags {
|
|||
// 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.
|
||||
|
|
37
io_buffer.c
37
io_buffer.c
|
@ -47,7 +47,7 @@ struct rb_io_buffer {
|
|||
};
|
||||
|
||||
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)
|
|||
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
|
|||
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
|
|||
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
|
|||
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)
|
|||
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)
|
|||
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)
|
|||
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)
|
|||
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);
|
||||
|
||||
|
|
|
@ -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("\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
|
||||
|
|
Loading…
Reference in a new issue