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

ruby-changes:24664

From: ko1 <ko1@a...>
Date: Thu, 16 Aug 2012 20:41:38 +0900 (JST)
Subject: [ruby-changes:24664] ko1:r36715 (trunk): * vm_trace.c, vm_core.h: simplify tracing mechanism.

ko1	2012-08-16 20:41:24 +0900 (Thu, 16 Aug 2012)

  New Revision: 36715

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

  Log:
    * vm_trace.c, vm_core.h: simplify tracing mechanism.
      (1) add rb_hook_list_t data structure which includes
      hooks, events (flag) and `need_clean' flag.
      If the last flag is true, then clean the hooks list.
      In other words, deleted hooks are contained by `hooks'.
      Cleanup process should run before traversing the list.
      (2) Change check mechanism
      See EXEC_EVENT_HOOK() in vm_core.h.
      (3) Add `raw' hooks APIs
      Normal hooks are guarded from exception by rb_protect().
      However, this protection is overhead for too simple
      functions which never cause exceptions.  `raw' hooks
      are executed without protection and faster.
      Now, we only provide registration APIs.  All `raw'
      hooks are kicked under protection (same as normal hooks).
    * include/ruby/ruby.h: remove internal data definition and
      macros.
    * internal.h (ruby_suppress_tracing), vm_trace.c: rename
      ruby_suppress_tracing() to rb_suppress_tracing()
      and remove unused function parameter.
    * parse.y: fix to use renamed rb_suppress_tracing().
    * thread.c (thread_create_core): no need to set RUBY_VM_VM.
    * vm.c (mark_event_hooks): move definition to vm_trace.c.
    * vm.c (ruby_vm_event_flags): add a global variable.
      This global variable represents all of Threads and VM's
      event masks (T1#events | T2#events | ... | VM#events).
      You can check the possibility kick trace func or not
      with ruby_vm_event_flags.
      ruby_vm_event_flags is maintained by vm_trace.c.
    * cont.c (fiber_switch, rb_cont_call): restore tracing status.
      [Feature #4347]
    * test/ruby/test_continuation.rb: ditto.

  Modified files:
    trunk/ChangeLog
    trunk/cont.c
    trunk/include/ruby/ruby.h
    trunk/internal.h
    trunk/parse.y
    trunk/test/ruby/test_continuation.rb
    trunk/thread.c
    trunk/vm.c
    trunk/vm_core.h
    trunk/vm_trace.c

Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 36714)
+++ include/ruby/ruby.h	(revision 36715)
@@ -1408,24 +1408,15 @@
 #define RUBY_EVENT_C_CALL    0x0020
 #define RUBY_EVENT_C_RETURN  0x0040
 #define RUBY_EVENT_RAISE     0x0080
-#define RUBY_EVENT_ALL       0xffff
-#define RUBY_EVENT_VM       0x10000
+#define RUBY_EVENT_ALL       0x00ff
 #define RUBY_EVENT_SWITCH   0x20000
 #define RUBY_EVENT_COVERAGE 0x40000
 
 typedef unsigned int rb_event_flag_t;
 typedef void (*rb_event_hook_func_t)(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE klass);
 
-typedef struct rb_event_hook_struct {
-    rb_event_flag_t flag;
-    rb_event_hook_func_t func;
-    VALUE data;
-    struct rb_event_hook_struct *next;
-} rb_event_hook_t;
-
 #define RB_EVENT_HOOKS_HAVE_CALLBACK_DATA 1
-void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events,
-		       VALUE data);
+void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
 int rb_remove_event_hook(rb_event_hook_func_t func);
 
 /* locale insensitive functions */
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 36714)
+++ ChangeLog	(revision 36715)
@@ -1,3 +1,47 @@
+Thu Aug 16 19:54:24 2012  Koichi Sasada  <ko1@a...>
+
+	* vm_trace.c, vm_core.h: simplify tracing mechanism.
+
+	  (1) add rb_hook_list_t data structure which includes
+	      hooks, events (flag) and `need_clean' flag.
+	      If the last flag is true, then clean the hooks list.
+	      In other words, deleted hooks are contained by `hooks'.
+	      Cleanup process should run before traversing the list.
+	  (2) Change check mechanism
+	      See EXEC_EVENT_HOOK() in vm_core.h.
+	  (3) Add `raw' hooks APIs
+	      Normal hooks are guarded from exception by rb_protect().
+	      However, this protection is overhead for too simple
+	      functions which never cause exceptions.  `raw' hooks
+	      are executed without protection and faster.
+	      Now, we only provide registration APIs.  All `raw'
+	      hooks are kicked under protection (same as normal hooks).
+
+	* include/ruby/ruby.h: remove internal data definition and
+	  macros.
+
+	* internal.h (ruby_suppress_tracing), vm_trace.c: rename
+	  ruby_suppress_tracing() to rb_suppress_tracing()
+	  and remove unused function parameter.
+
+	* parse.y: fix to use renamed rb_suppress_tracing().
+
+	* thread.c (thread_create_core): no need to set RUBY_VM_VM.
+
+	* vm.c (mark_event_hooks): move definition to vm_trace.c.
+
+	* vm.c (ruby_vm_event_flags): add a global variable.
+	  This global variable represents all of Threads and VM's
+	  event masks (T1#events | T2#events | ... | VM#events).
+	  You can check the possibility kick trace func or not
+	  with ruby_vm_event_flags.
+	  ruby_vm_event_flags is maintained by vm_trace.c.
+
+	* cont.c (fiber_switch, rb_cont_call): restore tracing status.
+	  [Feature #4347]
+
+	* test/ruby/test_continuation.rb: ditto.
+
 Thu Aug 16 19:15:23 2012  Nobuyoshi Nakada  <nobu@r...>
 
 	* object.c (rb_class_initialize): forbid inheriting uninitialized
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 36714)
+++ vm_core.h	(revision 36715)
@@ -290,6 +290,12 @@
 void rb_objspace_free(struct rb_objspace *);
 #endif
 
+typedef struct rb_hook_list_struct {
+    struct rb_event_hook_struct *hooks;
+    rb_event_flag_t events;
+    int need_clean;
+} rb_hook_list_t;
+
 typedef struct rb_vm_struct {
     VALUE self;
 
@@ -325,7 +331,7 @@
     } trap_list[RUBY_NSIG];
 
     /* hook */
-    rb_event_hook_t *event_hooks;
+    rb_hook_list_t event_hooks;
 
     int src_encoding_index;
 
@@ -513,9 +519,8 @@
     VALUE stat_insn_usage;
 
     /* tracer */
-    rb_event_hook_t *event_hooks;
-    rb_event_flag_t event_flags;
-    int tracing;
+    rb_hook_list_t event_hooks;
+    int trace_running;
 
     /* fiber */
     VALUE fiber;
@@ -764,6 +769,7 @@
 #if RUBY_VM_THREAD_MODEL == 2
 extern rb_thread_t *ruby_current_thread;
 extern rb_vm_t *ruby_current_vm;
+extern rb_event_flag_t ruby_vm_event_flags;
 
 #define GET_VM() ruby_current_vm
 #define GET_THREAD() ruby_current_thread
@@ -817,9 +823,8 @@
 rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass);
 
 #define EXEC_EVENT_HOOK(th, flag, self, id, klass) do { \
-    rb_event_flag_t wait_event__ = (th)->event_flags; \
-    if (UNLIKELY(wait_event__)) { \
-	if (wait_event__ & ((flag) | RUBY_EVENT_VM)) { \
+    if (UNLIKELY(ruby_vm_event_flags & (flag))) { \
+	if (((th)->event_hooks.events | (th)->vm->event_hooks.events) & (flag)) { \
 	    rb_threadptr_exec_event_hooks((th), (flag), (self), (id), (klass)); \
 	} \
     } \
Index: thread.c
===================================================================
--- thread.c	(revision 36714)
+++ thread.c	(revision 36715)
@@ -568,8 +568,6 @@
     RBASIC(th->async_errinfo_mask_stack)->klass = 0;
 
     native_mutex_initialize(&th->interrupt_lock);
-    if (GET_VM()->event_hooks != NULL)
-	th->event_flags |= RUBY_EVENT_VM;
 
     /* kick thread */
     st_insert(th->vm->living_threads, thval, (st_data_t) th->thread_id);
Index: parse.y
===================================================================
--- parse.y	(revision 36714)
+++ parse.y	(revision 36715)
@@ -5418,7 +5418,7 @@
 }
 
 static VALUE
-yycompile0(VALUE arg, int tracing)
+yycompile0(VALUE arg)
 {
     int n;
     NODE *tree;
@@ -5470,7 +5470,7 @@
 {
     ruby_sourcefile = ruby_strdup(f);
     ruby_sourceline = line - 1;
-    return (NODE *)ruby_suppress_tracing(yycompile0, (VALUE)parser, TRUE);
+    return (NODE *)rb_suppress_tracing(yycompile0, (VALUE)parser);
 }
 #endif /* !RIPPER */
 
Index: vm_trace.c
===================================================================
--- vm_trace.c	(revision 36714)
+++ vm_trace.c	(revision 36715)
@@ -30,61 +30,80 @@
 
 /* (1) trace mechanisms */
 
-#define RUBY_EVENT_REMOVED 0x1000000
+typedef enum {
+    RUBY_HOOK_FLAG_SAFE    = 0x01,
+    RUBY_HOOK_FLAG_DELETED = 0x02,
+} rb_hook_flag_t;
 
-enum {
-    EVENT_RUNNING_NOTHING,
-    EVENT_RUNNING_TRACE = 1,
-    EVENT_RUNNING_THREAD = 2,
-    EVENT_RUNNING_VM = 4,
-    EVENT_RUNNING_EVENT_MASK = EVENT_RUNNING_VM|EVENT_RUNNING_THREAD
-};
+typedef struct rb_event_hook_struct {
+    rb_hook_flag_t hook_flags;
+    rb_event_flag_t events;
+    rb_event_hook_func_t func;
+    VALUE data;
+    struct rb_event_hook_struct *next;
+} rb_event_hook_t;
 
-static VALUE thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always);
+#define MAX_EVENT_NUM 32
 
-struct event_call_args {
-    rb_thread_t *th;
-    VALUE klass;
-    VALUE self;
-    VALUE proc;
-    ID id;
-    rb_event_flag_t event;
-};
+static int ruby_event_flag_count[MAX_EVENT_NUM] = {0};
 
-static rb_event_hook_t *
-alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
+/* Safe API.  Callback will be called under PUSH_TAG() */
+void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
+int rb_remove_event_hook(rb_event_hook_func_t func);
+void rb_thread_add_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
+int rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func);
+
+/* Raw API.  Callback will be called without PUSH_TAG() */
+void rb_add_raw_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
+int rb_remove_raw_event_hook(rb_event_hook_func_t func);
+void rb_thread_add_raw_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
+int rb_thread_remove_raw_event_hook(VALUE thval, rb_event_hook_func_t func);
+
+/* called from vm.c */
+
+void
+vm_trace_mark_event_hooks(rb_hook_list_t *hooks)
 {
-    rb_event_hook_t *hook = ALLOC(rb_event_hook_t);
-    hook->func = func;
-    hook->flag = events;
-    hook->data = data;
-    return hook;
+    rb_event_hook_t *hook = hooks->hooks;
+
+    while (hook) {
+	rb_gc_mark(hook->data);
+	hook = hook->next;
+    }
 }
 
+/* ruby_vm_event_flags management */
+
 static void
-thread_reset_event_flags(rb_thread_t *th)
+recalc_add_ruby_vm_event_flags(rb_event_flag_t events)
 {
-    rb_event_hook_t *hook = th->event_hooks;
-    rb_event_flag_t flag = th->event_flags & RUBY_EVENT_VM;
+    int i;
+    ruby_vm_event_flags = 0;
 
-    while (hook) {
-	if (!(flag & RUBY_EVENT_REMOVED))
-	    flag |= hook->flag;
-	hook = hook->next;
+    for (i=0; i<MAX_EVENT_NUM; i++) {
+	if (events & (1 << i)) {
+	    ruby_event_flag_count[i]++;
+	}
+	ruby_vm_event_flags |= ruby_event_flag_count[i] ? (1<<i) : 0;
     }
-    th->event_flags = flag;
 }
 
 static void
-rb_threadptr_add_event_hook(rb_thread_t *th,
-			 rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
+recalc_remove_ruby_vm_event_flags(rb_event_flag_t events)
 {
-    rb_event_hook_t *hook = alloc_event_hook(func, events, data);
-    hook->next = th->event_hooks;
-    th->event_hooks = hook;
-    thread_reset_event_flags(th);
+    int i;
+    ruby_vm_event_flags = 0;
+
+    for (i=0; i<MAX_EVENT_NUM; i++) {
+	if (events & (1 << i)) {
+	    ruby_event_flag_count[i]--;
+	}
+	ruby_vm_event_flags |= ruby_event_flag_count[i] ? (1<<i) : 0;
+    }
 }
 
+/* add/remove hooks */
+
 static rb_thread_t *
 thval2thread_t(VALUE thval)
 {
@@ -93,180 +112,82 @@
     return th;
 }
 
-void
-rb_thread_add_event_hook(VALUE thval,
-			 rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
+static rb_event_hook_t *
+alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_hook_flag_t hook_flags)
 {
-    rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data);
+    rb_event_hook_t *hook = ALLOC(rb_event_hook_t);
+    hook->hook_flags = hook_flags;
+    hook->events = events;
+    hook->func = func;
+    hook->data = data;
+    return hook;
 }
 
-static int
-set_threads_event_flags_i(st_data_t key, st_data_t val, st_data_t flag)
+static void
+connect_event_hook(rb_hook_list_t *list, rb_event_hook_t *hook)
 {
-    VALUE thval = key;
-    rb_thread_t *th;
-    GetThreadPtr(thval, th);
-
-    if (flag) {
-	th->event_flags |= RUBY_EVENT_VM;
-    }
-    else {
-	th->event_flags &= (~RUBY_EVENT_VM);
-    }
-    return ST_CONTINUE;
+    hook->next = list->hooks;
+    list->hooks = hook;
+    recalc_add_ruby_vm_event_flags(hook->events);
+    list->events |= hook->events;
 }
 
 static void
-set_threads_event_flags(int flag)
+rb_threadptr_add_event_hook(rb_thread_t *th, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_hook_flag_t hook_flags)
 {
-    st_foreach(GET_VM()->living_threads, set_threads_event_flags_i, (st_data_t) flag);
+    rb_event_hook_t *hook = alloc_event_hook(func, events, data, hook_flags);
+    connect_event_hook(&th->event_hooks, hook);
 }
 
-static inline int
-exec_event_hooks(const rb_event_hook_t *hook, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
+void
+rb_thread_add_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
 {
-    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;
+    rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data, RUBY_HOOK_FLAG_SAFE);
 }
 
-static int remove_defered_event_hook(rb_event_hook_t **root);
-
-static VALUE
-thread_exec_event_hooks(VALUE args, int running)
+void
+rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
 {
-    struct event_call_args *argp = (struct event_call_args *)args;
-    rb_thread_t *th = argp->th;
-    rb_event_flag_t flag = argp->event;
-    VALUE self = argp->self;
-    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;
-	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) {
-	    th->event_flags &= (~RUBY_EVENT_VM);
-	}
-	else if (!(running & EVENT_RUNNING_VM)) {
-	    th->tracing |= EVENT_RUNNING_VM;
-	    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;
+    rb_event_hook_t *hook = alloc_event_hook(func, events, data, RUBY_HOOK_FLAG_SAFE);
+    connect_event_hook(&GET_VM()->event_hooks, hook);
 }
 
 void
-rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
+rb_thread_add_raw_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
 {
-    const VALUE errinfo = th->errinfo;
-    struct event_call_args args;
-    args.th = th;
-    args.event = flag;
-    args.self = self;
-    args.id = id;
-    args.klass = klass;
-    args.proc = 0;
-    thread_suppress_tracing(th, EVENT_RUNNING_EVENT_MASK, thread_exec_event_hooks, (VALUE)&args, FALSE);
-    th->errinfo = errinfo;
+    rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data, 0);
 }
 
 void
-rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
+rb_add_raw_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
 {
-    rb_event_hook_t *hook = alloc_event_hook(func, events, data);
-    rb_vm_t *vm = GET_VM();
-
-    hook->next = vm->event_hooks;
-    vm->event_hooks = hook;
-
-    set_threads_event_flags(1);
+    rb_event_hook_t *hook = alloc_event_hook(func, events, data, 0);
+    connect_event_hook(&GET_VM()->event_hooks, hook);
 }
 
+/* if func is 0, then clear all funcs */
 static int
-defer_remove_event_hook(rb_event_hook_t *hook, rb_event_hook_func_t func)
+remove_event_hook_by_func(rb_hook_list_t *list, rb_event_hook_func_t func)
 {
+    int ret = 0;
+    rb_event_hook_t *hook = list->hooks;
+
     while (hook) {
 	if (func == 0 || hook->func == func) {
-	    hook->flag |= RUBY_EVENT_REMOVED;
+	    hook->hook_flags |= RUBY_HOOK_FLAG_DELETED;
+	    ret+=1;
+	    list->need_clean++;
 	}
 	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 *hook = *root, *next;
-
-    while (hook) {
-	next = hook->next;
-	if (func == 0 || hook->func == func || (hook->flag & RUBY_EVENT_REMOVED)) {
-	    *root = next;
-	    xfree(hook);
-	}
-	else {
-	    root = &hook->next;
-	}
-	hook = next;
-    }
-    return -1;
+    return ret;
 }
 
 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;
-    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;
+    return remove_event_hook_by_func(&th->event_hooks, func);
 }
 
 int
@@ -275,69 +196,167 @@
     return rb_threadptr_remove_event_hook(thval2thread_t(thval), func);
 }
 
-static rb_event_hook_t *
-search_live_hook(rb_event_hook_t *hook)
+int
+rb_remove_event_hook(rb_event_hook_func_t func)
 {
-    while (hook) {
-	if (!(hook->flag & RUBY_EVENT_REMOVED))
-	    return hook;
-	hook = hook->next;
-    }
-    return NULL;
+    return remove_event_hook_by_func(&GET_VM()->event_hooks, func);
 }
 
 static int
-running_vm_event_hooks(st_data_t key, st_data_t val, st_data_t data)
+clear_trace_func_i(st_data_t key, st_data_t val, st_data_t flag)
 {
-    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;
+    rb_thread_t *th;
+    GetThreadPtr((VALUE)key, th);
+    rb_threadptr_remove_event_hook(th, 0);
+    return ST_CONTINUE;
 }
 
-static rb_thread_t *
-vm_event_hooks_running_thread(rb_vm_t *vm)
+void
+rb_clear_trace_func(void)
 {
-    rb_thread_t *found = NULL;
-    st_foreach(vm->living_threads, running_vm_event_hooks, (st_data_t)&found);
-    return found;
+    st_foreach(GET_VM()->living_threads, clear_trace_func_i, (st_data_t) 0);
+    rb_remove_event_hook(0);
 }
 
-int
-rb_remove_event_hook(rb_event_hook_func_t func)
+/* invoke hooks */
+
+static void
+clean_hooks(rb_hook_list_t *list)
 {
-    rb_vm_t *vm = GET_VM();
-    rb_event_hook_t *hook = search_live_hook(vm->event_hooks);
-    int ret;
+    rb_event_hook_t *hook = list->hooks, *prev = 0;
 
-    if (vm_event_hooks_running_thread(vm)) {
-	ret = defer_remove_event_hook(vm->event_hooks, func);
+    list->events = 0;
+    list->need_clean = 0;
+
+    while (hook) {
+	if (hook->hook_flags & RUBY_HOOK_FLAG_DELETED) {
+	    if (prev == 0) {
+		/* start of list */
+		list->hooks = hook->next;
+	    }
+	    else {
+		prev->next = hook->next;
+	    }
+
+	    recalc_remove_ruby_vm_event_flags(hook->events);
+	    xfree(hook);
+	    goto next_iter;
+	}
+	else {
+	    list->events |= hook->events; /* update active events */
+	}
+	prev = hook;
+      next_iter:
+	hook = hook->next;
     }
-    else {
-	ret = remove_event_hook(&vm->event_hooks, func);
+}
+
+static inline int
+exec_hooks(rb_thread_t *th, rb_hook_list_t *list, rb_event_flag_t event, VALUE self, ID id, VALUE klass)
+{
+    rb_event_hook_t *hook;
+    int state;
+    volatile int raised;
+
+    if (UNLIKELY(list->need_clean > 0)) {
+	clean_hooks(list);
     }
 
-    if (hook && !search_live_hook(vm->event_hooks)) {
-	set_threads_event_flags(0);
+    raised = rb_threadptr_reset_raised(th);
+
+    hook = list->hooks;
+
+    /* TODO: Support !RUBY_HOOK_FLAG_SAFE hooks */
+
+    TH_PUSH_TAG(th);
+    if ((state = TH_EXEC_TAG()) == 0) {
+	while (hook) {
+	    if (LIKELY(!(hook->hook_flags & RUBY_HOOK_FLAG_DELETED)) && (event & hook->events)) {
+		(*hook->func)(event, hook->data, self, id, klass);
+	    }
+	    hook = hook->next;
+	}
     }
+    TH_POP_TAG();
 
-    return ret;
+    if (raised) {
+	rb_threadptr_set_raised(th);
+    }
+
+    return state;
 }
 
-static int
-clear_trace_func_i(st_data_t key, st_data_t val, st_data_t flag)
+void
+rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t event, VALUE self, ID id, VALUE klass)
 {
-    rb_thread_t *th;
-    GetThreadPtr((VALUE)key, th);
-    rb_threadptr_remove_event_hook(th, 0);
-    return ST_CONTINUE;
+    if (th->trace_running == 0 &&
+	self != rb_mRubyVMFrozenCore /* skip special methods. TODO: remove it. */) {
+	int state;
+	int outer_state = th->state;
+	th->state = 0;
+
+	th->trace_running = 1;
+	{
+	    const VALUE errinfo = th->errinfo;
+	    rb_hook_list_t *list;
+
+	    /* thread local traces */
+	    list = &th->event_hooks;
+	    if (list->events & event) {
+		state = exec_hooks(th, list, event, self, id, klass);
+		if (state) goto terminate;
+	    }
+
+	    /* vm global traces */
+	    list = &th->vm->event_hooks;
+	    if (list->events & event) {
+		state = exec_hooks(th, list, event, self, id, klass);
+		if (state) goto terminate;
+	    }
+	    th->errinfo = errinfo;
+	}
+      terminate:
+	th->trace_running = 0;
+
+	if (state) {
+	    TH_JUMP_TAG(th, state);
+	}
+	th->state = outer_state;
+    }
 }
 
-void
-rb_clear_trace_func(void)
+VA (... truncated)

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

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