zlib.release_gvl.3.patch

Eric Hodel, 06/26/2012 08:27 AM

Download (5.35 KB)

View differences:

ext/zlib/zlib.c (working copy)
72 72

  
73 73
struct zstream;
74 74
struct zstream_funcs;
75
struct zstream_run_args;
75 76
static void zstream_init(struct zstream*, const struct zstream_funcs*);
76 77
static void zstream_expand_buffer(struct zstream*);
77 78
static void zstream_expand_buffer_into(struct zstream*, unsigned long);
......
564 565
    inflateReset, inflateEnd, inflate,
565 566
};
566 567

  
568
struct zstream_run_args {
569
    struct zstream * z;
570
    int flush;
571
    int interrupt;
572
};
567 573

  
568 574
static voidpf
569 575
zlib_mem_alloc(voidpf opaque, uInt items, uInt size)
......
655 661
    }
656 662
}
657 663

  
664
static int
665
zstream_expand_buffer_without_gvl(struct zstream *z)
666
{
667
    char * new_str;
668
    long inc, len;
669

  
670
    if (RSTRING_LEN(z->buf) - z->buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
671
	z->stream.avail_out = ZSTREAM_AVAIL_OUT_STEP_MAX;
672
    }
673
    else {
674
	inc = z->buf_filled / 2;
675
	if (inc < ZSTREAM_AVAIL_OUT_STEP_MIN) {
676
	    inc = ZSTREAM_AVAIL_OUT_STEP_MIN;
677
	}
678

  
679
	len = z->buf_filled + inc;
680

  
681
	new_str = realloc(RSTRING(z->buf)->as.heap.ptr, len + 1);
682

  
683
	if (!new_str)
684
	    return 0;
685

  
686
	/* from rb_str_resize */
687
	RSTRING(z->buf)->as.heap.ptr = new_str;
688
	RSTRING(z->buf)->as.heap.ptr[len] = '\0'; /* sentinel */
689
	RSTRING(z->buf)->as.heap.len =
690
	    RSTRING(z->buf)->as.heap.aux.capa = len;
691

  
692
	z->stream.avail_out = (inc < ZSTREAM_AVAIL_OUT_STEP_MAX) ?
693
	    (int)inc : ZSTREAM_AVAIL_OUT_STEP_MAX;
694
    }
695
    z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled;
696

  
697
    return 1;
698
}
699

  
658 700
static void
659 701
zstream_append_buffer(struct zstream *z, const Bytef *src, long len)
660 702
{
......
871 913
    return Qnil;
872 914
}
873 915

  
916
static VALUE
917
zstream_run_func(void *ptr) {
918
    struct zstream_run_args *args = (struct zstream_run_args *)ptr;
919
    int err, flush = args->flush;
920
    struct zstream *z = args->z;
921
    uInt n;
922

  
923
    while (!args->interrupt) {
924
	n = z->stream.avail_out;
925
	err = z->func->run(&z->stream, flush);
926
	z->buf_filled += n - z->stream.avail_out;
927

  
928
	if (err == Z_STREAM_END) {
929
	    z->flags &= ~ZSTREAM_FLAG_IN_STREAM;
930
	    z->flags |= ZSTREAM_FLAG_FINISHED;
931
	    break;
932
	}
933

  
934
	if (err != Z_OK)
935
	    break;
936

  
937
	if (z->stream.avail_out > 0) {
938
	    z->flags |= ZSTREAM_FLAG_IN_STREAM;
939
	    break;
940
	}
941

  
942
	if (!zstream_expand_buffer_without_gvl(z)) {
943
	    err = Z_MEM_ERROR; /* realloc failed */
944
	    break;
945
	}
946
    }
947

  
948
    return (VALUE)err;
949
}
950

  
951
/*
952
 * There is no safe way to interrupt z->run->func().
953
 */
954
static void
955
zstream_unblock_func(void *ptr) {
956
    struct zstream_run_args *args = (struct zstream_run_args *)ptr;
957

  
958
    args->interrupt = 1;
959
}
960

  
874 961
static void
875 962
zstream_run(struct zstream *z, Bytef *src, long len, int flush)
876 963
{
877
    uInt n;
964
    struct zstream_run_args args;
878 965
    int err;
879 966
    volatile VALUE guard = Qnil;
880 967

  
968
    args.z = z;
969
    args.flush = flush;
970
    args.interrupt = 0;
971

  
881 972
    if (NIL_P(z->input) && len == 0) {
882 973
	z->stream.next_in = (Bytef*)"";
883 974
	z->stream.avail_in = 0;
......
896 987
	zstream_expand_buffer(z);
897 988
    }
898 989

  
899
    for (;;) {
900
	/* VC allocates err and guard to same address.  accessing err and guard
901
	   in same scope prevents it. */
902
	RB_GC_GUARD(guard);
903
	n = z->stream.avail_out;
904
	err = z->func->run(&z->stream, flush);
905
	z->buf_filled += n - z->stream.avail_out;
906
	rb_thread_schedule();
990
loop:
991
    err = (int)rb_thread_blocking_region(
992
	    zstream_run_func, (void *)&args,
993
	    zstream_unblock_func, (void *)&args);
994

  
995
    if (flush != Z_FINISH && err == Z_BUF_ERROR
996
	    && z->stream.avail_out > 0) {
997
	z->flags |= ZSTREAM_FLAG_IN_STREAM;
998
    }
907 999

  
908
	if (err == Z_STREAM_END) {
909
	    z->flags &= ~ZSTREAM_FLAG_IN_STREAM;
910
	    z->flags |= ZSTREAM_FLAG_FINISHED;
911
	    break;
1000
    zstream_reset_input(z);
1001

  
1002
    if (err != Z_OK && err != Z_STREAM_END) {
1003
	if (z->stream.avail_in > 0) {
1004
	    zstream_append_input(z, z->stream.next_in, z->stream.avail_in);
912 1005
	}
913
	if (err != Z_OK) {
914
	    if (flush != Z_FINISH && err == Z_BUF_ERROR
915
		&& z->stream.avail_out > 0) {
916
		z->flags |= ZSTREAM_FLAG_IN_STREAM;
917
		break;
1006
	if (err == Z_NEED_DICT) {
1007
	    VALUE self = (VALUE)z->stream.opaque;
1008
	    VALUE dicts = rb_ivar_get(self, id_dictionaries);
1009
	    VALUE dict = rb_hash_aref(dicts, rb_uint2inum(z->stream.adler));
1010
	    if (!NIL_P(dict)) {
1011
		rb_inflate_set_dictionary(self, dict);
1012
		goto loop;
918 1013
	    }
919
	    zstream_reset_input(z);
920
	    if (z->stream.avail_in > 0) {
921
		zstream_append_input(z, z->stream.next_in, z->stream.avail_in);
922
	    }
923
	    if (err == Z_NEED_DICT) {
924
		VALUE self = (VALUE)z->stream.opaque;
925
		VALUE dicts = rb_ivar_get(self, id_dictionaries);
926
		VALUE dict = rb_hash_aref(dicts, rb_uint2inum(z->stream.adler));
927
		if (!NIL_P(dict)) {
928
		    rb_inflate_set_dictionary(self, dict);
929
		    continue;
930
		}
931
	    }
932
	    raise_zlib_error(err, z->stream.msg);
933
	}
934
	if (z->stream.avail_out > 0) {
935
	    z->flags |= ZSTREAM_FLAG_IN_STREAM;
936
	    break;
937 1014
	}
938
	zstream_expand_buffer(z);
1015
	raise_zlib_error(err, z->stream.msg);
939 1016
    }
940 1017

  
941
    zstream_reset_input(z);
942 1018
    if (z->stream.avail_in > 0) {
943 1019
	zstream_append_input(z, z->stream.next_in, z->stream.avail_in);
944 1020
        guard = Qnil; /* prevent tail call to make guard effective */