aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-11-16 02:47:58 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-11-16 02:47:58 +0000
commit23e452b17b604c35339265b480b900581abc2ce3 (patch)
tree52e682beed9b5df4cd7c014c9f0fe63f267c2d30
parent575993d74386157a9554e2b4f9f350d673be9613 (diff)
downloadruby-23e452b17b604c35339265b480b900581abc2ce3.tar.gz
cleanup hook cleanup code.
* vm_trace.c: before this patch, deleted hooks are remvoed at *the beggining* of hooks (exec_hooks_precheck). This patch cleanup deleted hooks at (1) just after hook is deleted (TracePoint#disable and so on) (2) just after executing hooks (exec_hooks_postcheck) Most of time (1) is enough, but if some threads running hooks, we need to wait cleaning up deleted hooks until threads finish running the hooks. This is why (2) is introduced (and this is why current impl cleanup deleted hooks at the beggining of hooks). * test/lib/tracepointchecker.rb: check also the number of delete waiting hooks. * cont.c (cont_restore_thread): fix VM->trace_running count. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60782 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--cont.c8
-rw-r--r--test/lib/tracepointchecker.rb6
-rw-r--r--vm_trace.c142
3 files changed, 77 insertions, 79 deletions
diff --git a/cont.c b/cont.c
index cebb7a28de..d4d6f2e60d 100644
--- a/cont.c
+++ b/cont.c
@@ -704,6 +704,14 @@ cont_restore_thread(rb_context_t *cont)
th->ec->root_svar = sec->root_svar;
th->ec->ensure_list = sec->ensure_list;
th->ec->errinfo = sec->errinfo;
+
+ /* trace on -> trace off */
+ if (sec->trace_arg == NULL && th->ec->trace_arg != NULL) {
+ GET_VM()->trace_running--;
+ }
+ else if (sec->trace_arg == NULL && th->ec->trace_arg != NULL) {
+ GET_VM()->trace_running++;
+ }
th->ec->trace_arg = sec->trace_arg;
VM_ASSERT(th->ec->vm_stack != NULL);
diff --git a/test/lib/tracepointchecker.rb b/test/lib/tracepointchecker.rb
index 447a63bc1e..2fa40546b2 100644
--- a/test/lib/tracepointchecker.rb
+++ b/test/lib/tracepointchecker.rb
@@ -7,7 +7,7 @@ module TracePointChecker
module ZombieTraceHunter
def before_setup
- @tracepoint_captured_stat = TracePoint.stat.map{|k, (activated, _deleted)| [k, activated]}
+ @tracepoint_captured_stat = TracePoint.stat.map{|k, (activated, deleted)| [k, activated, deleted]}
super
end
@@ -18,8 +18,8 @@ module TracePointChecker
# detect zombie traces.
assert_equal(
@tracepoint_captured_stat,
- TracePoint.stat.map{|k, (activated, _deleted)| [k, activated]},
- "The number of active trace events was changed"
+ TracePoint.stat.map{|k, (activated, deleted)| [k, activated, deleted]},
+ "The number of active/deleted trace events was changed"
)
# puts "TracePoint - deleted: #{deleted}" if deleted > 0
diff --git a/vm_trace.c b/vm_trace.c
index fd19a01487..efa2ee1bfb 100644
--- a/vm_trace.c
+++ b/vm_trace.c
@@ -46,8 +46,6 @@ typedef void (*rb_event_hook_raw_arg_func_t)(VALUE data, const rb_trace_arg_t *a
#define MAX_EVENT_NUM 32
-static int ruby_event_flag_count[MAX_EVENT_NUM] = {0};
-
/* called from vm.c */
void
@@ -82,39 +80,6 @@ update_global_event_hook(rb_event_flag_t vm_events)
rb_objspace_set_event_hook(vm_events);
}
-static void
-recalc_add_ruby_vm_event_flags(rb_event_flag_t events)
-{
- int i;
- rb_event_flag_t vm_events = 0;
-
- for (i=0; i<MAX_EVENT_NUM; i++) {
- if (events & ((rb_event_flag_t)1 << i)) {
- ruby_event_flag_count[i]++;
- }
- vm_events |= ruby_event_flag_count[i] ? (1<<i) : 0;
- }
-
- update_global_event_hook(vm_events);
-}
-
-static void
-recalc_remove_ruby_vm_event_flags(rb_event_flag_t events)
-{
- int i;
- rb_event_flag_t vm_events = 0;
-
- for (i=0; i<MAX_EVENT_NUM; i++) {
- if (events & ((rb_event_flag_t)1 << i)) {
- VM_ASSERT(ruby_event_flag_count[i] > 0);
- ruby_event_flag_count[i]--;
- }
- vm_events |= ruby_event_flag_count[i] ? (1<<i) : 0;
- }
-
- update_global_event_hook(vm_events);
-}
-
/* add/remove hooks */
static rb_event_hook_t *
@@ -145,8 +110,8 @@ connect_event_hook(const rb_execution_context_t *ec, rb_event_hook_t *hook)
hook->next = list->hooks;
list->hooks = hook;
- recalc_add_ruby_vm_event_flags(hook->events);
list->events |= hook->events;
+ update_global_event_hook(list->events);
}
static void
@@ -184,13 +149,47 @@ rb_add_event_hook2(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data
connect_event_hook(GET_EC(), hook);
}
+static void
+clean_hooks(rb_hook_list_t *list)
+{
+ rb_event_hook_t *hook, **nextp = &list->hooks;
+ VM_ASSERT(list->need_clean == TRUE);
+
+ list->events = 0;
+ list->need_clean = FALSE;
+
+ while ((hook = *nextp) != 0) {
+ if (hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED) {
+ *nextp = hook->next;
+ xfree(hook);
+ }
+ else {
+ list->events |= hook->events; /* update active events */
+ nextp = &hook->next;
+ }
+ }
+
+ update_global_event_hook(list->events);
+}
+
+static void
+clean_hooks_check(rb_vm_t *vm, rb_hook_list_t *list)
+{
+ if (UNLIKELY(list->need_clean != FALSE)) {
+ if (vm->trace_running == 0) {
+ clean_hooks(list);
+ }
+ }
+}
+
#define MATCH_ANY_FILTER_TH ((rb_thread_t *)1)
/* if func is 0, then clear all funcs */
static int
remove_event_hook(const rb_execution_context_t *ec, const rb_thread_t *filter_th, rb_event_hook_func_t func, VALUE data)
{
- rb_hook_list_t *list = &rb_ec_vm_ptr(ec)->event_hooks;
+ rb_vm_t *vm = rb_ec_vm_ptr(ec);
+ rb_hook_list_t *list = &vm->event_hooks;
int ret = 0;
rb_event_hook_t *hook = list->hooks;
@@ -207,6 +206,7 @@ remove_event_hook(const rb_execution_context_t *ec, const rb_thread_t *filter_th
hook = hook->next;
}
+ clean_hooks_check(vm, list);
return ret;
}
@@ -256,27 +256,6 @@ rb_ec_clear_current_thread_trace_func(const rb_execution_context_t *ec)
/* invoke hooks */
static void
-clean_hooks(rb_hook_list_t *list)
-{
- rb_event_hook_t *hook, **nextp = &list->hooks;
-
- list->events = 0;
- list->need_clean = FALSE;
-
- while ((hook = *nextp) != 0) {
- if (hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED) {
- *nextp = hook->next;
- recalc_remove_ruby_vm_event_flags(hook->events);
- xfree(hook);
- }
- else {
- list->events |= hook->events; /* update active events */
- nextp = &hook->next;
- }
- }
-}
-
-static void
exec_hooks_body(const rb_execution_context_t *ec, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
{
rb_event_hook_t *hook;
@@ -296,31 +275,39 @@ exec_hooks_body(const rb_execution_context_t *ec, rb_hook_list_t *list, const rb
}
static int
-exec_hooks_precheck(const rb_execution_context_t *ec, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
+exec_hooks_precheck(const rb_execution_context_t *ec, rb_vm_t *vm, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
{
- if (UNLIKELY(list->need_clean != FALSE)) {
- if (rb_ec_vm_ptr(ec)->trace_running <= 1) { /* only running this hooks */
- clean_hooks(list);
- }
+ if (list->events & trace_arg->event) {
+ vm->trace_running++;
+ return TRUE;
+ }
+ else {
+ return FALSE;
}
+}
- return (list->events & trace_arg->event) != 0;
+static void
+exec_hooks_postcheck(const rb_execution_context_t *ec, rb_vm_t *vm, rb_hook_list_t *list)
+{
+ vm->trace_running--;
+ clean_hooks_check(vm, list);
}
static void
-exec_hooks_unprotected(const rb_execution_context_t *ec, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
+exec_hooks_unprotected(const rb_execution_context_t *ec, rb_vm_t *vm, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
{
- if (exec_hooks_precheck(ec, list, trace_arg) == 0) return;
+ if (exec_hooks_precheck(ec, vm, list, trace_arg) == 0) return;
exec_hooks_body(ec, list, trace_arg);
+ exec_hooks_postcheck(ec, vm, list);
}
static int
-exec_hooks_protected(rb_execution_context_t *ec, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
+exec_hooks_protected(rb_execution_context_t *ec, rb_vm_t *vm, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
{
enum ruby_tag_type state;
volatile int raised;
- if (exec_hooks_precheck(ec, list, trace_arg) == 0) return 0;
+ if (exec_hooks_precheck(ec, vm, list, trace_arg) == 0) return 0;
raised = rb_ec_reset_raised(ec);
@@ -332,6 +319,8 @@ exec_hooks_protected(rb_execution_context_t *ec, rb_hook_list_t *list, const rb_
}
EC_POP_TAG();
+ exec_hooks_postcheck(ec, vm, list);
+
if (raised) {
rb_ec_set_raised(ec);
}
@@ -351,11 +340,9 @@ rb_exec_event_hooks(rb_trace_arg_t *trace_arg, int pop_p)
}
else {
rb_trace_arg_t *prev_trace_arg = ec->trace_arg;
- vm->trace_running++;
ec->trace_arg = trace_arg;
- exec_hooks_unprotected(ec, &vm->event_hooks, trace_arg);
+ exec_hooks_unprotected(ec, vm, &vm->event_hooks, trace_arg);
ec->trace_arg = prev_trace_arg;
- vm->trace_running--;
}
}
else {
@@ -368,17 +355,15 @@ rb_exec_event_hooks(rb_trace_arg_t *trace_arg, int pop_p)
ec->local_storage_recursive_hash = ec->local_storage_recursive_hash_for_trace;
ec->errinfo = Qnil;
- vm->trace_running++;
ec->trace_arg = trace_arg;
{
- state = exec_hooks_protected(ec, &vm->event_hooks, trace_arg);
+ state = exec_hooks_protected(ec, vm, &vm->event_hooks, trace_arg);
if (state) goto terminate;
ec->errinfo = errinfo;
}
terminate:
ec->trace_arg = NULL;
- vm->trace_running--;
ec->local_storage_recursive_hash_for_trace = ec->local_storage_recursive_hash;
ec->local_storage_recursive_hash = old_recursive;
@@ -402,12 +387,15 @@ rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg)
volatile int raised;
VALUE result = Qnil;
rb_execution_context_t *ec = GET_EC();
+ rb_vm_t *vm = rb_ec_vm_ptr(ec);
enum ruby_tag_type state;
const int volatile tracing = ec->trace_arg ? 1 : 0;
rb_trace_arg_t dummy_trace_arg;
dummy_trace_arg.event = 0;
- if (!tracing) rb_ec_vm_ptr(ec)->trace_running++;
+ if (!tracing) {
+ vm->trace_running++;
+ }
if (!ec->trace_arg) ec->trace_arg = &dummy_trace_arg;
raised = rb_ec_reset_raised(ec);
@@ -423,7 +411,9 @@ rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg)
}
if (ec->trace_arg == &dummy_trace_arg) ec->trace_arg = NULL;
- if (!tracing) rb_ec_vm_ptr(ec)->trace_running--;
+ if (!tracing) {
+ vm->trace_running--;
+ }
if (state) {
#if defined RUBY_USE_SETJMPEX && RUBY_USE_SETJMPEX