00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "ruby/ruby.h"
00025 #include "ruby/debug.h"
00026 #include "ruby/encoding.h"
00027
00028 #include "internal.h"
00029 #include "vm_core.h"
00030 #include "eval_intern.h"
00031
00032
00033
00034 typedef struct rb_event_hook_struct {
00035 rb_event_hook_flag_t hook_flags;
00036 rb_event_flag_t events;
00037 rb_event_hook_func_t func;
00038 VALUE data;
00039 struct rb_event_hook_struct *next;
00040 } rb_event_hook_t;
00041
00042 typedef void (*rb_event_hook_raw_arg_func_t)(VALUE data, const rb_trace_arg_t *arg);
00043
00044 #define MAX_EVENT_NUM 32
00045
00046 static int ruby_event_flag_count[MAX_EVENT_NUM] = {0};
00047
00048
00049
00050 void
00051 rb_vm_trace_mark_event_hooks(rb_hook_list_t *hooks)
00052 {
00053 rb_event_hook_t *hook = hooks->hooks;
00054
00055 while (hook) {
00056 rb_gc_mark(hook->data);
00057 hook = hook->next;
00058 }
00059 }
00060
00061
00062
00063 static void
00064 recalc_add_ruby_vm_event_flags(rb_event_flag_t events)
00065 {
00066 int i;
00067 ruby_vm_event_flags = 0;
00068
00069 for (i=0; i<MAX_EVENT_NUM; i++) {
00070 if (events & (1 << i)) {
00071 ruby_event_flag_count[i]++;
00072 }
00073 ruby_vm_event_flags |= ruby_event_flag_count[i] ? (1<<i) : 0;
00074 }
00075
00076 rb_objspace_set_event_hook(ruby_vm_event_flags);
00077 }
00078
00079 static void
00080 recalc_remove_ruby_vm_event_flags(rb_event_flag_t events)
00081 {
00082 int i;
00083 ruby_vm_event_flags = 0;
00084
00085 for (i=0; i<MAX_EVENT_NUM; i++) {
00086 if (events & (1 << i)) {
00087 ruby_event_flag_count[i]--;
00088 }
00089 ruby_vm_event_flags |= ruby_event_flag_count[i] ? (1<<i) : 0;
00090 }
00091
00092 rb_objspace_set_event_hook(ruby_vm_event_flags);
00093 }
00094
00095
00096
00097 static rb_thread_t *
00098 thval2thread_t(VALUE thval)
00099 {
00100 rb_thread_t *th;
00101 GetThreadPtr(thval, th);
00102 return th;
00103 }
00104
00105 static rb_event_hook_t *
00106 alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flags)
00107 {
00108 rb_event_hook_t *hook;
00109
00110 if ((events & RUBY_INTERNAL_EVENT_MASK) && (events & ~RUBY_INTERNAL_EVENT_MASK)) {
00111 rb_raise(rb_eTypeError, "Can not specify normal event and internal event simultaneously.");
00112 }
00113
00114 hook = ALLOC(rb_event_hook_t);
00115 hook->hook_flags = hook_flags;
00116 hook->events = events;
00117 hook->func = func;
00118 hook->data = data;
00119 return hook;
00120 }
00121
00122 static void
00123 connect_event_hook(rb_hook_list_t *list, rb_event_hook_t *hook)
00124 {
00125 hook->next = list->hooks;
00126 list->hooks = hook;
00127 recalc_add_ruby_vm_event_flags(hook->events);
00128 list->events |= hook->events;
00129 }
00130
00131 static void
00132 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_flag_t hook_flags)
00133 {
00134 rb_event_hook_t *hook = alloc_event_hook(func, events, data, hook_flags);
00135 connect_event_hook(&th->event_hooks, hook);
00136 }
00137
00138 void
00139 rb_thread_add_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
00140 {
00141 rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data, RUBY_EVENT_HOOK_FLAG_SAFE);
00142 }
00143
00144 void
00145 rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
00146 {
00147 rb_event_hook_t *hook = alloc_event_hook(func, events, data, RUBY_EVENT_HOOK_FLAG_SAFE);
00148 connect_event_hook(&GET_VM()->event_hooks, hook);
00149 }
00150
00151 void
00152 rb_thread_add_event_hook2(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flags)
00153 {
00154 rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data, hook_flags);
00155 }
00156
00157 void
00158 rb_add_event_hook2(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flags)
00159 {
00160 rb_event_hook_t *hook = alloc_event_hook(func, events, data, hook_flags);
00161 connect_event_hook(&GET_VM()->event_hooks, hook);
00162 }
00163
00164
00165 static int
00166 remove_event_hook(rb_hook_list_t *list, rb_event_hook_func_t func, VALUE data)
00167 {
00168 int ret = 0;
00169 rb_event_hook_t *hook = list->hooks;
00170
00171 while (hook) {
00172 if (func == 0 || hook->func == func) {
00173 if (data == Qundef || hook->data == data) {
00174 hook->hook_flags |= RUBY_EVENT_HOOK_FLAG_DELETED;
00175 ret+=1;
00176 list->need_clean++;
00177 }
00178 }
00179 hook = hook->next;
00180 }
00181
00182 return ret;
00183 }
00184
00185 static int
00186 rb_threadptr_remove_event_hook(rb_thread_t *th, rb_event_hook_func_t func, VALUE data)
00187 {
00188 return remove_event_hook(&th->event_hooks, func, data);
00189 }
00190
00191 int
00192 rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func)
00193 {
00194 return rb_threadptr_remove_event_hook(thval2thread_t(thval), func, Qundef);
00195 }
00196
00197 int
00198 rb_thread_remove_event_hook_with_data(VALUE thval, rb_event_hook_func_t func, VALUE data)
00199 {
00200 return rb_threadptr_remove_event_hook(thval2thread_t(thval), func, data);
00201 }
00202
00203 int
00204 rb_remove_event_hook(rb_event_hook_func_t func)
00205 {
00206 return remove_event_hook(&GET_VM()->event_hooks, func, Qundef);
00207 }
00208
00209 int
00210 rb_remove_event_hook_with_data(rb_event_hook_func_t func, VALUE data)
00211 {
00212 return remove_event_hook(&GET_VM()->event_hooks, func, data);
00213 }
00214
00215 static int
00216 clear_trace_func_i(st_data_t key, st_data_t val, st_data_t flag)
00217 {
00218 rb_thread_t *th;
00219 GetThreadPtr((VALUE)key, th);
00220 rb_threadptr_remove_event_hook(th, 0, Qundef);
00221 return ST_CONTINUE;
00222 }
00223
00224 void
00225 rb_clear_trace_func(void)
00226 {
00227 st_foreach(GET_VM()->living_threads, clear_trace_func_i, (st_data_t) 0);
00228 rb_remove_event_hook(0);
00229 }
00230
00231
00232
00233 static void
00234 clean_hooks(rb_hook_list_t *list)
00235 {
00236 rb_event_hook_t *hook, **nextp = &list->hooks;
00237
00238 list->events = 0;
00239 list->need_clean = 0;
00240
00241 while ((hook = *nextp) != 0) {
00242 if (hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED) {
00243 *nextp = hook->next;
00244 recalc_remove_ruby_vm_event_flags(hook->events);
00245 xfree(hook);
00246 }
00247 else {
00248 list->events |= hook->events;
00249 nextp = &hook->next;
00250 }
00251 }
00252 }
00253
00254 static void
00255 exec_hooks_body(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
00256 {
00257 rb_event_hook_t *hook;
00258
00259 for (hook = list->hooks; hook; hook = hook->next) {
00260 if (!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED) && (trace_arg->event & hook->events)) {
00261 if (!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_RAW_ARG)) {
00262 (*hook->func)(trace_arg->event, hook->data, trace_arg->self, trace_arg->id, trace_arg->klass);
00263 }
00264 else {
00265 (*((rb_event_hook_raw_arg_func_t)hook->func))(hook->data, trace_arg);
00266 }
00267 }
00268 }
00269 }
00270
00271 static int
00272 exec_hooks_precheck(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
00273 {
00274 if ((list->events & trace_arg->event) == 0) return 0;
00275
00276 if (UNLIKELY(list->need_clean > 0)) {
00277 if (th->vm->trace_running <= 1) {
00278 clean_hooks(list);
00279 }
00280 }
00281 return 1;
00282 }
00283
00284 static void
00285 exec_hooks_unprotected(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
00286 {
00287 if (exec_hooks_precheck(th, list, trace_arg) == 0) return;
00288 exec_hooks_body(th, list, trace_arg);
00289 }
00290
00291 static int
00292 exec_hooks_protected(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
00293 {
00294 int state;
00295 volatile int raised;
00296
00297 if (exec_hooks_precheck(th, list, trace_arg) == 0) return 0;
00298
00299 raised = rb_threadptr_reset_raised(th);
00300
00301
00302
00303 TH_PUSH_TAG(th);
00304 if ((state = TH_EXEC_TAG()) == 0) {
00305 exec_hooks_body(th, list, trace_arg);
00306 }
00307 TH_POP_TAG();
00308
00309 if (raised) {
00310 rb_threadptr_set_raised(th);
00311 }
00312
00313 return state;
00314 }
00315
00316 static void
00317 rb_threadptr_exec_event_hooks_orig(rb_trace_arg_t *trace_arg, int pop_p)
00318 {
00319 rb_thread_t *th = trace_arg->th;
00320
00321 if (trace_arg->event & RUBY_INTERNAL_EVENT_MASK) {
00322 if (th->trace_arg && (th->trace_arg->event & RUBY_INTERNAL_EVENT_MASK)) {
00323
00324 }
00325 else {
00326 rb_trace_arg_t *prev_trace_arg = th->trace_arg;
00327 th->trace_arg = trace_arg;
00328 exec_hooks_unprotected(th, &th->event_hooks, trace_arg);
00329 exec_hooks_unprotected(th, &th->vm->event_hooks, trace_arg);
00330 th->trace_arg = prev_trace_arg;
00331 }
00332 }
00333 else {
00334 if (th->trace_arg == 0 &&
00335 trace_arg->self != rb_mRubyVMFrozenCore ) {
00336 const VALUE errinfo = th->errinfo;
00337 const int outer_state = th->state;
00338 const VALUE old_recursive = rb_threadptr_reset_recursive_data(th);
00339 int state = 0;
00340 th->state = 0;
00341 th->errinfo = Qnil;
00342
00343 th->vm->trace_running++;
00344 th->trace_arg = trace_arg;
00345 {
00346
00347 state = exec_hooks_protected(th, &th->event_hooks, trace_arg);
00348 if (state) goto terminate;
00349
00350
00351 state = exec_hooks_protected(th, &th->vm->event_hooks, trace_arg);
00352 if (state) goto terminate;
00353
00354 th->errinfo = errinfo;
00355 }
00356 terminate:
00357 th->trace_arg = 0;
00358 th->vm->trace_running--;
00359 rb_threadptr_restore_recursive_data(th, old_recursive);
00360
00361 if (state) {
00362 if (pop_p) {
00363 if (VM_FRAME_TYPE_FINISH_P(th->cfp)) {
00364 th->tag = th->tag->prev;
00365 }
00366 th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
00367 }
00368 TH_JUMP_TAG(th, state);
00369 }
00370 th->state = outer_state;
00371 }
00372 }
00373 }
00374
00375 void
00376 rb_threadptr_exec_event_hooks_and_pop_frame(rb_trace_arg_t *trace_arg)
00377 {
00378 rb_threadptr_exec_event_hooks_orig(trace_arg, 1);
00379 }
00380
00381 void
00382 rb_threadptr_exec_event_hooks(rb_trace_arg_t *trace_arg)
00383 {
00384 rb_threadptr_exec_event_hooks_orig(trace_arg, 0);
00385 }
00386
00387 VALUE
00388 rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg)
00389 {
00390 volatile int raised;
00391 volatile int outer_state;
00392 VALUE result = Qnil;
00393 rb_thread_t *th = GET_THREAD();
00394 int state;
00395 const int tracing = th->trace_arg ? 1 : 0;
00396 rb_trace_arg_t dummy_trace_arg;
00397 dummy_trace_arg.event = 0;
00398
00399 if (!tracing) th->vm->trace_running++;
00400 if (!th->trace_arg) th->trace_arg = &dummy_trace_arg;
00401
00402 raised = rb_threadptr_reset_raised(th);
00403 outer_state = th->state;
00404 th->state = 0;
00405
00406 TH_PUSH_TAG(th);
00407 if ((state = TH_EXEC_TAG()) == 0) {
00408 result = (*func)(arg);
00409 }
00410 TH_POP_TAG();
00411
00412 if (raised) {
00413 rb_threadptr_set_raised(th);
00414 }
00415
00416 if (th->trace_arg == &dummy_trace_arg) th->trace_arg = 0;
00417 if (!tracing) th->vm->trace_running--;
00418
00419 if (state) {
00420 JUMP_TAG(state);
00421 }
00422
00423 th->state = outer_state;
00424 return result;
00425 }
00426
00427 static void call_trace_func(rb_event_flag_t, VALUE data, VALUE self, ID id, VALUE klass);
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 static VALUE
00491 set_trace_func(VALUE obj, VALUE trace)
00492 {
00493
00494 rb_remove_event_hook(call_trace_func);
00495
00496 if (NIL_P(trace)) {
00497 return Qnil;
00498 }
00499
00500 if (!rb_obj_is_proc(trace)) {
00501 rb_raise(rb_eTypeError, "trace_func needs to be Proc");
00502 }
00503
00504 rb_add_event_hook(call_trace_func, RUBY_EVENT_ALL, trace);
00505 return trace;
00506 }
00507
00508 static void
00509 thread_add_trace_func(rb_thread_t *th, VALUE trace)
00510 {
00511 if (!rb_obj_is_proc(trace)) {
00512 rb_raise(rb_eTypeError, "trace_func needs to be Proc");
00513 }
00514
00515 rb_threadptr_add_event_hook(th, call_trace_func, RUBY_EVENT_ALL, trace, RUBY_EVENT_HOOK_FLAG_SAFE);
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 static VALUE
00528 thread_add_trace_func_m(VALUE obj, VALUE trace)
00529 {
00530 rb_thread_t *th;
00531
00532 GetThreadPtr(obj, th);
00533 thread_add_trace_func(th, trace);
00534 return trace;
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548 static VALUE
00549 thread_set_trace_func_m(VALUE obj, VALUE trace)
00550 {
00551 rb_thread_t *th;
00552
00553 GetThreadPtr(obj, th);
00554 rb_threadptr_remove_event_hook(th, call_trace_func, Qundef);
00555
00556 if (NIL_P(trace)) {
00557 return Qnil;
00558 }
00559
00560 thread_add_trace_func(th, trace);
00561 return trace;
00562 }
00563
00564 static const char *
00565 get_event_name(rb_event_flag_t event)
00566 {
00567 switch (event) {
00568 case RUBY_EVENT_LINE: return "line";
00569 case RUBY_EVENT_CLASS: return "class";
00570 case RUBY_EVENT_END: return "end";
00571 case RUBY_EVENT_CALL: return "call";
00572 case RUBY_EVENT_RETURN: return "return";
00573 case RUBY_EVENT_C_CALL: return "c-call";
00574 case RUBY_EVENT_C_RETURN: return "c-return";
00575 case RUBY_EVENT_RAISE: return "raise";
00576 default:
00577 return "unknown";
00578 }
00579 }
00580
00581 static ID
00582 get_event_id(rb_event_flag_t event)
00583 {
00584 ID id;
00585
00586 switch (event) {
00587 #define C(name, NAME) case RUBY_EVENT_##NAME: CONST_ID(id, #name); return id;
00588 C(line, LINE);
00589 C(class, CLASS);
00590 C(end, END);
00591 C(call, CALL);
00592 C(return, RETURN);
00593 C(c_call, C_CALL);
00594 C(c_return, C_RETURN);
00595 C(raise, RAISE);
00596 C(b_call, B_CALL);
00597 C(b_return, B_RETURN);
00598 C(thread_begin, THREAD_BEGIN);
00599 C(thread_end, THREAD_END);
00600 C(specified_line, SPECIFIED_LINE);
00601 case RUBY_EVENT_LINE | RUBY_EVENT_SPECIFIED_LINE: CONST_ID(id, "line"); return id;
00602 #undef C
00603 default:
00604 return 0;
00605 }
00606 }
00607
00608 static void
00609 call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
00610 {
00611 const char *srcfile = rb_sourcefile();
00612 VALUE eventname = rb_str_new2(get_event_name(event));
00613 VALUE filename = srcfile ? rb_str_new2(srcfile) : Qnil;
00614 VALUE argv[6];
00615 int line = rb_sourceline();
00616 rb_thread_t *th = GET_THREAD();
00617
00618 if (!klass) {
00619 rb_thread_method_id_and_class(th, &id, &klass);
00620 }
00621
00622 if (klass) {
00623 if (RB_TYPE_P(klass, T_ICLASS)) {
00624 klass = RBASIC(klass)->klass;
00625 }
00626 else if (FL_TEST(klass, FL_SINGLETON)) {
00627 klass = rb_ivar_get(klass, id__attached__);
00628 }
00629 }
00630
00631 argv[0] = eventname;
00632 argv[1] = filename;
00633 argv[2] = INT2FIX(line);
00634 argv[3] = id ? ID2SYM(id) : Qnil;
00635 argv[4] = (self && srcfile) ? rb_binding_new() : Qnil;
00636 argv[5] = klass ? klass : Qnil;
00637
00638 rb_proc_call_with_block(proc, 6, argv, Qnil);
00639 }
00640
00641
00642
00643 static VALUE rb_cTracePoint;
00644
00645 typedef struct rb_tp_struct {
00646 rb_event_flag_t events;
00647 rb_thread_t *target_th;
00648 void (*func)(VALUE tpval, void *data);
00649 void *data;
00650 VALUE proc;
00651 int tracing;
00652 VALUE self;
00653 } rb_tp_t;
00654
00655 static void
00656 tp_mark(void *ptr)
00657 {
00658 if (ptr) {
00659 rb_tp_t *tp = (rb_tp_t *)ptr;
00660 rb_gc_mark(tp->proc);
00661 if (tp->target_th) rb_gc_mark(tp->target_th->self);
00662 }
00663 }
00664
00665 static size_t
00666 tp_memsize(const void *ptr)
00667 {
00668 return sizeof(rb_tp_t);
00669 }
00670
00671 static const rb_data_type_t tp_data_type = {
00672 "tracepoint",
00673 {tp_mark, RUBY_TYPED_NEVER_FREE, tp_memsize,},
00674 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
00675 };
00676
00677 static VALUE
00678 tp_alloc(VALUE klass)
00679 {
00680 rb_tp_t *tp;
00681 return TypedData_Make_Struct(klass, rb_tp_t, &tp_data_type, tp);
00682 }
00683
00684 static rb_event_flag_t
00685 symbol2event_flag(VALUE v)
00686 {
00687 static ID id;
00688 VALUE sym = rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym");
00689
00690 #define C(name, NAME) CONST_ID(id, #name); if (sym == ID2SYM(id)) return RUBY_EVENT_##NAME
00691 C(line, LINE);
00692 C(class, CLASS);
00693 C(end, END);
00694 C(call, CALL);
00695 C(return, RETURN);
00696 C(c_call, C_CALL);
00697 C(c_return, C_RETURN);
00698 C(raise, RAISE);
00699 C(b_call, B_CALL);
00700 C(b_return, B_RETURN);
00701 C(thread_begin, THREAD_BEGIN);
00702 C(thread_end, THREAD_END);
00703 C(specified_line, SPECIFIED_LINE);
00704 #undef C
00705 CONST_ID(id, "a_call"); if (sym == ID2SYM(id)) return RUBY_EVENT_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_C_CALL;
00706 CONST_ID(id, "a_return"); if (sym == ID2SYM(id)) return RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_C_RETURN;
00707 rb_raise(rb_eArgError, "unknown event: %s", rb_id2name(SYM2ID(sym)));
00708 }
00709
00710 static rb_tp_t *
00711 tpptr(VALUE tpval)
00712 {
00713 rb_tp_t *tp;
00714 TypedData_Get_Struct(tpval, rb_tp_t, &tp_data_type, tp);
00715 return tp;
00716 }
00717
00718 static rb_trace_arg_t *
00719 get_trace_arg(void)
00720 {
00721 rb_trace_arg_t *trace_arg = GET_THREAD()->trace_arg;
00722 if (trace_arg == 0) {
00723 rb_raise(rb_eRuntimeError, "access from outside");
00724 }
00725 return trace_arg;
00726 }
00727
00728 struct rb_trace_arg_struct *
00729 rb_tracearg_from_tracepoint(VALUE tpval)
00730 {
00731 return get_trace_arg();
00732 }
00733
00734 rb_event_flag_t
00735 rb_tracearg_event_flag(rb_trace_arg_t *trace_arg)
00736 {
00737 return trace_arg->event;
00738 }
00739
00740 VALUE
00741 rb_tracearg_event(rb_trace_arg_t *trace_arg)
00742 {
00743 return ID2SYM(get_event_id(trace_arg->event));
00744 }
00745
00746 static void
00747 fill_path_and_lineno(rb_trace_arg_t *trace_arg)
00748 {
00749 if (trace_arg->path == Qundef) {
00750 rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(trace_arg->th, trace_arg->cfp);
00751
00752 if (cfp) {
00753 trace_arg->path = cfp->iseq->location.path;
00754 trace_arg->lineno = rb_vm_get_sourceline(cfp);
00755 }
00756 else {
00757 trace_arg->path = Qnil;
00758 trace_arg->lineno = 0;
00759 }
00760 }
00761 }
00762
00763 VALUE
00764 rb_tracearg_lineno(rb_trace_arg_t *trace_arg)
00765 {
00766 fill_path_and_lineno(trace_arg);
00767 return INT2FIX(trace_arg->lineno);
00768 }
00769 VALUE
00770 rb_tracearg_path(rb_trace_arg_t *trace_arg)
00771 {
00772 fill_path_and_lineno(trace_arg);
00773 return trace_arg->path;
00774 }
00775
00776 static void
00777 fill_id_and_klass(rb_trace_arg_t *trace_arg)
00778 {
00779 if (!trace_arg->klass_solved) {
00780 if (!trace_arg->klass) {
00781 rb_vm_control_frame_id_and_class(trace_arg->cfp, &trace_arg->id, &trace_arg->klass);
00782 }
00783
00784 if (trace_arg->klass) {
00785 if (RB_TYPE_P(trace_arg->klass, T_ICLASS)) {
00786 trace_arg->klass = RBASIC(trace_arg->klass)->klass;
00787 }
00788 }
00789 else {
00790 trace_arg->klass = Qnil;
00791 }
00792
00793 trace_arg->klass_solved = 1;
00794 }
00795 }
00796
00797 VALUE
00798 rb_tracearg_method_id(rb_trace_arg_t *trace_arg)
00799 {
00800 fill_id_and_klass(trace_arg);
00801 return trace_arg->id ? ID2SYM(trace_arg->id) : Qnil;
00802 }
00803
00804 VALUE
00805 rb_tracearg_defined_class(rb_trace_arg_t *trace_arg)
00806 {
00807 fill_id_and_klass(trace_arg);
00808 return trace_arg->klass;
00809 }
00810
00811 VALUE
00812 rb_tracearg_binding(rb_trace_arg_t *trace_arg)
00813 {
00814 rb_control_frame_t *cfp;
00815 cfp = rb_vm_get_binding_creatable_next_cfp(trace_arg->th, trace_arg->cfp);
00816
00817 if (cfp) {
00818 return rb_binding_new_with_cfp(trace_arg->th, cfp);
00819 }
00820 else {
00821 return Qnil;
00822 }
00823 }
00824
00825 VALUE
00826 rb_tracearg_self(rb_trace_arg_t *trace_arg)
00827 {
00828 return trace_arg->self;
00829 }
00830
00831 VALUE
00832 rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
00833 {
00834 if (trace_arg->event & (RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN | RUBY_EVENT_B_RETURN)) {
00835
00836 }
00837 else {
00838 rb_raise(rb_eRuntimeError, "not supported by this event");
00839 }
00840 if (trace_arg->data == Qundef) {
00841 rb_bug("tp_attr_return_value_m: unreachable");
00842 }
00843 return trace_arg->data;
00844 }
00845
00846 VALUE
00847 rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg)
00848 {
00849 if (trace_arg->event & (RUBY_EVENT_RAISE)) {
00850
00851 }
00852 else {
00853 rb_raise(rb_eRuntimeError, "not supported by this event");
00854 }
00855 if (trace_arg->data == Qundef) {
00856 rb_bug("tp_attr_raised_exception_m: unreachable");
00857 }
00858 return trace_arg->data;
00859 }
00860
00861 VALUE
00862 rb_tracearg_object(rb_trace_arg_t *trace_arg)
00863 {
00864 if (trace_arg->event & (RUBY_INTERNAL_EVENT_NEWOBJ | RUBY_INTERNAL_EVENT_FREEOBJ)) {
00865
00866 }
00867 else {
00868 rb_raise(rb_eRuntimeError, "not supported by this event");
00869 }
00870 if (trace_arg->data == Qundef) {
00871 rb_bug("tp_attr_raised_exception_m: unreachable");
00872 }
00873 return trace_arg->data;
00874 }
00875
00876
00877
00878
00879
00880
00881 static VALUE
00882 tracepoint_attr_event(VALUE tpval)
00883 {
00884 return rb_tracearg_event(get_trace_arg());
00885 }
00886
00887
00888
00889
00890 static VALUE
00891 tracepoint_attr_lineno(VALUE tpval)
00892 {
00893 return rb_tracearg_lineno(get_trace_arg());
00894 }
00895
00896
00897
00898
00899 static VALUE
00900 tracepoint_attr_path(VALUE tpval)
00901 {
00902 return rb_tracearg_path(get_trace_arg());
00903 }
00904
00905
00906
00907
00908 static VALUE
00909 tracepoint_attr_method_id(VALUE tpval)
00910 {
00911 return rb_tracearg_method_id(get_trace_arg());
00912 }
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948 static VALUE
00949 tracepoint_attr_defined_class(VALUE tpval)
00950 {
00951 return rb_tracearg_defined_class(get_trace_arg());
00952 }
00953
00954
00955
00956
00957 static VALUE
00958 tracepoint_attr_binding(VALUE tpval)
00959 {
00960 return rb_tracearg_binding(get_trace_arg());
00961 }
00962
00963
00964
00965
00966
00967
00968
00969 static VALUE
00970 tracepoint_attr_self(VALUE tpval)
00971 {
00972 return rb_tracearg_self(get_trace_arg());
00973 }
00974
00975
00976
00977
00978 static VALUE
00979 tracepoint_attr_return_value(VALUE tpval)
00980 {
00981 return rb_tracearg_return_value(get_trace_arg());
00982 }
00983
00984
00985
00986
00987 static VALUE
00988 tracepoint_attr_raised_exception(VALUE tpval)
00989 {
00990 return rb_tracearg_raised_exception(get_trace_arg());
00991 }
00992
00993 static void
00994 tp_call_trace(VALUE tpval, rb_trace_arg_t *trace_arg)
00995 {
00996 rb_tp_t *tp = tpptr(tpval);
00997
00998 if (tp->func) {
00999 (*tp->func)(tpval, tp->data);
01000 }
01001 else {
01002 rb_proc_call_with_block((VALUE)tp->proc, 1, &tpval, Qnil);
01003 }
01004 }
01005
01006 VALUE
01007 rb_tracepoint_enable(VALUE tpval)
01008 {
01009 rb_tp_t *tp;
01010
01011 tp = tpptr(tpval);
01012
01013 if (tp->target_th) {
01014 rb_thread_add_event_hook2(tp->target_th->self, (rb_event_hook_func_t)tp_call_trace, tp->events, tpval,
01015 RUBY_EVENT_HOOK_FLAG_SAFE | RUBY_EVENT_HOOK_FLAG_RAW_ARG);
01016 }
01017 else {
01018 rb_add_event_hook2((rb_event_hook_func_t)tp_call_trace, tp->events, tpval,
01019 RUBY_EVENT_HOOK_FLAG_SAFE | RUBY_EVENT_HOOK_FLAG_RAW_ARG);
01020 }
01021 tp->tracing = 1;
01022 return Qundef;
01023 }
01024
01025 VALUE
01026 rb_tracepoint_disable(VALUE tpval)
01027 {
01028 rb_tp_t *tp;
01029
01030 tp = tpptr(tpval);
01031
01032 if (tp->target_th) {
01033 rb_thread_remove_event_hook_with_data(tp->target_th->self, (rb_event_hook_func_t)tp_call_trace, tpval);
01034 }
01035 else {
01036 rb_remove_event_hook_with_data((rb_event_hook_func_t)tp_call_trace, tpval);
01037 }
01038 tp->tracing = 0;
01039 return Qundef;
01040 }
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079 static VALUE
01080 tracepoint_enable_m(VALUE tpval)
01081 {
01082 rb_tp_t *tp = tpptr(tpval);
01083 int previous_tracing = tp->tracing;
01084 rb_tracepoint_enable(tpval);
01085
01086 if (rb_block_given_p()) {
01087 return rb_ensure(rb_yield, Qnil,
01088 previous_tracing ? rb_tracepoint_enable : rb_tracepoint_disable,
01089 tpval);
01090 }
01091 else {
01092 return previous_tracing ? Qtrue : Qfalse;
01093 }
01094 }
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130 static VALUE
01131 tracepoint_disable_m(VALUE tpval)
01132 {
01133 rb_tp_t *tp = tpptr(tpval);
01134 int previous_tracing = tp->tracing;
01135 rb_tracepoint_disable(tpval);
01136
01137 if (rb_block_given_p()) {
01138 return rb_ensure(rb_yield, Qnil,
01139 previous_tracing ? rb_tracepoint_enable : rb_tracepoint_disable,
01140 tpval);
01141 }
01142 else {
01143 return previous_tracing ? Qtrue : Qfalse;
01144 }
01145 }
01146
01147
01148
01149
01150
01151
01152
01153 VALUE
01154 rb_tracepoint_enabled_p(VALUE tpval)
01155 {
01156 rb_tp_t *tp = tpptr(tpval);
01157 return tp->tracing ? Qtrue : Qfalse;
01158 }
01159
01160 static VALUE
01161 tracepoint_new(VALUE klass, rb_thread_t *target_th, rb_event_flag_t events, void (func)(VALUE, void*), void *data, VALUE proc)
01162 {
01163 VALUE tpval = tp_alloc(klass);
01164 rb_tp_t *tp;
01165 TypedData_Get_Struct(tpval, rb_tp_t, &tp_data_type, tp);
01166
01167 tp->proc = proc;
01168 tp->func = func;
01169 tp->data = data;
01170 tp->events = events;
01171 tp->self = tpval;
01172
01173 return tpval;
01174 }
01175
01176 VALUE
01177 rb_tracepoint_new(VALUE target_thval, rb_event_flag_t events, void (*func)(VALUE, void *), void *data)
01178 {
01179 rb_thread_t *target_th = 0;
01180 if (RTEST(target_thval)) {
01181 GetThreadPtr(target_thval, target_th);
01182
01183
01184
01185 }
01186 return tracepoint_new(rb_cTracePoint, target_th, events, func, data, Qundef);
01187 }
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236 static VALUE
01237 tracepoint_new_s(int argc, VALUE *argv, VALUE self)
01238 {
01239 rb_event_flag_t events = 0;
01240 int i;
01241
01242 if (argc > 0) {
01243 for (i=0; i<argc; i++) {
01244 events |= symbol2event_flag(argv[i]);
01245 }
01246 }
01247 else {
01248 events = RUBY_EVENT_TRACEPOINT_ALL;
01249 }
01250
01251 if (!rb_block_given_p()) {
01252 rb_raise(rb_eThreadError, "must be called with a block");
01253 }
01254
01255 return tracepoint_new(self, 0, events, 0, 0, rb_block_proc());
01256 }
01257
01258 static VALUE
01259 tracepoint_trace_s(int argc, VALUE *argv, VALUE self)
01260 {
01261 VALUE trace = tracepoint_new_s(argc, argv, self);
01262 rb_tracepoint_enable(trace);
01263 return trace;
01264 }
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274 static VALUE
01275 tracepoint_inspect(VALUE self)
01276 {
01277 rb_tp_t *tp = tpptr(self);
01278 rb_trace_arg_t *trace_arg = GET_THREAD()->trace_arg;
01279
01280 if (trace_arg) {
01281 switch (trace_arg->event) {
01282 case RUBY_EVENT_LINE:
01283 case RUBY_EVENT_SPECIFIED_LINE:
01284 {
01285 VALUE sym = rb_tracearg_method_id(trace_arg);
01286 if (NIL_P(sym))
01287 goto default_inspect;
01288 return rb_sprintf("#<TracePoint:%"PRIsVALUE"@%"PRIsVALUE":%d in `%"PRIsVALUE"'>",
01289 rb_tracearg_event(trace_arg),
01290 rb_tracearg_path(trace_arg),
01291 FIX2INT(rb_tracearg_lineno(trace_arg)),
01292 sym);
01293 }
01294 case RUBY_EVENT_CALL:
01295 case RUBY_EVENT_C_CALL:
01296 case RUBY_EVENT_RETURN:
01297 case RUBY_EVENT_C_RETURN:
01298 return rb_sprintf("#<TracePoint:%"PRIsVALUE" `%"PRIsVALUE"'@%"PRIsVALUE":%d>",
01299 rb_tracearg_event(trace_arg),
01300 rb_tracearg_method_id(trace_arg),
01301 rb_tracearg_path(trace_arg),
01302 FIX2INT(rb_tracearg_lineno(trace_arg)));
01303 case RUBY_EVENT_THREAD_BEGIN:
01304 case RUBY_EVENT_THREAD_END:
01305 return rb_sprintf("#<TracePoint:%"PRIsVALUE" %"PRIsVALUE">",
01306 rb_tracearg_event(trace_arg),
01307 rb_tracearg_self(trace_arg));
01308 default:
01309 default_inspect:
01310 return rb_sprintf("#<TracePoint:%"PRIsVALUE"@%"PRIsVALUE":%d>",
01311 rb_tracearg_event(trace_arg),
01312 rb_tracearg_path(trace_arg),
01313 FIX2INT(rb_tracearg_lineno(trace_arg)));
01314 }
01315 }
01316 else {
01317 return rb_sprintf("#<TracePoint:%s>", tp->tracing ? "enabled" : "disabled");
01318 }
01319 }
01320
01321 static void Init_postponed_job(void);
01322
01323
01324 void
01325 Init_vm_trace(void)
01326 {
01327
01328 rb_define_global_function("set_trace_func", set_trace_func, 1);
01329 rb_define_method(rb_cThread, "set_trace_func", thread_set_trace_func_m, 1);
01330 rb_define_method(rb_cThread, "add_trace_func", thread_add_trace_func_m, 1);
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378 rb_cTracePoint = rb_define_class("TracePoint", rb_cObject);
01379 rb_undef_alloc_func(rb_cTracePoint);
01380 rb_undef_method(CLASS_OF(rb_cTracePoint), "new");
01381 rb_define_singleton_method(rb_cTracePoint, "new", tracepoint_new_s, -1);
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396 rb_define_singleton_method(rb_cTracePoint, "trace", tracepoint_trace_s, -1);
01397
01398 rb_define_method(rb_cTracePoint, "enable", tracepoint_enable_m, 0);
01399 rb_define_method(rb_cTracePoint, "disable", tracepoint_disable_m, 0);
01400 rb_define_method(rb_cTracePoint, "enabled?", rb_tracepoint_enabled_p, 0);
01401
01402 rb_define_method(rb_cTracePoint, "inspect", tracepoint_inspect, 0);
01403
01404 rb_define_method(rb_cTracePoint, "event", tracepoint_attr_event, 0);
01405 rb_define_method(rb_cTracePoint, "lineno", tracepoint_attr_lineno, 0);
01406 rb_define_method(rb_cTracePoint, "path", tracepoint_attr_path, 0);
01407 rb_define_method(rb_cTracePoint, "method_id", tracepoint_attr_method_id, 0);
01408 rb_define_method(rb_cTracePoint, "defined_class", tracepoint_attr_defined_class, 0);
01409 rb_define_method(rb_cTracePoint, "binding", tracepoint_attr_binding, 0);
01410 rb_define_method(rb_cTracePoint, "self", tracepoint_attr_self, 0);
01411 rb_define_method(rb_cTracePoint, "return_value", tracepoint_attr_return_value, 0);
01412 rb_define_method(rb_cTracePoint, "raised_exception", tracepoint_attr_raised_exception, 0);
01413
01414
01415
01416 Init_postponed_job();
01417 }
01418
01419 typedef struct rb_postponed_job_struct {
01420 unsigned long flags;
01421 struct rb_thread_struct *th;
01422 rb_postponed_job_func_t func;
01423 void *data;
01424 } rb_postponed_job_t;
01425
01426 #define MAX_POSTPONED_JOB 1000
01427 #define MAX_POSTPONED_JOB_SPECIAL_ADDITION 24
01428
01429 static void
01430 Init_postponed_job(void)
01431 {
01432 rb_vm_t *vm = GET_VM();
01433 vm->postponed_job_buffer = ALLOC_N(rb_postponed_job_t, MAX_POSTPONED_JOB);
01434 vm->postponed_job_index = 0;
01435 }
01436
01437 enum postponed_job_register_result {
01438 PJRR_SUCESS = 0,
01439 PJRR_FULL = 1,
01440 PJRR_INTERRUPTED = 2
01441 };
01442
01443 static enum postponed_job_register_result
01444 postponed_job_register(rb_thread_t *th, rb_vm_t *vm,
01445 unsigned int flags, rb_postponed_job_func_t func, void *data, int max, int expected_index)
01446 {
01447 rb_postponed_job_t *pjob;
01448
01449 if (expected_index >= max) return PJRR_FULL;
01450
01451 if (ATOMIC_CAS(vm->postponed_job_index, expected_index, expected_index+1) == expected_index) {
01452 pjob = &vm->postponed_job_buffer[expected_index];
01453 }
01454 else {
01455 return PJRR_INTERRUPTED;
01456 }
01457
01458 pjob->flags = flags;
01459 pjob->th = th;
01460 pjob->func = func;
01461 pjob->data = data;
01462
01463 RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(th);
01464
01465 return PJRR_SUCESS;
01466 }
01467
01468
01469
01470 int
01471 rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data)
01472 {
01473 rb_thread_t *th = GET_THREAD();
01474 rb_vm_t *vm = th->vm;
01475
01476 begin:
01477 switch (postponed_job_register(th, vm, flags, func, data, MAX_POSTPONED_JOB, vm->postponed_job_index)) {
01478 case PJRR_SUCESS : return 1;
01479 case PJRR_FULL : return 0;
01480 case PJRR_INTERRUPTED: goto begin;
01481 default: rb_bug("unreachable\n");
01482 }
01483 }
01484
01485
01486 int
01487 rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data)
01488 {
01489 rb_thread_t *th = GET_THREAD();
01490 rb_vm_t *vm = th->vm;
01491 rb_postponed_job_t *pjob;
01492 int i, index;
01493
01494 begin:
01495 index = vm->postponed_job_index;
01496 for (i=0; i<index; i++) {
01497 pjob = &vm->postponed_job_buffer[i];
01498 if (pjob->func == func) {
01499 RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(th);
01500 return 2;
01501 }
01502 }
01503 switch (postponed_job_register(th, vm, flags, func, data, MAX_POSTPONED_JOB + MAX_POSTPONED_JOB_SPECIAL_ADDITION, index)) {
01504 case PJRR_SUCESS : return 1;
01505 case PJRR_FULL : return 0;
01506 case PJRR_INTERRUPTED: goto begin;
01507 default: rb_bug("unreachable\n");
01508 }
01509 }
01510
01511 void
01512 rb_postponed_job_flush(rb_vm_t *vm)
01513 {
01514 rb_thread_t *th = GET_THREAD();
01515 unsigned long saved_postponed_job_interrupt_mask = th->interrupt_mask & POSTPONED_JOB_INTERRUPT_MASK;
01516 VALUE saved_errno = th->errinfo;
01517
01518 th->errinfo = Qnil;
01519
01520 th->interrupt_mask |= POSTPONED_JOB_INTERRUPT_MASK;
01521 {
01522 TH_PUSH_TAG(th);
01523 EXEC_TAG();
01524 {
01525 int index;
01526 while ((index = vm->postponed_job_index) > 0) {
01527 if (ATOMIC_CAS(vm->postponed_job_index, index, index-1) == index) {
01528 rb_postponed_job_t *pjob = &vm->postponed_job_buffer[index-1];
01529 (*pjob->func)(pjob->data);
01530 }
01531 }
01532 }
01533 TH_POP_TAG();
01534 }
01535
01536 th->interrupt_mask &= ~(saved_postponed_job_interrupt_mask ^ POSTPONED_JOB_INTERRUPT_MASK);
01537 th->errinfo = saved_errno;
01538 }
01539