というように、GC を常に動かすというのは GC 関連の問題を発見
するのに有効なわけですが、パッチを当ててコンパイルし直すのは
面倒臭いので、GC.always というメソッドを加えたいのですが、ど
うでしょう?

GC 関連の問題は対象プラットフォームやコンパイラのバージョン・
最適化などで問題の起こりかたが変わるため、たとえ今 i386 で
-O2 なケースについて発見できたものを修正したとしても、全部修
正できるとはかぎりません。というわけで、問題が発見された時に
簡単に絞りこめるように、GC を常に動かすという挙動を簡単に選
べるといいと思うんですが。

あと名前については、disable, enable が他動詞なのに対して、
always がそうでないのが気になるのですが、なんか他にいい名前
を思いつく人はいませんか?

Index: gc.c
===================================================================
RCS file: /src/ruby/gc.c,v
retrieving revision 1.217
diff -u -p -r1.217 gc.c
--- gc.c	6 Dec 2005 07:52:17 -0000	1.217
+++ gc.c	11 Dec 2005 14:42:20 -0000
@@ -93,6 +93,12 @@ static void run_final(VALUE obj);
 static VALUE nomem_error;
 static int garbage_collect(void);
 
+static enum {
+    gc_disable = 0,
+    gc_enable = 1,
+    gc_always = 2
+} do_gc = gc_enable;
+
 void
 rb_memerror(void)
 {
@@ -117,7 +123,7 @@ ruby_xmalloc(size_t size)
     if (size == 0) size = 1;
     malloc_increase += size;
 
-    if (malloc_increase > malloc_limit) {
+    if (do_gc == gc_always || malloc_increase > malloc_limit) {
 	garbage_collect();
     }
     RUBY_CRITICAL(mem = malloc(size));
@@ -165,6 +171,7 @@ ruby_xrealloc(void *ptr, size_t size)
     if (!ptr) return ruby_xmalloc(size);
     if (size == 0) size = 1;
     malloc_increase += size;
+    if (do_gc == gc_always) garbage_collect();
     RUBY_CRITICAL(mem = realloc(ptr, size));
     if (!mem) {
 	if (garbage_collect()) {
@@ -195,18 +202,30 @@ ruby_xfree(void *x)
 	RUBY_CRITICAL(free(x));
 }
 
-static int dont_gc;
 static int during_gc;
 static int need_call_final = 0;
 static st_table *finalizer_table = 0;
 
+static VALUE
+gc_status(void)
+{
+    switch (do_gc) {
+    case gc_disable: return Qtrue;
+    case gc_enable: return Qfalse;
+    case gc_always: return ID2SYM(rb_intern("always"));
+    }
+}
 
 /*
  *  call-seq:
- *     GC.enable    => true or false
+ *     GC.enable    => true, false or :always
  *
- *  Enables garbage collection, returning <code>true</code> if garbage
- *  collection was previously disabled.
+ *  Enables garbage collection.
+ *  It returns previous GC status:
+ *
+ *  disable:: true
+ *  enable:: false
+ *  always:: :always
  *
  *     GC.disable   #=> false
  *     GC.enable    #=> true
@@ -217,18 +236,22 @@ static st_table *finalizer_table = 0;
 VALUE
 rb_gc_enable(void)
 {
-    int old = dont_gc;
+    VALUE old = gc_status();
 
-    dont_gc = Qfalse;
+    do_gc = gc_enable;
     return old;
 }
 
 /*
  *  call-seq:
- *     GC.disable    => true or false
+ *     GC.disable    => true, false or :always
+ *
+ *  Disables garbage collection.
+ *  It returns previous GC status:
  *
- *  Disables garbage collection, returning <code>true</code> if garbage
- *  collection was already disabled.
+ *  disable:: true
+ *  enable:: false
+ *  always:: :always
  *
  *     GC.disable   #=> false
  *     GC.disable   #=> true
@@ -238,9 +261,36 @@ rb_gc_enable(void)
 VALUE
 rb_gc_disable(void)
 {
-    int old = dont_gc;
+    VALUE old = gc_status();
+
+    do_gc = gc_disable;
+    return old;
+}
+
+/*
+ *  call-seq:
+ *     GC.always    => true, false or :always
+ *
+ *  Enables garbage collection.
+ *  GC will be always activated whenever possible.
+ *  It returns previous GC status:
+ *
+ *  disable:: true
+ *  enable:: false
+ *  always:: :always
+ *
+ *     GC.disable   #=> false
+ *     GC.always    #=> true
+ *     GC.always    #=> :always
+ *
+ */
+
+VALUE
+rb_gc_always(void)
+{
+    VALUE old = gc_status();
 
-    dont_gc = Qtrue;
+    do_gc = gc_always;
     return old;
 }
 
@@ -394,7 +444,7 @@ rb_newobj(void)
 {
     VALUE obj;
 
-    if (!freelist && !garbage_collect())
+    if ((do_gc == gc_always || !freelist) && !garbage_collect())
 	rb_memerror();
 
     obj = (VALUE)freelist;
@@ -1277,7 +1327,7 @@ garbage_collect(void)
 	rb_bug("cross-thread violation on rb_gc()");
     }
 #endif
-    if (dont_gc || during_gc) {
+    if (do_gc == gc_disable || during_gc) {
 	if (!freelist) {
 	    add_heap();
 	}
@@ -1879,6 +1929,7 @@ Init_GC(void)
     rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0);
     rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0);
     rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
+    rb_define_singleton_method(rb_mGC, "always", rb_gc_always, 0);
     rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
 
     rb_mObSpace = rb_define_module("ObjectSpace");
-- 
[田中 哲][たなか あきら][Tanaka Akira]