From 07652b7f232129ed404ac1d0a079e6315e87b687 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Fri, 1 Nov 2024 15:12:55 +1300 Subject: [PATCH] Don't call `rb_str_set_len` while released the GVL. --- ext/zlib/zlib.c | 128 +++++++++++++++++++++++++----------------------- 1 file changed, 67 insertions(+), 61 deletions(-) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 7b6cc4e..037cd96 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -720,17 +720,15 @@ zstream_expand_buffer_into(struct zstream *z, unsigned long size) } } -static void * -zstream_expand_buffer_protect(void *ptr) +static int +zstream_expand_buffer_protect(struct zstream *z) { - struct zstream *z = (struct zstream *)ptr; int state = 0; rb_protect((VALUE (*)(VALUE))zstream_expand_buffer, (VALUE)z, &state); - return (void *)(VALUE)state; + return state; } - static int zstream_expand_buffer_non_stream(struct zstream *z) { @@ -1023,57 +1021,14 @@ zstream_ensure_end(VALUE v) } static void * -zstream_run_func(void *ptr) +zstream_run_once(void *_arguments) { - struct zstream_run_args *args = (struct zstream_run_args *)ptr; - int err, state, flush = args->flush; - struct zstream *z = args->z; - uInt n; - - err = Z_OK; - while (!args->interrupt) { - n = z->stream.avail_out; - err = z->func->run(&z->stream, flush); - rb_str_set_len(z->buf, ZSTREAM_BUF_FILLED(z) + (n - z->stream.avail_out)); - - if (err == Z_STREAM_END) { - z->flags &= ~ZSTREAM_FLAG_IN_STREAM; - z->flags |= ZSTREAM_FLAG_FINISHED; - break; - } - - if (err != Z_OK && err != Z_BUF_ERROR) - break; - - if (z->stream.avail_out > 0) { - z->flags |= ZSTREAM_FLAG_IN_STREAM; - break; - } - - if (z->stream.avail_in == 0 && z->func == &inflate_funcs) { - /* break here because inflate() return Z_BUF_ERROR when avail_in == 0. */ - /* but deflate() could be called with avail_in == 0 (there's hidden buffer - in zstream->state) */ - z->flags |= ZSTREAM_FLAG_IN_STREAM; - break; - } + struct zstream_run_args *arguments = (struct zstream_run_args *)_arguments; + struct zstream *z = arguments->z; - if (args->stream_output) { - state = (int)(VALUE)rb_thread_call_with_gvl(zstream_expand_buffer_protect, - (void *)z); - } - else { - state = zstream_expand_buffer_non_stream(z); - } + uintptr_t error = z->func->run(&z->stream, arguments->flush); - if (state) { - err = Z_OK; /* buffer expanded but stream processing was stopped */ - args->jump_state = state; - break; - } - } - - return (void *)(VALUE)err; + return (void*)error; } /* @@ -1088,6 +1043,64 @@ zstream_unblock_func(void *ptr) args->interrupt = 1; } +static int +zstream_run_func(struct zstream_run_args *args) +{ + struct zstream *z = args->z; + int state; + uInt n; + + int err = Z_OK; + while (!args->interrupt) { + n = z->stream.avail_out; + +#ifndef RB_NOGVL_UBF_ASYNC_SAFE + err = (int)(VALUE)rb_thread_call_without_gvl(zstream_run_once, (void *)args, zstream_unblock_func, (void *)args); +#else + err = (int)(VALUE)rb_nogvl(zstream_run_once, (void *)args, zstream_unblock_func, (void *)args, RB_NOGVL_UBF_ASYNC_SAFE); +#endif + + rb_str_set_len(z->buf, ZSTREAM_BUF_FILLED(z) + (n - z->stream.avail_out)); + + if (err == Z_STREAM_END) { + z->flags &= ~ZSTREAM_FLAG_IN_STREAM; + z->flags |= ZSTREAM_FLAG_FINISHED; + break; + } + + if (err != Z_OK && err != Z_BUF_ERROR) + break; + + if (z->stream.avail_out > 0) { + z->flags |= ZSTREAM_FLAG_IN_STREAM; + break; + } + + if (z->stream.avail_in == 0 && z->func == &inflate_funcs) { + /* break here because inflate() return Z_BUF_ERROR when avail_in == 0. */ + /* but deflate() could be called with avail_in == 0 (there's hidden buffer + in zstream->state) */ + z->flags |= ZSTREAM_FLAG_IN_STREAM; + break; + } + + if (args->stream_output) { + state = zstream_expand_buffer_protect(z); + } + else { + state = zstream_expand_buffer_non_stream(z); + } + + if (state) { + err = Z_OK; /* buffer expanded but stream processing was stopped */ + args->jump_state = state; + break; + } + } + + return err; +} + static VALUE zstream_run_try(VALUE value_arg) { @@ -1126,14 +1139,7 @@ zstream_run_try(VALUE value_arg) } loop: -#ifndef RB_NOGVL_UBF_ASYNC_SAFE - err = (int)(VALUE)rb_thread_call_without_gvl(zstream_run_func, (void *)args, - zstream_unblock_func, (void *)args); -#else - err = (int)(VALUE)rb_nogvl(zstream_run_func, (void *)args, - zstream_unblock_func, (void *)args, - RB_NOGVL_UBF_ASYNC_SAFE); -#endif + err = zstream_run_func(args); /* retry if no exception is thrown */ if (err == Z_OK && args->interrupt) {