Skip to content

Commit

Permalink
* eval.c (rb_add_event_hook): new function to add a hook function for
Browse files Browse the repository at this point in the history
  interpreter events.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8162 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
shugo committed Mar 16, 2005
1 parent feda16c commit 1aeb9b9
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 35 deletions.
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Wed Mar 16 22:03:15 2005 Shugo Maeda <[email protected]>

* 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 <[email protected]>

* eval.c (rb_call0): reorganize "return" event post.
Expand Down
26 changes: 26 additions & 0 deletions README.EXT
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
26 changes: 26 additions & 0 deletions README.EXT.ja
Original file line number Diff line number Diff line change
Expand Up @@ -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�ǻȤ���ؿ�����

Expand Down
153 changes: 118 additions & 35 deletions eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down
17 changes: 17 additions & 0 deletions node.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 1aeb9b9

Please sign in to comment.