[#25808] break & retry in block — Shin-ichiro HARA <sinara@...>

原です。

15 messages 2005/03/04

[#25812] Re: [ruby-cvs] ruby/test/ruby, ruby/test/logger, ruby/sample, ruby/misc, ruby/lib/xmlrpc, ruby/lib/wsdl/soap, ruby/lib/rexml, ruby/lib/rdoc/parsers, ruby/lib/rdoc/generators, ruby/lib/irb, ruby/lib, ruby/ext/zlib, ruby/ext/win32ole, ruby/ext/tk, ruby/ext/strscan, ruby/ext/socket, ruby/ext/readline, ruby/ext/pty, ruby/ext/openssl, ruby/ext/iconv, ruby/ext/etc, ruby/ext/dl, ruby/ext/curses, ruby/ext/bigdecimal, ruby/ext/Win32API, ruby: * array.c: replace rb_protect_inspect() and rb_inspecting_p() by — Tanaka Akira <akr@...17n.org>

In article <20050304064753.53859C671F@lithium.ruby-lang.org>,

3 messages 2005/03/06

[#25853] conflict method and local variable — Hidetoshi NAGAI <nagai@...>

永井@知能.九工大です.

56 messages 2005/03/10
[#25854] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/10

まつもと ゆきひろです

[#25855] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/10

永井@知能.九工大です.

[#25856] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/10

まつもと ゆきひろです

[#25857] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/11

永井@知能.九工大です.

[#25858] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/11

まつもと ゆきひろです

[#25861] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/11

永井@知能.九工大です.

[#25863] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/11

まつもと ゆきひろです

[#25864] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/11

永井@知能.九工大です.

[#25865] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/11

まつもと ゆきひろです

[#25866] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/11

永井@知能.九工大です.

[#25869] Re: conflict method and local variable — Shugo Maeda <shugo@...> 2005/03/13

前田です。

[#25875] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/13

まつもと ゆきひろです

[#25878] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/13

永井@知能.九工大です.

[#25882] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/13

まつもと ゆきひろです

[#25884] Re: conflict method and local variable — Hidetoshi NAGAI <nagai@...> 2005/03/14

永井@知能.九工大です.

[#25885] Re: conflict method and local variable — Yukihiro Matsumoto <matz@...> 2005/03/14

まつもと ゆきひろです

[#25888] Re: conflict method and local variable — Shugo Maeda <shugo@...> 2005/03/14

前田です。

[#25946] ext/tk/sample/**/*.gif are broken — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp>

山本です。

16 messages 2005/03/27

[#25959] some trouble on ext/tk/sample — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp>

山本です。

20 messages 2005/03/29
[#25969] Re: some trouble on ext/tk/sample — Hidetoshi NAGAI <nagai@...> 2005/03/30

永井@知能.九工大です.

[#25970] Re: some trouble on ext/tk/sample — "H.Yamamoto" <ocean@...2.ccsnet.ne.jp> 2005/03/30

山本です。

[#25973] Re: some trouble on ext/tk/sample — Hidetoshi NAGAI <nagai@...> 2005/03/31

永井@知能.九工大です.

[ruby-dev:25870] Re: C level set_trace_func

From: Shugo Maeda <shugo@...>
Date: 2005-03-13 00:18:42 UTC
List: ruby-dev #25870
前田です。

Shugo Maeda wrote:
>>|今Cでプロファイラを書いているのですが、Cレベルでset_trace_funcのような
>>|ことができるようにしていただけないでしょうか。
>>
>>パッチを当ててもよいですが、せっかく手を入れるんなら複数のイ
>>ベントフックを登録したいような気がするんですが、どう思います
>>か?
> 
> 
> そう思いつつ手を抜いていました。手が空いたら書き直します。

実装してみました。
パッチを添付します。

> それはそれとして、今のAPIだとRubyで定義されたメソッドで例外が発生する
> と、メソッドからの脱出を追えないのですが、これはどうしたものでしょう。
> rescueもフックできるようにして、raise時に保存した$!.backtraceとrescue時
> の$!.backtraceを比較する、とかですかね。

こっちはどうでしょうね。

-- 
前田 修吾

Attachments (1)

event-hook.diff (9.19 KB, text/x-diff)
Index: eval.c
===================================================================
RCS file: /src/ruby/eval.c,v
retrieving revision 1.764
diff -u -p -r1.764 eval.c
--- eval.c	8 Mar 2005 01:52:15 -0000	1.764
+++ eval.c	12 Mar 2005 23:51:45 -0000
@@ -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, k
     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, k
     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);
@@ -4591,10 +4673,9 @@ return_jump(retval)
 	{ 
 	    tt->dst = (VALUE)tt->frame->uniq;
 	    tt->retval = retval;
-	    if (trace_func) {
-		struct FRAME *f = tt->frame;
-		call_trace_func("return", f->node, f->self, f->this_func, f->this_class);
-	    }
+	    EXEC_EVENT_HOOK(RUBY_EVENT_RETURN,
+			    tt->frame->node, tt->frame->self,
+			    tt->frame->this_func, tt->frame->this_class);
 	    JUMP_TAG(TAG_RETURN);
 	}
 	if (tt->tag == PROT_THREAD) {
@@ -5589,17 +5670,19 @@ rb_call0(klass, recv, id, oid, argc, arg
 		rb_bug("bad argc (%d) specified for `%s(%s)'",
 		       len, rb_class2name(klass), rb_id2name(id));
 	    }
-	    if (trace_func) {
+	    if (event_hooks) {
 		int state;
 
-		call_trace_func("c-call", ruby_current_node, recv, id, klass);
+		EXEC_EVENT_HOOK(RUBY_EVENT_C_CALL, ruby_current_node,
+				recv, id, klass);
 		PUSH_TAG(PROT_FUNC);
 		if ((state = EXEC_TAG()) == 0) {
 		    result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
 		}
 		POP_TAG();
 		ruby_current_node = ruby_frame->node;
-		call_trace_func("c-return", ruby_current_node, recv, id, klass);
+		EXEC_EVENT_HOOK(RUBY_EVENT_C_RETURN, ruby_current_node,
+				recv, id, klass);
 		if (state) JUMP_TAG(state);
 	    }
 	    else {
@@ -5729,13 +5812,9 @@ rb_call0(klass, recv, id, oid, argc, arg
 		    ruby_frame->argc = -(ruby_frame->argc - argc)-1;
 		}
 
-		if (trace_func) {
-		    call_trace_func("call", b2, recv, id, klass);
-		}
+		EXEC_EVENT_HOOK(RUBY_EVENT_CALL, b2, recv, id, klass);
 		result = rb_eval(recv, body);
-		if (trace_func) {
-		    call_trace_func("return", body, recv, id, klass);
-		}
+		EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, body, recv, id, klass);
 	    }
 	    else if (state == TAG_RETURN && TAG_DST()) {
 		result = prot_tag->retval;
Index: node.h
===================================================================
RCS file: /src/ruby/node.h,v
retrieving revision 1.62
diff -u -p -r1.62 node.h
--- node.h	2 Mar 2005 03:21:30 -0000	1.62
+++ node.h	12 Mar 2005 23:51:45 -0000
@@ -366,6 +366,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

In This Thread