Skip to content

Commit

Permalink
Don't call rb_str_set_len while released the GVL.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Nov 1, 2024
1 parent bce161f commit ef0d339
Showing 1 changed file with 66 additions and 62 deletions.
128 changes: 66 additions & 62 deletions ext/zlib/zlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}

/*
Expand All @@ -1088,6 +1043,63 @@ zstream_unblock_func(void *ptr)
args->interrupt = 1;
}

static int zstream_run_func(struct zstream_run_args *args)
{
struct zstream *z = args->z;

int err = Z_OK;
int state;

while (!args->interrupt) {
uInt 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;
args->jump_state = state;
break;
}
}

return err;
}

static VALUE
zstream_run_try(VALUE value_arg)
{
Expand All @@ -1097,7 +1109,6 @@ zstream_run_try(VALUE value_arg)
long len = args->len;
int flush = args->flush;

int err;
VALUE old_input = Qnil;

/* Cannot start zstream while it is in progress. */
Expand Down Expand Up @@ -1126,14 +1137,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
int err = zstream_run_func(args);

/* retry if no exception is thrown */
if (err == Z_OK && args->interrupt) {
Expand Down

0 comments on commit ef0d339

Please sign in to comment.