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

ruby-changes:17424

From: nobu <ko1@a...>
Date: Sat, 9 Oct 2010 11:03:52 +0900 (JST)
Subject: [ruby-changes:17424] Ruby:r29429 (trunk): * thread.c (thread_reset_event_flags, exec_event_hooks): ignore

nobu	2010-10-09 11:00:21 +0900 (Sat, 09 Oct 2010)

  New Revision: 29429

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

  Log:
    * thread.c (thread_reset_event_flags, exec_event_hooks): ignore
      hooks marked as removed.
    
    * thread.c (thread_exec_event_hooks): remove hooks to be removed.
    
    * thread.c (rb_threadptr_remove_event_hook, rb_remove_event_hook):
      defer removing hooks if running the hooks.  [ruby-dev:42350]

  Modified files:
    trunk/ChangeLog
    trunk/test/ruby/test_settracefunc.rb
    trunk/thread.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 29428)
+++ ChangeLog	(revision 29429)
@@ -1,3 +1,13 @@
+Sat Oct  9 11:00:06 2010  Nobuyoshi Nakada  <nobu@r...>
+
+	* thread.c (thread_reset_event_flags, exec_event_hooks): ignore
+	  hooks marked as removed.
+
+	* thread.c (thread_exec_event_hooks): remove hooks to be removed.
+
+	* thread.c (rb_threadptr_remove_event_hook, rb_remove_event_hook):
+	  defer removing hooks if running the hooks.  [ruby-dev:42350]
+
 Sat Oct  9 10:51:00 2010  Nobuyoshi Nakada  <nobu@r...>
 
 	* thread.c (rb_threadptr_exec_event_hooks): suppress each event
Index: thread.c
===================================================================
--- thread.c	(revision 29428)
+++ thread.c	(revision 29429)
@@ -3708,6 +3708,8 @@
 }
 
 /* tracer */
+#define RUBY_EVENT_REMOVED 0x1000000
+
 enum {
     EVENT_RUNNING_NOTHING,
     EVENT_RUNNING_TRACE = 1,
@@ -3745,7 +3747,8 @@
     rb_event_flag_t flag = th->event_flags & RUBY_EVENT_VM;
 
     while (hook) {
-	flag |= hook->flag;
+	if (!(flag & RUBY_EVENT_REMOVED))
+	    flag |= hook->flag;
 	hook = hook->next;
     }
     th->event_flags = flag;
@@ -3798,16 +3801,24 @@
     st_foreach(GET_VM()->living_threads, set_threads_event_flags_i, (st_data_t) flag);
 }
 
-static inline void
+static inline int
 exec_event_hooks(const rb_event_hook_t *hook, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
 {
+    int removed = 0;
     for (; hook; hook = hook->next) {
+	if (hook->flag & RUBY_EVENT_REMOVED) {
+	    removed++;
+	    continue;
+	}
 	if (flag & hook->flag) {
 	    (*hook->func)(flag, hook->data, self, id, klass);
 	}
     }
+    return removed;
 }
 
+static int remove_defered_event_hook(rb_event_hook_t **root);
+
 static VALUE
 thread_exec_event_hooks(VALUE args, int running)
 {
@@ -3818,13 +3829,17 @@
     ID id = argp->id;
     VALUE klass = argp->klass;
     const rb_event_flag_t wait_event = th->event_flags;
+    int removed;
 
     if (self == rb_mRubyVMFrozenCore) return 0;
 
     if ((wait_event & flag) && !(running & EVENT_RUNNING_THREAD)) {
 	th->tracing |= EVENT_RUNNING_THREAD;
-	exec_event_hooks(th->event_hooks, flag, self, id, klass);
+	removed = exec_event_hooks(th->event_hooks, flag, self, id, klass);
 	th->tracing &= ~EVENT_RUNNING_THREAD;
+	if (removed) {
+	    remove_defered_event_hook(&th->event_hooks);
+	}
     }
     if (wait_event & RUBY_EVENT_VM) {
 	if (th->vm->event_hooks == NULL) {
@@ -3832,8 +3847,11 @@
 	}
 	else if (!(running & EVENT_RUNNING_VM)) {
 	    th->tracing |= EVENT_RUNNING_VM;
-	    exec_event_hooks(th->vm->event_hooks, flag, self, id, klass);
+	    removed = exec_event_hooks(th->vm->event_hooks, flag, self, id, klass);
 	    th->tracing &= ~EVENT_RUNNING_VM;
+	    if (removed) {
+		remove_defered_event_hook(&th->vm->event_hooks);
+	    }
 	}
     }
     return 0;
@@ -3867,23 +3885,30 @@
 }
 
 static int
+defer_remove_event_hook(rb_event_hook_t *hook, rb_event_hook_func_t func)
+{
+    while (hook) {
+	if (func == 0 || hook->func == func) {
+	    hook->flag |= RUBY_EVENT_REMOVED;
+	}
+	hook = hook->next;
+    }
+    return -1;
+}
+
+static int
 remove_event_hook(rb_event_hook_t **root, rb_event_hook_func_t func)
 {
-    rb_event_hook_t *prev = NULL, *hook = *root, *next;
+    rb_event_hook_t *hook = *root, *next;
 
     while (hook) {
 	next = hook->next;
-	if (func == 0 || hook->func == func) {
-	    if (prev) {
-		prev->next = hook->next;
-	    }
-	    else {
-		*root = hook->next;
-	    }
+	if (func == 0 || hook->func == func || (hook->flag & RUBY_EVENT_REMOVED)) {
+	    *root = next;
 	    xfree(hook);
 	}
 	else {
-	    prev = hook;
+	    root = &hook->next;
 	}
 	hook = next;
     }
@@ -3891,9 +3916,34 @@
 }
 
 static int
+remove_defered_event_hook(rb_event_hook_t **root)
+{
+    rb_event_hook_t *hook = *root, *next;
+
+    while (hook) {
+	next = hook->next;
+	if (hook->flag & RUBY_EVENT_REMOVED) {
+	    *root = next;
+	    xfree(hook);
+	}
+	else {
+	    root = &hook->next;
+	}
+	hook = next;
+    }
+    return -1;
+}
+
+static int
 rb_threadptr_remove_event_hook(rb_thread_t *th, rb_event_hook_func_t func)
 {
-    int ret = remove_event_hook(&th->event_hooks, func);
+    int ret;
+    if (th->tracing & EVENT_RUNNING_THREAD) {
+	ret = defer_remove_event_hook(th->event_hooks, func);
+    }
+    else {
+	ret = remove_event_hook(&th->event_hooks, func);
+    }
     thread_reset_event_flags(th);
     return ret;
 }
@@ -3904,14 +3954,49 @@
     return rb_threadptr_remove_event_hook(thval2thread_t(thval), func);
 }
 
+static rb_event_hook_t *
+search_live_hook(rb_event_hook_t *hook)
+{
+    while (hook) {
+	if (!(hook->flag & RUBY_EVENT_REMOVED))
+	    return hook;
+	hook = hook->next;
+    }
+    return NULL;
+}
+
+static int
+running_vm_event_hooks(st_data_t key, st_data_t val, st_data_t data)
+{
+    rb_thread_t *th = thval2thread_t((VALUE)key);
+    if (!(th->tracing & EVENT_RUNNING_VM)) return ST_CONTINUE;
+    *(rb_thread_t **)data = th;
+    return ST_STOP;
+}
+
+static rb_thread_t *
+vm_event_hooks_running_thread(rb_vm_t *vm)
+{
+    rb_thread_t *found = NULL;
+    st_foreach(vm->living_threads, running_vm_event_hooks, (st_data_t)&found);
+    return found;
+}
+
 int
 rb_remove_event_hook(rb_event_hook_func_t func)
 {
     rb_vm_t *vm = GET_VM();
-    rb_event_hook_t *hook = vm->event_hooks;
-    int ret = remove_event_hook(&vm->event_hooks, func);
+    rb_event_hook_t *hook = search_live_hook(vm->event_hooks);
+    int ret;
 
-    if (hook != NULL && vm->event_hooks == NULL) {
+    if (vm_event_hooks_running_thread(vm)) {
+	ret = defer_remove_event_hook(vm->event_hooks, func);
+    }
+    else {
+	ret = remove_event_hook(&vm->event_hooks, func);
+    }
+
+    if (hook && !search_live_hook(vm->event_hooks)) {
 	set_threads_event_flags(0);
     }
 
Index: test/ruby/test_settracefunc.rb
===================================================================
--- test/ruby/test_settracefunc.rb	(revision 29428)
+++ test/ruby/test_settracefunc.rb	(revision 29429)
@@ -354,4 +354,16 @@
     assert_equal([], events[:set])
     assert_equal([], events[:add])
   end
+
+  def test_remove_in_trace
+    bug3921 = '[ruby-dev:42350]'
+    ok = false
+    func = lambda{|e, f, l, i, b, k|
+      set_trace_func(nil)
+      ok = eval("self", b)
+    }
+
+    set_trace_func(func)
+    assert_equal(self, ok, bug3921)
+  end
 end

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

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