* 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:
parent
956cc2934d
commit
1dce5edf99
11
ChangeLog
11
ChangeLog
@ -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
|
||||
|
30
bignum.c
30
bignum.c
@ -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) {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user