* eval.c (rb_add_event_hook): new function to add a hook function for

interpreter events.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8162 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shugo 2005-03-16 13:05:46 +00:00
Родитель feda16cbd4
Коммит 1aeb9b93c2
5 изменённых файлов: 192 добавлений и 35 удалений

Просмотреть файл

@ -1,3 +1,8 @@
Wed Mar 16 22:03:15 2005 Shugo Maeda <shugo@ruby-lang.org>
* eval.c (rb_add_event_hook): new function to add a hook function for
interpreter events.
Wed Mar 16 18:08:32 2005 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (rb_call0): reorganize "return" event post.

Просмотреть файл

@ -1001,6 +1001,32 @@ Starts execution of the interpreter.
Specifies the name of the script ($0).
** Hooks for the Interpreter Events
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_t events)
Adds a hook function for the specified interpreter events.
events should be Or'ed value of:
RUBY_EVENT_LINE
RUBY_EVENT_CLASS
RUBY_EVENT_END
RUBY_EVENT_CALL
RUBY_EVENT_RETURN
RUBY_EVENT_C_CALL
RUBY_EVENT_C_RETURN
RUBY_EVENT_RAISE
RUBY_EVENT_ALL
The definition of rb_event_hook_func_t is below:
typedef void (*rb_event_hook_func_t)(rb_event_t event, NODE *node,
VALUE self, ID id, VALUE klass)
int rb_remove_event_hook(rb_event_hook_func_t func)
Removes the specified hook function.
Appendix C. Functions Available in extconf.rb
These functions are available in extconf.rb:

Просмотреть файл

@ -1117,6 +1117,32 @@ void ruby_script(char *name)
Rubyのスクリプト名($0)を設定する.
** インタプリタのイベントのフック
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_t events)
指定されたインタプリタのイベントに対するフック関数を追加します.
eventsは以下の値のorでなければなりません:
RUBY_EVENT_LINE
RUBY_EVENT_CLASS
RUBY_EVENT_END
RUBY_EVENT_CALL
RUBY_EVENT_RETURN
RUBY_EVENT_C_CALL
RUBY_EVENT_C_RETURN
RUBY_EVENT_RAISE
RUBY_EVENT_ALL
rb_event_hook_func_tの定義は以下の通りです:
typedef void (*rb_event_hook_func_t)(rb_event_t event, NODE *node,
VALUE self, ID id, VALUE klass)
int rb_remove_event_hook(rb_event_hook_func_t func)
指定されたフック関数を削除します.
Appendix C. extconf.rbで使える関数たち

153
eval.c
Просмотреть файл

@ -1040,9 +1040,27 @@ static VALUE module_setup _((VALUE,NODE*));
static VALUE massign _((VALUE,NODE*,VALUE,int));
static void assign _((VALUE,NODE*,VALUE,int));
typedef struct event_hook {
rb_event_hook_func_t func;
rb_event_t events;
struct event_hook *next;
} rb_event_hook_t;
static rb_event_hook_t *event_hooks;
#define EXEC_EVENT_HOOK(event, node, self, id, klass) \
do { \
rb_event_hook_t *hook; \
\
for (hook = event_hooks; hook; hook = hook->next) { \
if (hook->events & event) \
(*hook->func)(event, node, self, id, klass); \
} \
} while (0)
static VALUE trace_func = 0;
static int tracing = 0;
static void call_trace_func _((char*,NODE*,VALUE,ID,VALUE));
static void call_trace_func _((rb_event_t,NODE*,VALUE,ID,VALUE));
#if 0
#define SET_CURRENT_SOURCE() (ruby_sourcefile = ruby_current_node->nd_file, \
@ -2415,6 +2433,42 @@ rb_obj_is_proc(proc)
return Qfalse;
}
void
rb_add_event_hook(rb_event_hook_func_t func, rb_event_t events)
{
rb_event_hook_t *hook;
hook = ALLOC(rb_event_hook_t);
hook->func = func;
hook->events = events;
hook->next = event_hooks;
event_hooks = hook;
}
int
rb_remove_event_hook(rb_event_hook_func_t func)
{
rb_event_hook_t *prev, *hook;
prev = NULL;
hook = event_hooks;
while (hook) {
if (hook->func == func) {
if (prev) {
prev->next = hook->next;
}
else {
event_hooks = hook->next;
}
xfree(hook);
return 0;
}
prev = hook;
hook = hook->next;
}
return -1;
}
/*
* call-seq:
* set_trace_func(proc) => proc
@ -2463,19 +2517,53 @@ static VALUE
set_trace_func(obj, trace)
VALUE obj, trace;
{
rb_event_hook_t *hook;
if (NIL_P(trace)) {
trace_func = 0;
rb_remove_event_hook(call_trace_func);
return Qnil;
}
if (!rb_obj_is_proc(trace)) {
rb_raise(rb_eTypeError, "trace_func needs to be Proc");
}
return trace_func = trace;
trace_func = trace;
for (hook = event_hooks; hook; hook = hook->next) {
if (hook->func == call_trace_func)
return trace;
}
rb_add_event_hook(call_trace_func, RUBY_EVENT_ALL);
return trace;
}
static char *
get_event_name(rb_event_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 void
call_trace_func(event, node, self, id, klass)
char *event;
rb_event_t event;
NODE *node;
VALUE self;
ID id;
@ -2485,6 +2573,7 @@ call_trace_func(event, node, self, id, klass)
struct FRAME *prev;
NODE *node_save;
VALUE srcfile;
char *event_name;
if (!trace_func) return;
if (tracing) return;
@ -2519,7 +2608,8 @@ call_trace_func(event, node, self, id, klass)
raised = thread_reset_raised();
if ((state = EXEC_TAG()) == 0) {
srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)");
proc_invoke(trace_func, rb_ary_new3(6, rb_str_new2(event),
event_name = get_event_name(event);
proc_invoke(trace_func, rb_ary_new3(6, rb_str_new2(event_name),
srcfile,
INT2FIX(ruby_sourceline),
id?ID2SYM(id):Qnil,
@ -2686,8 +2776,8 @@ rb_eval(self, n)
if (!node) RETURN(Qnil);
ruby_current_node = node;
if (trace_func && (node->flags & NODE_NEWLINE)) {
call_trace_func("line", node, self,
if (node->flags & NODE_NEWLINE) {
EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
ruby_frame->this_func,
ruby_frame->this_class);
}
@ -2783,11 +2873,9 @@ rb_eval(self, n)
RETURN(ruby_errinfo);
case NODE_IF:
if (trace_func) {
call_trace_func("line", node, self,
ruby_frame->this_func,
ruby_frame->this_class);
}
EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
ruby_frame->this_func,
ruby_frame->this_class);
if (RTEST(rb_eval(self, node->nd_cond))) {
node = node->nd_body;
}
@ -2803,11 +2891,9 @@ rb_eval(self, n)
if (nd_type(node) != NODE_WHEN) goto again;
tag = node->nd_head;
while (tag) {
if (trace_func) {
call_trace_func("line", tag, self,
ruby_frame->this_func,
ruby_frame->this_class);
}
EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
ruby_frame->this_func,
ruby_frame->this_class);
if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
VALUE v = rb_eval(self, tag->nd_head->nd_head);
long i;
@ -2846,11 +2932,9 @@ rb_eval(self, n)
}
tag = node->nd_head;
while (tag) {
if (trace_func) {
call_trace_func("line", tag, self,
ruby_frame->this_func,
ruby_frame->this_class);
}
EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
ruby_frame->this_func,
ruby_frame->this_class);
if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
VALUE v = rb_eval(self, tag->nd_head->nd_head);
long i;
@ -3961,9 +4045,8 @@ module_setup(module, n)
PUSH_CREF(module);
PUSH_TAG(PROT_NONE);
if ((state = EXEC_TAG()) == 0) {
if (trace_func) {
call_trace_func("class", n, ruby_cbase, ruby_frame->this_func, ruby_frame->this_class);
}
EXEC_EVENT_HOOK(RUBY_EVENT_CLASS, n, ruby_cbase,
ruby_frame->this_func, ruby_frame->this_class);
result = rb_eval(ruby_cbase, node->nd_next);
}
POP_TAG();
@ -3973,9 +4056,8 @@ module_setup(module, n)
POP_CLASS();
ruby_frame = frame.tmp;
if (trace_func) {
call_trace_func("end", n, 0, ruby_frame->this_func, ruby_frame->this_class);
}
EXEC_EVENT_HOOK(RUBY_EVENT_END, n, 0, ruby_frame->this_func,
ruby_frame->this_class);
if (state) JUMP_TAG(state);
return result;
@ -4370,8 +4452,8 @@ rb_longjmp(tag, mesg)
}
rb_trap_restore_mask();
if (trace_func && tag != TAG_FATAL) {
call_trace_func("raise", ruby_current_node,
if (tag != TAG_FATAL) {
EXEC_EVENT_HOOK(RUBY_EVENT_RAISE, ruby_current_node,
ruby_frame->self,
ruby_frame->this_func,
ruby_frame->this_class);
@ -5585,8 +5667,9 @@ rb_call0(klass, recv, id, oid, argc, argv, body, nosuper)
rb_bug("bad argc (%d) specified for `%s(%s)'",
len, rb_class2name(klass), rb_id2name(id));
}
if (trace_func) {
call_trace_func("c-call", ruby_current_node, recv, id, klass);
if (event_hooks) {
EXEC_EVENT_HOOK(RUBY_EVENT_C_CALL, ruby_current_node,
recv, id, klass);
trace_status = 1; /* cfunc */
}
result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
@ -5714,8 +5797,8 @@ rb_call0(klass, recv, id, oid, argc, argv, body, nosuper)
ruby_frame->argc = -(ruby_frame->argc - argc)-1;
}
if (trace_func) {
call_trace_func("call", b2, recv, id, klass);
if (event_hooks) {
EXEC_EVENT_HOOK(RUBY_EVENT_CALL, b2, recv, id, klass);
trace_status = 2; /* rfunc */
}
result = rb_eval(recv, body);
@ -5732,10 +5815,10 @@ rb_call0(klass, recv, id, oid, argc, argv, body, nosuper)
switch (trace_status) {
case 0: break; /* none */
case 1: /* cfunc */
call_trace_func("c-return", body, recv, id, klass);
EXEC_EVENT_HOOK(RUBY_EVENT_C_RETURN, body, recv, id, klass);
break;
case 2: /* rfunc */
call_trace_func("return", body, recv, id, klass);
EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, body, recv, id, klass);
break;
}
switch (state) {

17
node.h
Просмотреть файл

@ -365,6 +365,23 @@ VALUE rb_gvar_get _((struct global_entry *));
VALUE rb_gvar_set _((struct global_entry *, VALUE));
VALUE rb_gvar_defined _((struct global_entry *));
typedef unsigned int rb_event_t;
#define RUBY_EVENT_NONE 0x00
#define RUBY_EVENT_LINE 0x01
#define RUBY_EVENT_CLASS 0x02
#define RUBY_EVENT_END 0x04
#define RUBY_EVENT_CALL 0x08
#define RUBY_EVENT_RETURN 0x10
#define RUBY_EVENT_C_CALL 0x20
#define RUBY_EVENT_C_RETURN 0x40
#define RUBY_EVENT_RAISE 0x80
#define RUBY_EVENT_ALL 0xff
typedef void (*rb_event_hook_func_t)_((rb_event_t,NODE*,VALUE,ID,VALUE));
void rb_add_event_hook(rb_event_hook_func_t,rb_event_t);
int rb_remove_event_hook(rb_event_hook_func_t);
#if defined(__cplusplus)
} /* extern "C" { */
#endif