Skip to content

Commit 3c0b09a

Browse files
authored
Allow io_buffer_memmove to release the GVL for large buffers. (ruby#12021)
[Feature #20902]
1 parent 682ff52 commit 3c0b09a

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

NEWS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ Note: We're only listing outstanding class updates.
6666
* An optional `Fiber::Scheduler#blocking_operation_wait` hook allows blocking operations to be moved out of the
6767
event loop in order to reduce latency and improve multi-core processor utilization. [[Feature #20876]]
6868

69+
* IO::Buffer
70+
71+
* `IO::Buffer#copy` can release the GVL, allowing other threads to run while copying data. [[Feature #20902]]
72+
6973
## Stdlib updates
7074

7175
* Tempfile
@@ -242,3 +246,4 @@ details of the default gems or bundled gems.
242246
[Feature #20624]: https://bugs.ruby-lang.org/issues/20624
243247
[Feature #20775]: https://bugs.ruby-lang.org/issues/20775
244248
[Feature #20876]: https://bugs.ruby-lang.org/issues/20876
249+
[Feature #20902]: https://bugs.ruby-lang.org/issues/20902

common.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8816,6 +8816,7 @@ io_buffer.$(OBJEXT): {$(VPATH)}onigmo.h
88168816
io_buffer.$(OBJEXT): {$(VPATH)}oniguruma.h
88178817
io_buffer.$(OBJEXT): {$(VPATH)}st.h
88188818
io_buffer.$(OBJEXT): {$(VPATH)}subst.h
8819+
io_buffer.$(OBJEXT): {$(VPATH)}thread.h
88198820
io_buffer.$(OBJEXT): {$(VPATH)}thread_native.h
88208821
iseq.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
88218822
iseq.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h

io_buffer.c

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include "ruby/io/buffer.h"
1010
#include "ruby/fiber/scheduler.h"
1111

12+
// For `rb_nogvl`.
13+
#include "ruby/thread.h"
14+
1215
#include "internal.h"
1316
#include "internal/array.h"
1417
#include "internal/bits.h"
@@ -2327,6 +2330,30 @@ io_buffer_set_values(VALUE self, VALUE buffer_types, VALUE _offset, VALUE values
23272330
return SIZET2NUM(offset);
23282331
}
23292332

2333+
static size_t IO_BUFFER_BLOCKING_SIZE = 1024*1024;
2334+
2335+
struct io_buffer_memmove_arguments {
2336+
unsigned char * destination;
2337+
const unsigned char * source;
2338+
size_t length;
2339+
};
2340+
2341+
static void *
2342+
io_buffer_memmove_blocking(void *data)
2343+
{
2344+
struct io_buffer_memmove_arguments *arguments = (struct io_buffer_memmove_arguments *)data;
2345+
2346+
memmove(arguments->destination, arguments->source, arguments->length);
2347+
2348+
return NULL;
2349+
}
2350+
2351+
static void
2352+
io_buffer_memmove_unblock(void *data)
2353+
{
2354+
// No safe way to interrupt.
2355+
}
2356+
23302357
static void
23312358
io_buffer_memmove(struct rb_io_buffer *buffer, size_t offset, const void *source_base, size_t source_offset, size_t source_size, size_t length)
23322359
{
@@ -2340,8 +2367,16 @@ io_buffer_memmove(struct rb_io_buffer *buffer, size_t offset, const void *source
23402367
rb_raise(rb_eArgError, "The computed source range exceeds the size of the source buffer!");
23412368
}
23422369

2343-
if (length != 0) {
2344-
memmove((unsigned char*)base+offset, (const unsigned char*)source_base+source_offset, length);
2370+
struct io_buffer_memmove_arguments arguments = {
2371+
.destination = (unsigned char*)base+offset,
2372+
.source = (unsigned char*)source_base+source_offset,
2373+
.length = length
2374+
};
2375+
2376+
if (arguments.length >= IO_BUFFER_BLOCKING_SIZE) {
2377+
rb_nogvl(io_buffer_memmove_blocking, &arguments, io_buffer_memmove_unblock, &arguments, RB_NOGVL_OFFLOAD_SAFE);
2378+
} else if (arguments.length != 0) {
2379+
memmove(arguments.destination, arguments.source, arguments.length);
23452380
}
23462381
}
23472382

0 commit comments

Comments
 (0)