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.
|
// 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.
|
||||||
|
|
37
io_buffer.c
37
io_buffer.c
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue