Index: ext/zlib/zlib.c =================================================================== --- ext/zlib/zlib.c (revision 36146) +++ ext/zlib/zlib.c (working copy) @@ -72,6 +72,7 @@ static void finalizer_warn(const char*); struct zstream; struct zstream_funcs; +struct zstream_run_args; static void zstream_init(struct zstream*, const struct zstream_funcs*); static void zstream_expand_buffer(struct zstream*); static void zstream_expand_buffer_into(struct zstream*, unsigned long); @@ -557,13 +558,17 @@ struct zstream { #define ZSTREAM_AVAIL_OUT_STEP_MIN 2048 static const struct zstream_funcs deflate_funcs = { - deflateReset, deflateEnd, deflate, + deflateReset, deflateEnd, deflate }; static const struct zstream_funcs inflate_funcs = { - inflateReset, inflateEnd, inflate, + inflateReset, inflateEnd, inflate }; +struct zstream_run_args { + struct zstream * z; + int flush; +}; static voidpf zlib_mem_alloc(voidpf opaque, uInt items, uInt size) @@ -871,13 +876,37 @@ zstream_end(struct zstream *z) return Qnil; } +static VALUE +zstream_run_func(void *ptr) { + struct zstream_run_args *args = (struct zstream_run_args *)ptr; + int err, flush = args->flush; + struct zstream *z = args->z; + uInt n; + + n = z->stream.avail_out; + err = z->func->run(&z->stream, flush); + z->buf_filled += n - z->stream.avail_out; + + return (VALUE)err; +} + +/* + * There is no safe way to interrupt z->run->func(). + */ +static void +zstream_unblock_func(void *ptr) { +} + static void zstream_run(struct zstream *z, Bytef *src, long len, int flush) { - uInt n; + struct zstream_run_args args; int err; volatile VALUE guard = Qnil; + args.z = z; + args.flush = flush; + if (NIL_P(z->input) && len == 0) { z->stream.next_in = (Bytef*)""; z->stream.avail_in = 0; @@ -900,10 +929,10 @@ zstream_run(struct zstream *z, Bytef *sr /* VC allocates err and guard to same address. accessing err and guard in same scope prevents it. */ RB_GC_GUARD(guard); - n = z->stream.avail_out; - err = z->func->run(&z->stream, flush); - z->buf_filled += n - z->stream.avail_out; - rb_thread_schedule(); + + err = (int)rb_thread_blocking_region( + zstream_run_func, (void *)&args, + zstream_unblock_func, NULL); if (err == Z_STREAM_END) { z->flags &= ~ZSTREAM_FLAG_IN_STREAM;