Correctly release the underlying file mapping. (#9340)
* Avoiding using `Tempfile` which was retaining the file preventing it from unlinking.
This commit is contained in:
parent
5af64ff7db
commit
260bf60e52
@ -58,6 +58,9 @@ enum rb_io_buffer_flags {
|
||||
|
||||
// The buffer is read-only and cannot be modified.
|
||||
RB_IO_BUFFER_READONLY = 128,
|
||||
|
||||
// The buffer is backed by a file.
|
||||
RB_IO_BUFFER_FILE = 256,
|
||||
};
|
||||
|
||||
// Represents the endian of the data types.
|
||||
|
40
io_buffer.c
40
io_buffer.c
@ -155,17 +155,7 @@ io_buffer_map_file(struct rb_io_buffer *buffer, int descriptor, size_t size, rb_
|
||||
buffer->size = size;
|
||||
|
||||
buffer->flags |= RB_IO_BUFFER_MAPPED;
|
||||
}
|
||||
|
||||
// Release the memory associated with a mapped buffer.
|
||||
static inline void
|
||||
io_buffer_unmap(void* base, size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap(base, size);
|
||||
#endif
|
||||
buffer->flags |= RB_IO_BUFFER_FILE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -234,7 +224,16 @@ io_buffer_free(struct rb_io_buffer *buffer)
|
||||
}
|
||||
|
||||
if (buffer->flags & RB_IO_BUFFER_MAPPED) {
|
||||
io_buffer_unmap(buffer->base, buffer->size);
|
||||
#ifdef _WIN32
|
||||
if (buffer->flags & RB_IO_BUFFER_FILE) {
|
||||
UnmapViewOfFile(buffer->base);
|
||||
}
|
||||
else {
|
||||
VirtualFree(buffer->base, 0, MEM_RELEASE);
|
||||
}
|
||||
#else
|
||||
munmap(buffer->base, buffer->size);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Previously we had this, but we found out due to the way GC works, we
|
||||
@ -245,12 +244,6 @@ io_buffer_free(struct rb_io_buffer *buffer)
|
||||
|
||||
buffer->base = NULL;
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (buffer->mapping) {
|
||||
CloseHandle(buffer->mapping);
|
||||
buffer->mapping = NULL;
|
||||
}
|
||||
#endif
|
||||
buffer->size = 0;
|
||||
buffer->flags = 0;
|
||||
buffer->source = Qnil;
|
||||
@ -258,6 +251,13 @@ io_buffer_free(struct rb_io_buffer *buffer)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (buffer->mapping) {
|
||||
CloseHandle(buffer->mapping);
|
||||
buffer->mapping = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -926,6 +926,10 @@ rb_io_buffer_to_s(VALUE self)
|
||||
rb_str_cat2(result, " MAPPED");
|
||||
}
|
||||
|
||||
if (buffer->flags & RB_IO_BUFFER_FILE) {
|
||||
rb_str_cat2(result, " FILE");
|
||||
}
|
||||
|
||||
if (buffer->flags & RB_IO_BUFFER_SHARED) {
|
||||
rb_str_cat2(result, " SHARED");
|
||||
}
|
||||
|
@ -519,23 +519,22 @@ class TestIOBuffer < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def test_private
|
||||
omit if RUBY_PLATFORM =~ /mswin|mingw/
|
||||
tmpdir = Dir.tmpdir
|
||||
buffer_path = File.join(tmpdir, "buffer.txt")
|
||||
File.write(buffer_path, "Hello World")
|
||||
|
||||
Tempfile.create("buffer.txt") do |io|
|
||||
io.write("Hello World")
|
||||
|
||||
buffer = IO::Buffer.map(io, nil, 0, IO::Buffer::PRIVATE)
|
||||
File.open(buffer_path) do |file|
|
||||
buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
|
||||
assert buffer.private?
|
||||
refute buffer.readonly?
|
||||
|
||||
buffer.set_string("J")
|
||||
|
||||
# It was not changed because the mapping was private:
|
||||
io.seek(0)
|
||||
assert_equal "Hello World", io.read
|
||||
file.seek(0)
|
||||
assert_equal "Hello World", file.read
|
||||
ensure
|
||||
buffer&.free
|
||||
io&.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user