diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 05e2647..89c1d84 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -1080,7 +1080,7 @@ zstream_run_func(struct zstream_run_args *args) uInt n; int err = Z_OK; - while (!args->interrupt) { + while (1) { n = z->stream.avail_out; err = (int)(VALUE)rb_ensure(zstream_run_once_begin, (VALUE)args, zstream_run_once_ensure, (VALUE)args); @@ -1167,18 +1167,6 @@ zstream_run_try(VALUE value_arg) loop: err = zstream_run_func(args); - /* retry if no exception is thrown */ - if (err == Z_OK && args->interrupt) { - args->interrupt = 0; - - /* Retry only if both avail_in > 0 (more input to process) and avail_out > 0 - * (output buffer has space). If avail_out == 0, the buffer is full and should - * be consumed by the caller first. If avail_in == 0, there's nothing more to process. */ - if (z->stream.avail_in > 0 && z->stream.avail_out > 0) { - goto loop; - } - } - if (flush != Z_FINISH && err == Z_BUF_ERROR && z->stream.avail_out > 0) { z->flags |= ZSTREAM_FLAG_IN_STREAM; } diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb index 38f39e5..6b4e4a1 100644 --- a/test/zlib/test_zlib.rb +++ b/test/zlib/test_zlib.rb @@ -248,6 +248,37 @@ def test_close assert_raise(Zlib::Error) { z << "foo" } assert_raise(Zlib::Error) { z.reset } end + + # An interrupt must neither raise Zlib::BufError on a deflate call that + # already consumed all its input, nor stop Zlib::Deflate#finish before the + # stream ends. + def test_thread_wakeup_interrupt + pend 'fails' if RUBY_ENGINE == 'truffleruby' + + content = SecureRandom.random_bytes(256 * 1024) + outputs = [] + + thr = Thread.new do + 100.times do + z = Zlib::Deflate.new + outputs << (z.deflate(content) << z.finish) + z.close + end + end + + while thr.alive? + begin + thr.wakeup + rescue ThreadError + end + Thread.pass + end + thr.join + + outputs.each do |output| + assert_equal(content, Zlib::Inflate.inflate(output)) + end + end end class TestZlibInflate < Test::Unit::TestCase