ruby-1.8.7-p77

ChangeLog

Mon Jan  5 11:14:39 2009  Nobuyoshi Nakada  <nobu@...>

	* eval.c (rb_thread_schedule): runs deferred finalizers.

	* gc.c (gc_sweep): sets rb_thread_pending to run deferred finalizers.

	* rubysig.h (CHECK_INTS): now checks rb_thread_pending even on
	  platforms where setitimer is not available.  [ruby-core:18045]

Mon Jan  5 11:14:39 2009  Nobuyoshi Nakada  <nobu@...>

	* rubysig.h (CHECK_INTS): gives the chance to perform to deferred
	  finalizers before explicit GC.start or the process termination.
	  [ruby-core:18045]

ソースコードの修正内容

Index: eval.c
===================================================================
--- eval.c	(.../v1_8_7_76)	(revision 22266)
+++ eval.c	(.../v1_8_7_77)	(revision 22266)
@@ -10948,6 +10948,7 @@
     }
 #endif
     rb_thread_pending = 0;
+    rb_gc_finalize_deferred();
     if (curr_thread == curr_thread->next
 	&& curr_thread->status == THREAD_RUNNABLE)
 	return;
Index: gc.c
===================================================================
--- gc.c	(.../v1_8_7_76)	(revision 22266)
+++ gc.c	(.../v1_8_7_77)	(revision 22266)
@@ -1187,6 +1187,7 @@
     /* clear finalization list */
     if (final_list) {
 	deferred_final_list = final_list;
+	rb_thread_pending = 1;
 	return;
     }
     free_unused_heaps();
Index: rubysig.h
===================================================================
--- rubysig.h	(.../v1_8_7_76)	(revision 22266)
+++ rubysig.h	(.../v1_8_7_77)	(revision 22266)
@@ -78,12 +78,12 @@
 void rb_trap_restore_mask _((void));
 
 RUBY_EXTERN int rb_thread_critical;
+RUBY_EXTERN int rb_thread_pending;
 void rb_thread_schedule _((void));
 #if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE)
-RUBY_EXTERN int rb_thread_pending;
 # define CHECK_INTS do {\
     if (!(rb_prohibit_interrupt || rb_thread_critical)) {\
-        if (rb_thread_pending) rb_thread_schedule();\
+	if (rb_thread_pending) rb_thread_schedule();\
 	if (rb_trap_pending) rb_trap_exec();\
     }\
 } while (0)
@@ -93,9 +93,9 @@
 #define THREAD_TICK 500
 #define CHECK_INTS do {\
     if (!(rb_prohibit_interrupt || rb_thread_critical)) {\
-	if (rb_thread_tick-- <= 0) {\
+	if (rb_thread_pending || rb_thread_tick-- <= 0) {\
 	    rb_thread_tick = THREAD_TICK;\
-            rb_thread_schedule();\
+	    rb_thread_schedule();\
 	}\
     }\
     if (rb_trap_pending) rb_trap_exec();\

不具合の内容や影響範囲

ruby 1.6 において、GC の直後にオブジェクトに関連づけた後処理 (finalizer) が実行されていました。しかし、ruby 1.8 ではプロセスが終了するか、GC.startの呼び出しにより GC の開始を明示的に指示しないと finalizer が実行されません。

修正内容や注意点

スレッドの切り替えが必要かどうかを判定する (rb_thread_schedule 関数を呼んだ) ときにも、finalizer を実行するようになります。
なお、この不具合に関連して、finalizer の中で特定のオブジェクトの操作をすると SEGV が発生する不具合がありましたが、finalizer を実行中であるというフラグ (rb_thread_pending) を用意することでこの不具合にも対応されています。安心ください。