* bignum.c (bigdivrem): optimize the way to retry calculation of

bigdivrem so that the calculation is started from the point where
  the last interruption was occurred.

* bignum.c (bigdivrem1): ditto.

* test/ruby/test_bignum.rb: add a test case for rb_bigdivrem in the
  case that an interruption is occurred during bigdivrem1 is running.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37899 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
mrkn 2012-11-27 12:46:32 +00:00
parent 956cc2934d
commit 1dce5edf99
3 changed files with 56 additions and 15 deletions

View File

@ -1,3 +1,14 @@
Tue Nov 27 21:29:00 2012 Kenta Murata <mrkn@mrkn.jp>
* bignum.c (bigdivrem): optimize the way to retry calculation of
bigdivrem so that the calculation is started from the point where
the last interruption was occurred.
* bignum.c (bigdivrem1): ditto.
* test/ruby/test_bignum.rb: add a test case for rb_bigdivrem in the
case that an interruption is occurred during bigdivrem1 is running.
Tue Nov 27 19:56:43 2012 Koichi Sasada <ko1@atdot.net>
* vm.c (rb_vm_make_env_object): make Proc object if Env is possible

View File

@ -2655,7 +2655,7 @@ rb_big_mul(VALUE x, VALUE y)
}
struct big_div_struct {
long nx, ny;
long nx, ny, j, nyzero;
BDIGIT *yds, *zds;
volatile VALUE stop;
};
@ -2664,21 +2664,23 @@ static void *
bigdivrem1(void *ptr)
{
struct big_div_struct *bds = (struct big_div_struct*)ptr;
long nx = bds->nx, ny = bds->ny;
long i, j, nyzero;
long ny = bds->ny;
long i, j;
BDIGIT *yds = bds->yds, *zds = bds->zds;
BDIGIT_DBL t2;
BDIGIT_DBL_SIGNED num;
BDIGIT q;
j = nx==ny?nx+1:nx;
for (nyzero = 0; !yds[nyzero]; nyzero++);
j = bds->j;
do {
if (bds->stop) return 0;
if (bds->stop) {
bds->j = j;
return 0;
}
if (zds[j] == yds[ny-1]) q = (BDIGIT)BIGRAD-1;
else q = (BDIGIT)((BIGUP(zds[j]) + zds[j-1])/yds[ny-1]);
if (q) {
i = nyzero; num = 0; t2 = 0;
i = bds->nyzero; num = 0; t2 = 0;
do { /* multiply and subtract */
BDIGIT_DBL ee;
t2 += (BDIGIT_DBL)yds[i] * q;
@ -2713,22 +2715,16 @@ rb_big_stop(void *ptr)
}
static VALUE
bigdivrem(VALUE x, VALUE y_, volatile VALUE *divp, volatile VALUE *modp)
bigdivrem(VALUE x, VALUE y, volatile VALUE *divp, volatile VALUE *modp)
{
VALUE y;
struct big_div_struct bds;
long nx, ny;
long nx = RBIGNUM_LEN(x), ny = RBIGNUM_LEN(y);
long i, j;
VALUE z, yy, zz;
BDIGIT *xds, *yds, *zds, *tds;
BDIGIT_DBL t2;
BDIGIT dd, q;
retry:
y = y_;
nx = RBIGNUM_LEN(x);
ny = RBIGNUM_LEN(y);
if (BIGZEROP(y)) rb_num_zerodiv();
xds = BDIGITS(x);
yds = BDIGITS(y);
@ -2799,7 +2795,11 @@ bigdivrem(VALUE x, VALUE y_, volatile VALUE *divp, volatile VALUE *modp)
bds.zds = zds;
bds.yds = yds;
bds.stop = Qfalse;
bds.j = nx==ny?nx+1:nx;
for (bds.nyzero = 0; !yds[bds.nyzero]; bds.nyzero++);
if (nx > 10000 || ny > 10000) {
retry:
bds.stop = Qfalse;
rb_thread_call_without_gvl(bigdivrem1, &bds, rb_big_stop, &bds);
if (bds.stop == Qtrue) {

View File

@ -581,6 +581,36 @@ class TestBignum < Test::Unit::TestCase
assert_interrupt {(65536 ** 65536).to_s}
end
def test_interrupt_during_bigdivrem
return unless Process.respond_to?(:kill)
begin
trace = []
oldtrap = Signal.trap(:INT) {|sig| trace << :int }
a = 456 ** 100
b = 123 ** 100
c = nil
100.times do |n|
a **= 3
b **= 3
trace.clear
th = Thread.new do
sleep 0.1; Process.kill :INT, $$
sleep 0.1; Process.kill :INT, $$
end
c = a / b
trace << :end
th.join
if trace == [:int, :int, :end]
assert_equal(a / b, c)
return
end
end
skip "cannot create suitable test case"
ensure
Signal.trap(:INT, oldtrap) if oldtrap
end
end
def test_too_big_to_s
if (big = 2**31-1).is_a?(Fixnum)
return