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

ruby-changes:31304

From: ko1 <ko1@a...>
Date: Tue, 22 Oct 2013 15:24:59 +0900 (JST)
Subject: [ruby-changes:31304] ko1:r43383 (trunk): * vm_trace.c: exterminate Zombies.

ko1	2013-10-22 15:24:54 +0900 (Tue, 22 Oct 2013)

  New Revision: 43383

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

  Log:
    * vm_trace.c: exterminate Zombies.
      There is a bug that T_ZOMBIE objects are not collected.
      Because there is a pass to miss finalizer postponed job
      with multi-threading. This patch solve this issue.
    * vm_trace.c (rb_postponed_job_register_one): set
      RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(th) if another same job
      is registered.
      There is a possibility to remain a postponed job without
      interrupt flag.
    * vm_trace.c (rb_postponed_job_register_one): check interrupt
      carefully.
    * vm_trace.c (rb_postponed_job_register_one): use additional space
      to avoid buffer full.
    * gc.c (gc_finalize_deferred_register): check failure.
    * thread.c (rb_threadptr_execute_interrupts): check
      `postponed_job_interrupt' immediately.  There is a possibility
      to miss this flag.

  Modified files:
    trunk/ChangeLog
    trunk/gc.c
    trunk/thread.c
    trunk/vm_trace.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 43382)
+++ ChangeLog	(revision 43383)
@@ -1,3 +1,28 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Oct 22 14:53:11 2013  Koichi Sasada  <ko1@a...>
+
+	* vm_trace.c: exterminate Zombies.
+	  There is a bug that T_ZOMBIE objects are not collected.
+	  Because there is a pass to miss finalizer postponed job
+	  with multi-threading. This patch solve this issue.
+
+	* vm_trace.c (rb_postponed_job_register_one): set 
+	  RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(th) if another same job
+	  is registered.
+	  There is a possibility to remain a postponed job without
+	  interrupt flag.
+
+	* vm_trace.c (rb_postponed_job_register_one): check interrupt
+	  carefully.
+
+	* vm_trace.c (rb_postponed_job_register_one): use additional space
+	  to avoid buffer full.
+
+	* gc.c (gc_finalize_deferred_register): check failure.
+
+	* thread.c (rb_threadptr_execute_interrupts): check
+	  `postponed_job_interrupt' immediately.  There is a possibility
+	  to miss this flag.
+
 Tue Oct 22 12:11:16 2013  Nobuyoshi Nakada  <nobu@r...>
 
 	* configure.in: check if the given CFLAGS and LDFLAGS are working, and
Index: thread.c
===================================================================
--- thread.c	(revision 43382)
+++ thread.c	(revision 43383)
@@ -1956,6 +1956,10 @@ rb_threadptr_execute_interrupts(rb_threa https://github.com/ruby/ruby/blob/trunk/thread.c#L1956
 	postponed_job_interrupt = interrupt & POSTPONED_JOB_INTERRUPT_MASK;
 	trap_interrupt = interrupt & TRAP_INTERRUPT_MASK;
 
+	if (postponed_job_interrupt) {
+	    rb_postponed_job_flush(th->vm);
+	}
+
 	/* signal handling */
 	if (trap_interrupt && (th == th->vm->main_thread)) {
 	    enum rb_thread_status prev_status = th->status;
@@ -2004,10 +2008,6 @@ rb_threadptr_execute_interrupts(rb_threa https://github.com/ruby/ruby/blob/trunk/thread.c#L2008
 	    rb_thread_schedule_limits(limits_us);
 	}
     }
-
-    if (postponed_job_interrupt) {
-	rb_postponed_job_flush(th->vm);
-    }
 }
 
 void
Index: gc.c
===================================================================
--- gc.c	(revision 43382)
+++ gc.c	(revision 43383)
@@ -1821,7 +1821,9 @@ rb_gc_finalize_deferred(void) https://github.com/ruby/ruby/blob/trunk/gc.c#L1821
 static void
 gc_finalize_deferred_register()
 {
-    rb_postponed_job_register_one(0, gc_finalize_deferred, 0);
+    if (rb_postponed_job_register_one(0, gc_finalize_deferred, 0) == 0) {
+	rb_bug("gc_finalize_deferred_register: can't register finalizer.");
+    }
 }
 
 struct force_finalize_list {
Index: vm_trace.c
===================================================================
--- vm_trace.c	(revision 43382)
+++ vm_trace.c	(revision 43383)
@@ -1385,7 +1385,8 @@ typedef struct rb_postponed_job_struct { https://github.com/ruby/ruby/blob/trunk/vm_trace.c#L1385
     void *data;
 } rb_postponed_job_t;
 
-#define MAX_POSTPONED_JOB 1024
+#define MAX_POSTPONED_JOB                  1000
+#define MAX_POSTPONED_JOB_SPECIAL_ADDITION   24
 
 static void
 Init_postponed_job(void)
@@ -1395,22 +1396,25 @@ Init_postponed_job(void) https://github.com/ruby/ruby/blob/trunk/vm_trace.c#L1396
     vm->postponed_job_index = 0;
 }
 
-/* return 0 if job buffer is full */
-int
-rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data)
+enum postponed_job_register_result {
+    PJRR_SUCESS      = 0,
+    PJRR_FULL        = 1,
+    PJRR_INTERRUPTED = 2
+};
+
+static enum postponed_job_register_result
+postponed_job_register(rb_thread_t *th, rb_vm_t *vm,
+		       unsigned int flags, rb_postponed_job_func_t func, void *data, int max, int expected_index)
 {
-    rb_thread_t *th = GET_THREAD();
-    rb_vm_t *vm = th->vm;
     rb_postponed_job_t *pjob;
 
-    while (1) {
-	int index = vm->postponed_job_index;
-	if (index >= MAX_POSTPONED_JOB) return 0; /* failed */
-
-	if (ATOMIC_CAS(vm->postponed_job_index, index, index+1) == index) {
-	    pjob = &vm->postponed_job_buffer[index];
-	    break;
-	}
+    if (expected_index >= max) return PJRR_FULL; /* failed */
+
+    if (ATOMIC_CAS(vm->postponed_job_index, expected_index, expected_index+1) == expected_index) {
+	pjob = &vm->postponed_job_buffer[expected_index];
+    }
+    else {
+	return PJRR_INTERRUPTED;
     }
 
     pjob->flags = flags;
@@ -1420,25 +1424,50 @@ rb_postponed_job_register(unsigned int f https://github.com/ruby/ruby/blob/trunk/vm_trace.c#L1424
 
     RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(th);
 
-    return 1;
+    return PJRR_SUCESS;
 }
 
+
+/* return 0 if job buffer is full */
+int
+rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data)
+{
+    rb_thread_t *th = GET_THREAD();
+    rb_vm_t *vm = th->vm;
+
+  begin:
+    switch (postponed_job_register(th, vm, flags, func, data, MAX_POSTPONED_JOB, vm->postponed_job_index)) {
+      case PJRR_SUCESS     : return 1;
+      case PJRR_FULL       : return 0;
+      case PJRR_INTERRUPTED: goto begin;
+      default: rb_bug("unreachable\n");
+    }
+}
+
+/* return 0 if job buffer is full */
 int
 rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data)
 {
-    rb_vm_t *vm = GET_VM();
+    rb_thread_t *th = GET_THREAD();
+    rb_vm_t *vm = th->vm;
     rb_postponed_job_t *pjob;
-    int i;
+    int i, index;
 
-    /* TODO: this check is not signal safe, but I believe this is not critical prbolem */
-    for (i=0; i<vm->postponed_job_index; i++) {
+  begin:
+    index = vm->postponed_job_index;
+    for (i=0; i<index; i++) {
 	pjob = &vm->postponed_job_buffer[i];
 	if (pjob->func == func) {
+	    RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(th);
 	    return 2;
 	}
     }
-
-    return rb_postponed_job_register(flags, func, data);
+    switch (postponed_job_register(th, vm, flags, func, data, MAX_POSTPONED_JOB + MAX_POSTPONED_JOB_SPECIAL_ADDITION, index)) {
+      case PJRR_SUCESS     : return 1;
+      case PJRR_FULL       : return 0;
+      case PJRR_INTERRUPTED: goto begin;
+      default: rb_bug("unreachable\n");
+    }
 }
 
 void

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

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