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

ruby-changes:34267

From: ko1 <ko1@a...>
Date: Wed, 4 Jun 2014 22:33:25 +0900 (JST)
Subject: [ruby-changes:34267] ko1:r46348 (trunk): * gc.c: introduce RZombie to manage zombie objects.

ko1	2014-06-04 22:33:20 +0900 (Wed, 04 Jun 2014)

  New Revision: 46348

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

  Log:
    * gc.c: introduce RZombie to manage zombie objects.
      Rewrite finalizing logics with this type.
    * gc.c (gc_verify_internal_consistency): verify zombie (finalizing)
      objects count.

  Modified files:
    trunk/ChangeLog
    trunk/gc.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 46347)
+++ ChangeLog	(revision 46348)
@@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Wed Jun  4 22:28:14 2014  Koichi Sasada  <ko1@a...>
+
+	* gc.c: introduce RZombie to manage zombie objects.
+	  Rewrite finalizing logics with this type.
+
+	* gc.c (gc_verify_internal_consistency): verify zombie (finalizing)
+	  objects count.
+
 Wed Jun  4 22:09:53 2014  Nobuyoshi Nakada  <nobu@r...>
 
 	* re.c (match_aref, rb_reg_regsub): consider encoding of captured
Index: gc.c
===================================================================
--- gc.c	(revision 46347)
+++ gc.c	(revision 46348)
@@ -454,7 +454,7 @@ typedef struct rb_objspace { https://github.com/ruby/ruby/blob/trunk/gc.c#L454
 
 	/* final */
 	size_t final_slots;
-	RVALUE *deferred_final;
+	VALUE deferred_final;
     } heap_pages;
 
     struct {
@@ -653,6 +653,15 @@ VALUE *ruby_initial_gc_stress_ptr = &rb_ https://github.com/ruby/ruby/blob/trunk/gc.c#L653
 
 #define RANY(o) ((RVALUE*)(o))
 
+struct RZombie {
+    struct RBasic basic;
+    VALUE next;
+    void (*dfree)(void *);
+    void *data;
+};
+
+#define RZOMBIE(o) ((struct RZombie *)(o))
+
 #define nomem_error GET_VM()->special_exceptions[ruby_error_nomemory]
 
 int ruby_gc_debug_indent = 0;
@@ -1516,20 +1525,21 @@ rb_free_const_table(st_table *tbl) https://github.com/ruby/ruby/blob/trunk/gc.c#L1525
 }
 
 static inline void
-make_deferred(rb_objspace_t *objspace,RVALUE *p)
+make_zombie(rb_objspace_t *objspace, VALUE obj, void (*dfree)(void *), void *data)
 {
-    p->as.basic.flags = T_ZOMBIE;
-    p->as.free.next = heap_pages_deferred_final;
-    heap_pages_deferred_final = p;
+    struct RZombie *zombie = RZOMBIE(obj);
+    zombie->basic.flags = T_ZOMBIE;
+    zombie->dfree = dfree;
+    zombie->data = data;
+    zombie->next = heap_pages_deferred_final;
+    heap_pages_deferred_final = (VALUE)zombie;
 }
 
 static inline void
-make_io_deferred(rb_objspace_t *objspace,RVALUE *p)
+make_io_zombie(rb_objspace_t *objspace, VALUE obj)
 {
-    rb_io_t *fptr = p->as.file.fptr;
-    make_deferred(objspace, p);
-    p->as.data.dfree = (void (*)(void*))rb_io_fptr_finalize;
-    p->as.data.data = fptr;
+    rb_io_t *fptr = RANY(obj)->as.file.fptr;
+    make_zombie(objspace, obj, (void (*)(void*))rb_io_fptr_finalize, fptr);
 }
 
 static int
@@ -1612,22 +1622,30 @@ obj_free(rb_objspace_t *objspace, VALUE https://github.com/ruby/ruby/blob/trunk/gc.c#L1622
       case T_DATA:
 	if (DATA_PTR(obj)) {
 	    int free_immediately = FALSE;
+	    void (*dfree)(void *);
+	    void *data = DATA_PTR(obj);
 
 	    if (RTYPEDDATA_P(obj)) {
 		free_immediately = (RANY(obj)->as.typeddata.type->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0;
-		RDATA(obj)->dfree = RANY(obj)->as.typeddata.type->function.dfree;
-		if (0 && free_immediately == 0) /* to expose non-free-immediate T_DATA */
+		dfree = RANY(obj)->as.typeddata.type->function.dfree;
+		if (0 && free_immediately == 0) {
+		    /* to expose non-free-immediate T_DATA */
 		    fprintf(stderr, "not immediate -> %s\n", RANY(obj)->as.typeddata.type->wrap_struct_name);
+		}
 	    }
-	    if (RANY(obj)->as.data.dfree == RUBY_DEFAULT_FREE) {
-		xfree(DATA_PTR(obj));
+	    else {
+		dfree = RANY(obj)->as.data.dfree;
 	    }
-	    else if (RANY(obj)->as.data.dfree) {
-		if (free_immediately) {
-		    (RDATA(obj)->dfree)(DATA_PTR(obj));
+
+	    if (dfree) {
+		if (dfree == RUBY_DEFAULT_FREE) {
+		    xfree(data);
+		}
+		else if (free_immediately) {
+		    (*dfree)(data);
 		}
 		else {
-		    make_deferred(objspace, RANY(obj));
+		    make_zombie(objspace, obj, dfree, data);
 		    return 1;
 		}
 	    }
@@ -1644,7 +1662,7 @@ obj_free(rb_objspace_t *objspace, VALUE https://github.com/ruby/ruby/blob/trunk/gc.c#L1662
 	break;
       case T_FILE:
 	if (RANY(obj)->as.file.fptr) {
-	    make_io_deferred(objspace, RANY(obj));
+	    make_io_zombie(objspace, obj);
 	    return 1;
 	}
 	break;
@@ -1707,7 +1725,13 @@ obj_free(rb_objspace_t *objspace, VALUE https://github.com/ruby/ruby/blob/trunk/gc.c#L1725
 	       BUILTIN_TYPE(obj), (void*)obj, RBASIC(obj)->flags);
     }
 
-    return 0;
+    if (FL_TEST(obj, FL_FINALIZE)) {
+	make_zombie(objspace, obj, 0, 0);
+	return 1;
+    }
+    else {
+	return 0;
+    }
 }
 
 void
@@ -2108,56 +2132,48 @@ run_finalizer(rb_objspace_t *objspace, V https://github.com/ruby/ruby/blob/trunk/gc.c#L2132
 }
 
 static void
-run_final(rb_objspace_t *objspace, VALUE obj)
+run_final(rb_objspace_t *objspace, VALUE zombie)
 {
-    RUBY_DATA_FUNC free_func = 0;
     st_data_t key, table;
 
-    heap_pages_final_slots--;
-
-    RBASIC_CLEAR_CLASS(obj);
-
-    if (RTYPEDDATA_P(obj)) {
-	free_func = RTYPEDDATA_TYPE(obj)->function.dfree;
-    }
-    else {
-	free_func = RDATA(obj)->dfree;
-    }
-    if (free_func) {
-	(*free_func)(DATA_PTR(obj));
+    if (RZOMBIE(zombie)->dfree) {
+	RZOMBIE(zombie)->dfree(RZOMBIE(zombie)->data);
     }
 
-    key = (st_data_t)obj;
+    key = (st_data_t)zombie;
     if (st_delete(finalizer_table, &key, &table)) {
-	run_finalizer(objspace, obj, (VALUE)table);
+	run_finalizer(objspace, zombie, (VALUE)table);
     }
 }
 
 static void
-finalize_list(rb_objspace_t *objspace, RVALUE *p)
+finalize_list(rb_objspace_t *objspace, VALUE zombie)
 {
-    while (p) {
-	RVALUE *tmp = p->as.free.next;
-	struct heap_page *page = GET_HEAP_PAGE(p);
+    while (zombie) {
+	VALUE next_zombie = RZOMBIE(zombie)->next;
+	struct heap_page *page = GET_HEAP_PAGE(zombie);
 
-	run_final(objspace, (VALUE)p);
-	objspace->profile.total_freed_object_num++;
+	run_final(objspace, zombie);
 
+	RZOMBIE(zombie)->basic.flags = 0;
+	heap_pages_final_slots--;
 	page->final_slots--;
-	heap_page_add_freeobj(objspace, GET_HEAP_PAGE(p), (VALUE)p);
+	heap_page_add_freeobj(objspace, GET_HEAP_PAGE(zombie), zombie);
+
 	heap_pages_swept_slots++;
+	objspace->profile.total_freed_object_num++;
 
-	p = tmp;
+	zombie = next_zombie;
     }
 }
 
 static void
 finalize_deferred(rb_objspace_t *objspace)
 {
-    RVALUE *p;
+    VALUE zombie;
 
-    while ((p = ATOMIC_PTR_EXCHANGE(heap_pages_deferred_final, 0)) != 0) {
-	finalize_list(objspace, p);
+    while ((zombie = (VALUE)ATOMIC_PTR_EXCHANGE(heap_pages_deferred_final, 0)) != 0) {
+	finalize_list(objspace, zombie);
     }
 }
 
@@ -2261,12 +2277,12 @@ rb_objspace_call_finalizer(rb_objspace_t https://github.com/ruby/ruby/blob/trunk/gc.c#L2277
 		    xfree(DATA_PTR(p));
 		}
 		else if (RANY(p)->as.data.dfree) {
-		    make_deferred(objspace, RANY(p));
+		    make_zombie(objspace, (VALUE)p, RANY(p)->as.data.dfree, RANY(p)->as.data.data);
 		}
 		break;
 	      case T_FILE:
 		if (RANY(p)->as.file.fptr) {
-		    make_io_deferred(objspace, RANY(p));
+		    make_io_zombie(objspace, (VALUE)p);
 		}
 		break;
 	    }
@@ -2591,7 +2607,7 @@ obj_memsize_of(VALUE obj, int use_tdata) https://github.com/ruby/ruby/blob/trunk/gc.c#L2607
 	break;
 
       case T_ZOMBIE:
-	break;
+	/* fall through */
 
       default:
 	rb_bug("objspace/memsize_of(): unknown data type 0x%x(%p)",
@@ -2804,11 +2820,6 @@ gc_page_sweep(rb_objspace_t *objspace, r https://github.com/ruby/ruby/blob/trunk/gc.c#L2820
 			if (obj_free(objspace, (VALUE)p)) {
 			    final_slots++;
 			}
-			else if (FL_TEST(p, FL_FINALIZE)) {
-			    RDATA(p)->dfree = 0;
-			    make_deferred(objspace,p);
-			    final_slots++;
-			}
 			else {
 			    (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
 			    heap_page_add_freeobj(objspace, sweep_page, (VALUE)p);
@@ -2849,6 +2860,7 @@ gc_page_sweep(rb_objspace_t *objspace, r https://github.com/ruby/ruby/blob/trunk/gc.c#L2860
 	    sweep_page->free_next = NULL;
 	}
     }
+
     heap_pages_swept_slots += freed_slots + empty_slots;
     objspace->profile.total_freed_object_num += freed_slots;
     heap_pages_final_slots += final_slots;
@@ -3053,7 +3065,7 @@ gc_after_sweep(rb_objspace_t *objspace) https://github.com/ruby/ruby/blob/trunk/gc.c#L3065
 #endif
 
 #if RGENGC_CHECK_MODE >= 2
-	gc_verify_internal_consistency(Qnil);
+    gc_verify_internal_consistency(Qnil);
 #endif
 
     gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_END_SWEEP, 0);
@@ -4506,6 +4518,7 @@ struct verify_internal_consistency_struc https://github.com/ruby/ruby/blob/trunk/gc.c#L4518
 #if RGENGC_AGE2_PROMOTION
     size_t young_object_count;
 #endif
+    size_t zombie_object_count;
     VALUE parent;
 };
 
@@ -4546,13 +4559,18 @@ verify_internal_consistency_i(void *page https://github.com/ruby/ruby/blob/trunk/gc.c#L4559
 		data->young_object_count++;
 	    }
 #endif
-
 	    if (RVALUE_OLD_P(v)) {
 		data->parent = v;
 		/* reachable objects from an oldgen object should be old or (young with remember) */
 		rb_objspace_reachable_objects_from(v, verify_internal_consistency_reachable_i, (void *)data);
 	    }
 	}
+	else {
+	    if (BUILTIN_TYPE(v) == T_ZOMBIE) {
+		assert(RBASIC(v)->flags == T_ZOMBIE);
+		data->zombie_object_count++;
+	    }
+	}
     }
 
     return 0;
@@ -4574,16 +4592,9 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/gc.c#L4592
 gc_verify_internal_consistency(VALUE self)
 {
 #if USE_RGENGC
-    struct verify_internal_consistency_struct data;
+    struct verify_internal_consistency_struct data = {0};
     rb_objspace_t *objspace = &rb_objspace;
     data.objspace = objspace;
-    data.err_count = 0;
-
-    data.live_object_count = 0;
-    data.old_object_count = 0;
-#if RGENGC_AGE2_PROMOTION
-    data.young_object_count = 0;
-#endif
 
     {
 	struct each_obj_args eo_args;
@@ -4618,6 +4629,30 @@ gc_verify_internal_consistency(VALUE sel https://github.com/ruby/ruby/blob/trunk/gc.c#L4629
     }
 #endif
 
+    if (!finalizing) {
+	size_t list_count = 0;
+
+	{
+	    VALUE z = heap_pages_deferred_final;
+	    while (z) {
+		list_count++;
+		z = RZOMBIE(z)->next;
+	    }
+	}
+
+	if (heap_pages_final_slots != data.zombie_object_count ||
+	    heap_pages_final_slots != list_count) {
+
+	    rb_bug("inconsistent finalizing object count:\n"
+		   "  expect %"PRIuSIZE"\n"
+		   "  but    %"PRIuSIZE" zombies\n"
+		   "  heap_pages_deferred_final list has %"PRIuSIZE" items.",
+		   heap_pages_final_slots,
+		   data.zombie_object_count,
+		   list_count);
+	}
+    }
+
     return Qnil;
 }
 

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

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