mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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:
parent
feda16cbd4
commit
1aeb9b93c2
5 changed files with 192 additions and 35 deletions
|
@ -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.
|
||||
|
|
26
README.EXT
26
README.EXT
|
@ -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
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
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
|
||||
|
|
Loading…
Reference in a new issue