[前][次][番号順一覧][スレッド一覧]

ruby-changes:25842

From: mrkn <ko1@a...>
Date: Tue, 27 Nov 2012 21:46:46 +0900 (JST)
Subject: [ruby-changes:25842] mrkn:r37899 (trunk): * bignum.c (bigdivrem): optimize the way to retry calculation of

mrkn	2012-11-27 21:46:32 +0900 (Tue, 27 Nov 2012)

  New Revision: 37899

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=37899

  Log:
    * 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.

  Modified files:
    trunk/ChangeLog
    trunk/bignum.c
    trunk/test/ruby/test_bignum.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 37898)
+++ ChangeLog	(revision 37899)
@@ -1,3 +1,14 @@
+Tue Nov 27 21:29:00 2012  Kenta Murata  <mrkn@m...>
+
+	* 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@a...>
 
 	* vm.c (rb_vm_make_env_object): make Proc object if Env is possible
Index: bignum.c
===================================================================
--- bignum.c	(revision 37898)
+++ bignum.c	(revision 37899)
@@ -2655,7 +2655,7 @@
 }
 
 struct big_div_struct {
-    long nx, ny;
+    long nx, ny, j, nyzero;
     BDIGIT *yds, *zds;
     volatile VALUE stop;
 };
@@ -2664,21 +2664,23 @@
 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 @@
 }
 
 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 @@
     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) {
Index: test/ruby/test_bignum.rb
===================================================================
--- test/ruby/test_bignum.rb	(revision 37898)
+++ test/ruby/test_bignum.rb	(revision 37899)
@@ -581,6 +581,36 @@
     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

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]