ruby-changes:24652
From: ko1 <ko1@a...>
Date: Wed, 15 Aug 2012 13:39:22 +0900 (JST)
Subject: [ruby-changes:24652] ko1:r36703 (trunk): * vm_trace.c: separate trace_func related functions from
ko1 2012-08-15 13:39:10 +0900 (Wed, 15 Aug 2012) New Revision: 36703 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=36703 Log: * vm_trace.c: separate trace_func related functions from thread.c. * thread.c: ditto. * common.mk: add vm_trace.o. * inits.c: call Init_vm_trace(). Added files: trunk/vm_trace.c Modified files: trunk/ChangeLog trunk/common.mk trunk/inits.c trunk/thread.c Index: ChangeLog =================================================================== --- ChangeLog (revision 36702) +++ ChangeLog (revision 36703) @@ -1,3 +1,14 @@ +Wed Aug 15 11:39:53 2012 Koichi Sasada <ko1@a...> + + * vm_trace.c: separate trace_func related functions from + thread.c. + + * thread.c: ditto. + + * common.mk: add vm_trace.o. + + * inits.c: call Init_vm_trace(). + Tue Aug 14 16:25:46 2012 Shugo Maeda <shugo@r...> * test/erb/test_erb.rb (test_html_escape): add assertions for the Index: thread.c =================================================================== --- thread.c (revision 36702) +++ thread.c (revision 36703) @@ -4442,558 +4442,8 @@ return exec_recursive(func, obj, 0, arg, 1); } -/* tracer */ -#define RUBY_EVENT_REMOVED 0x1000000 - -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 -}; - -static VALUE thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always); - -struct event_call_args { - rb_thread_t *th; - VALUE klass; - VALUE self; - VALUE proc; - ID id; - rb_event_flag_t event; -}; - -static rb_event_hook_t * -alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data) -{ - rb_event_hook_t *hook = ALLOC(rb_event_hook_t); - hook->func = func; - hook->flag = events; - hook->data = data; - return hook; -} - -static void -thread_reset_event_flags(rb_thread_t *th) -{ - rb_event_hook_t *hook = th->event_hooks; - rb_event_flag_t flag = th->event_flags & RUBY_EVENT_VM; - - while (hook) { - if (!(flag & RUBY_EVENT_REMOVED)) - flag |= hook->flag; - hook = hook->next; - } - 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) -{ - 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); -} - -static rb_thread_t * -thval2thread_t(VALUE thval) -{ - rb_thread_t *th; - GetThreadPtr(thval, th); - return th; -} - -void -rb_thread_add_event_hook(VALUE thval, - rb_event_hook_func_t func, rb_event_flag_t events, VALUE data) -{ - rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data); -} - -static int -set_threads_event_flags_i(st_data_t key, st_data_t val, st_data_t flag) -{ - 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; -} - -static void -set_threads_event_flags(int flag) -{ - st_foreach(GET_VM()->living_threads, set_threads_event_flags_i, (st_data_t) flag); -} - -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) -{ - 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; -} - -void -rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass) -{ - 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; -} - -void -rb_add_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); -} - -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 *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; -} - -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; -} - -int -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) -{ - 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 = search_live_hook(vm->event_hooks); - int ret; - - 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); - } - - return ret; -} - -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; -} - -void -rb_clear_trace_func(void) -{ - st_foreach(GET_VM()->living_threads, clear_trace_func_i, (st_data_t) 0); - rb_remove_event_hook(0); -} - -static void call_trace_func(rb_event_flag_t, VALUE data, VALUE self, ID id, VALUE klass); - /* * call-seq: - * set_trace_func(proc) -> proc - * set_trace_func(nil) -> nil - * - * Establishes _proc_ as the handler for tracing, or disables - * tracing if the parameter is +nil+. _proc_ takes up - * to six parameters: an event name, a filename, a line number, an - * object id, a binding, and the name of a class. _proc_ is - * invoked whenever an event occurs. Events are: <code>c-call</code> - * (call a C-language routine), <code>c-return</code> (return from a - * C-language routine), <code>call</code> (call a Ruby method), - * <code>class</code> (start a class or module definition), - * <code>end</code> (finish a class or module definition), - * <code>line</code> (execute code on a new line), <code>raise</code> - * (raise an exception), and <code>return</code> (return from a Ruby - * method). Tracing is disabled within the context of _proc_. - * - * class Test - * def test - * a = 1 - * b = 2 - * end - * end - * - * set_trace_func proc { |event, file, line, id, binding, classname| - * printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname - * } - * t = Test.new - * t.test - * - * line prog.rb:11 false - * c-call prog.rb:11 new Class - * c-call prog.rb:11 initialize Object - * c-return prog.rb:11 initialize Object - * c-return prog.rb:11 new Class - * line prog.rb:12 false - * call prog.rb:2 test Test - * line prog.rb:3 test Test - * line prog.rb:4 test Test - * return prog.rb:4 test Test - */ - -static VALUE -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; - } - - if (!rb_obj_is_proc(trace)) { - rb_raise(rb_eTypeError, "trace_func needs to be Proc"); - } - - rb_add_event_hook(call_trace_func, RUBY_EVENT_ALL, trace); - return trace; -} - -static void -thread_add_trace_func(rb_thread_t *th, VALUE trace) -{ - if (!rb_obj_is_proc(trace)) { - rb_raise(rb_eTypeError, "trace_func needs to be Proc"); - } - - rb_threadptr_add_event_hook(th, call_trace_func, RUBY_EVENT_ALL, trace); -} - -/* - * call-seq: - * thr.add_trace_func(proc) -> proc - * - * Adds _proc_ as a handler for tracing. - * See <code>Thread#set_trace_func</code> and +set_trace_func+. - */ - -static VALUE -thread_add_trace_func_m(VALUE obj, VALUE trace) -{ - rb_thread_t *th; - GetThreadPtr(obj, th); - thread_add_trace_func(th, trace); - return trace; -} - -/* - * call-seq: - * thr.set_trace_func(proc) -> proc - * thr.set_trace_func(nil) -> nil - * - * Establishes _proc_ on _thr_ as the handler for tracing, or - * disables tracing if the parameter is +nil+. - * See +set_trace_func+. - */ - -static VALUE -thread_set_trace_func_m(VALUE obj, VALUE trace) -{ - rb_thread_t *th; - GetThreadPtr(obj, th); - 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; -} - -static const char * -get_event_name(rb_event_flag_t event) -{ - switch (event) { - case RUBY_EVENT_LINE: - return "line"; - case RUBY_EVENT_CLASS: - return "class"; - case RUBY_EVENT_END: - return "end"; - case RUBY_EVENT_CALL: - return "call"; - case RUBY_EVENT_RETURN: - return "return"; - case RUBY_EVENT_C_CALL: - return "c-call"; - case RUBY_EVENT_C_RETURN: - return "c-return"; - case RUBY_EVENT_RAISE: - return "raise"; - default: - return "unknown"; - } -} - -static VALUE -call_trace_proc(VALUE args, int tracing) -{ - 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 filename = srcfile ? rb_str_new2(srcfile) : Qnil; - VALUE argv[6]; - int line = rb_sourceline(); - ID id = 0; - VALUE klass = 0; - - if (p->klass != 0) { - id = p->id; - klass = p->klass; - } - else { - rb_thread_method_id_and_class(p->th, &id, &klass); - } - if (id == ID_ALLOCATOR) - return Qnil; - if (klass) { - if (RB_TYPE_P(klass, T_ICLASS)) { - klass = RBASIC(klass)->klass; - } - else if (FL_TEST(klass, FL_SINGLETON)) { - klass = rb_iv_get(klass, "__attached__"); - } - } - - argv[0] = eventname; - argv[1] = filename; - argv[2] = INT2FIX(line); - argv[3] = id ? ID2SYM(id) : Qnil; - argv[4] = (p->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; -} - -/* - * call-seq: * thr.backtrace -> array * * Returns the current back trace of the _thr_. @@ -5110,11 +4560,6 @@ recursive_key = rb_intern("__recursive_key__"); rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError); - /* trace */ - rb_define_global_function("set_trace_func", set_trace_func, 1); - rb_define_method(rb_cThread, "set_trace_func", thread_set_trace_func_m, 1); - rb_define_method(rb_cThread, "add_trace_func", thread_add_trace_func_m, 1); - /* init thread core */ { /* main thread setting */ Index: common.mk =================================================================== --- common.mk (revision 36702) +++ common.mk (revision 36703) @@ -92,6 +92,7 @@ vm.$(OBJEXT) \ vm_dump.$(OBJEXT) \ vm_backtrace.$(OBJEXT) \ + vm_trace.$(OBJEXT) \ thread.$(OBJEXT) \ cont.$(OBJEXT) \ $(BUILTIN_ENCOBJS) \ @@ -781,6 +782,9 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}vm_backtrace.c \ $(VM_CORE_H_INCLUDES) $(RUBY_H_INCLUDES) \ {$(VPATH)}internal.h {$(VPATH)}iseq.h +vm_trace.$(OBJEXT): {$(VPATH)}vm_trace.c \ + $(VM_CORE_H_INCLUDES) $(RUBY_H_INCLUDES) \ + {$(VPATH)}internal.h miniprelude.$(OBJEXT): {$(VPATH)}miniprelude.c $(RUBY_H_INCLUDES) \ $(VM_CORE_H_INCLUDES) {$(VPATH)}debug.h {$(VPATH)}internal.h prelude.$(OBJEXT): {$(VPATH)}prelude.c $(RUBY_H_INCLUDES) \ Index: vm_trace.c =================================================================== --- vm_trace.c (revision 0) +++ vm_trace.c (revision 36703) @@ -0,0 +1,596 @@ +/********************************************************************** + + vm_trace.c - + + $Author: ko1 $ + created at: Tue Aug 14 19:37:09 2012 + + Copyright (C) 1993-2012 Yukihiro Matsumoto + +**********************************************************************/ + +/* + * This file incldue two parts: + * + * (1) set_trace_func internal mechanisms + * and C level API + * + * (2) Ruby level API + * (2-1) set_trace_func API + * (2-2) TracePoint API (not yet) + * + */ + +#include "ruby/ruby.h" +#include "ruby/encoding.h" + +#include "internal.h" +#include "vm_core.h" +#include "eval_intern.h" + +/* (1) trace mechanisms */ + +#define RUBY_EVENT_REMOVED 0x1000000 + +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 +}; + +static VALUE thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always); + +struct event_call_args { + rb_thread_t *th; + VALUE klass; + VALUE self; + VALUE proc; + ID id; + rb_event_flag_t event; +}; + +static rb_event_hook_t * +alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data) +{ + rb_event_hook_t *hook = ALLOC(rb_event_hook_t); + hook->func = func; + hook->flag = events; + hook->data = data; + return hook; +} + +static void +thread_reset_event_flags(rb_thread_t *th) +{ + rb_event_hook_t *hook = th->event_hooks; + rb_event_flag_t flag = th->event_flags & RUBY_EVENT_VM; + + while (hook) { + if (!(flag & RUBY_EVENT_REMOVED)) + flag |= hook->flag; + hook = hook->next; + } + 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) +{ + 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); +} + +static rb_thread_t * +thval2thread_t(VALUE thval) +{ + rb_thread_t *th; + GetThreadPtr(thval, th); + return th; +} + +void +rb_thread_add_event_hook(VALUE thval, + rb_event_hook_func_t func, rb_event_flag_t events, VALUE data) +{ + rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data); +} + +static int +set_threads_event_flags_i(st_data_t key, st_data_t val, st_data_t flag) +{ + 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; +} + +static void +set_threads_event_flags(int flag) +{ + st_foreach(GET_VM()->living_threads, set_threads_event_flags_i, (st_data_t) flag); +} + +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) +{ + 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 &= (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/