summaryrefslogtreecommitdiff
path: root/vm_trace.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-08-16 11:41:24 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-08-16 11:41:24 +0000
commit4a4a702e61d1c5585d522f1185a82a5685c554f6 (patch)
treebbbd9f9a92339aa20f6a113238965064a67487c7 /vm_trace.c
parent9528358120511f0587be39c853f5916cf8d05a9d (diff)
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36715 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_trace.c')
-rw-r--r--vm_trace.c541
1 files changed, 250 insertions, 291 deletions
diff --git a/vm_trace.c b/vm_trace.c
index f608e1b2c0..23ad2a8ea1 100644
--- a/vm_trace.c
+++ b/vm_trace.c
@@ -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 @@ thval2thread_t(VALUE thval)
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;
-}
-
-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;
+ return ret;
}
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 @@ rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func)
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;
+
+ 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;
+ }
- if (vm_event_hooks_running_thread(vm)) {
- ret = defer_remove_event_hook(vm->event_hooks, func);
+ 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);
+ }
-static int
-clear_trace_func_i(st_data_t key, st_data_t val, st_data_t flag)
-{
- rb_thread_t *th;
- GetThreadPtr((VALUE)key, th);
- rb_threadptr_remove_event_hook(th, 0);
- return ST_CONTINUE;
+ return state;
}
void
-rb_clear_trace_func(void)
+rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t event, VALUE self, ID id, VALUE klass)
+{
+ 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;
+ }
+}
+
+VALUE
+rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg)
{
- st_foreach(GET_VM()->living_threads, clear_trace_func_i, (st_data_t) 0);
- rb_remove_event_hook(0);
+ volatile int raised;
+ volatile int outer_state;
+ VALUE result = Qnil;
+ rb_thread_t *th = GET_THREAD();
+ int state;
+ int tracing = th->trace_running;
+
+ th->trace_running = 1;
+ raised = rb_threadptr_reset_raised(th);
+ outer_state = th->state;
+ th->state = 0;
+
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ result = (*func)(arg);
+ }
+ POP_TAG();
+
+ if (raised) {
+ rb_threadptr_set_raised(th);
+ }
+ th->trace_running = tracing;
+
+ if (state) {
+ JUMP_TAG(state);
+ }
+
+ th->state = outer_state;
+ return result;
}
static void call_trace_func(rb_event_flag_t, VALUE data, VALUE self, ID id, VALUE klass);
@@ -393,7 +412,6 @@ set_trace_func(VALUE obj, VALUE trace)
rb_remove_event_hook(call_trace_func);
if (NIL_P(trace)) {
- GET_THREAD()->tracing = EVENT_RUNNING_NOTHING;
return Qnil;
}
@@ -412,7 +430,7 @@ thread_add_trace_func(rb_thread_t *th, VALUE trace)
rb_raise(rb_eTypeError, "trace_func needs to be Proc");
}
- rb_threadptr_add_event_hook(th, call_trace_func, RUBY_EVENT_ALL, trace);
+ rb_threadptr_add_event_hook(th, call_trace_func, RUBY_EVENT_ALL, trace, RUBY_HOOK_FLAG_SAFE);
}
/*
@@ -450,9 +468,9 @@ thread_set_trace_func_m(VALUE obj, VALUE trace)
rb_threadptr_remove_event_hook(th, call_trace_func);
if (NIL_P(trace)) {
- th->tracing = EVENT_RUNNING_NOTHING;
return Qnil;
}
+
thread_add_trace_func(th, trace);
return trace;
}
@@ -482,27 +500,27 @@ get_event_name(rb_event_flag_t event)
}
}
-static VALUE
-call_trace_proc(VALUE args, int tracing)
+static void
+call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
{
- struct event_call_args *p = (struct event_call_args *)args;
const char *srcfile = rb_sourcefile();
- VALUE eventname = rb_str_new2(get_event_name(p->event));
+ VALUE eventname = rb_str_new2(get_event_name(event));
VALUE filename = srcfile ? rb_str_new2(srcfile) : Qnil;
VALUE argv[6];
int line = rb_sourceline();
- ID id = 0;
- VALUE klass = 0;
+ rb_thread_t *th = GET_THREAD();
- if (p->klass != 0) {
- id = p->id;
- klass = p->klass;
+ if (klass != 0) {
+ id = id;
+ klass = klass;
}
else {
- rb_thread_method_id_and_class(p->th, &id, &klass);
+ rb_thread_method_id_and_class(th, &id, &klass);
}
+
if (id == ID_ALLOCATOR)
- return Qnil;
+ return;
+
if (klass) {
if (RB_TYPE_P(klass, T_ICLASS)) {
klass = RBASIC(klass)->klass;
@@ -516,69 +534,10 @@ call_trace_proc(VALUE args, int tracing)
argv[1] = filename;
argv[2] = INT2FIX(line);
argv[3] = id ? ID2SYM(id) : Qnil;
- argv[4] = (p->self && srcfile) ? rb_binding_new() : Qnil;
+ argv[4] = (self && srcfile) ? rb_binding_new() : Qnil;
argv[5] = klass ? klass : Qnil;
- return rb_proc_call_with_block(p->proc, 6, argv, Qnil);
-}
-
-static void
-call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
-{
- struct event_call_args args;
-
- args.th = GET_THREAD();
- args.event = event;
- args.proc = proc;
- args.self = self;
- args.id = id;
- args.klass = klass;
- ruby_suppress_tracing(call_trace_proc, (VALUE)&args, FALSE);
-}
-
-VALUE
-ruby_suppress_tracing(VALUE (*func)(VALUE, int), VALUE arg, int always)
-{
- rb_thread_t *th = GET_THREAD();
- return thread_suppress_tracing(th, EVENT_RUNNING_TRACE, func, arg, always);
-}
-
-static VALUE
-thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always)
-{
- int state, tracing = th->tracing, running = tracing & ev;
- volatile int raised;
- volatile int outer_state;
- VALUE result = Qnil;
-
- if (running == ev && !always) {
- return Qnil;
- }
- else {
- th->tracing |= ev;
- }
-
- raised = rb_threadptr_reset_raised(th);
- outer_state = th->state;
- th->state = 0;
-
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- result = (*func)(arg, running);
- }
-
- if (raised) {
- rb_threadptr_set_raised(th);
- }
- POP_TAG();
-
- th->tracing = tracing;
- if (state) {
- JUMP_TAG(state);
- }
- th->state = outer_state;
-
- return result;
+ rb_proc_call_with_block(proc, 6, argv, Qnil);
}
/* (2-2) TracePoint API (not yet) */