diff --git a/ChangeLog b/ChangeLog index 3e34db44fe..265f85a164 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Sat Oct 14 03:32:13 2000 Yukihiro Matsumoto + + * eval.c (rb_thread_alloc): should not link a new thread in the + live thread ring before initialization. + Fri Oct 13 17:08:09 2000 Shugo Maeda * lib/net/imap.rb: new file. diff --git a/eval.c b/eval.c index 5b6dd3cbb6..b56b8bd768 100644 --- a/eval.c +++ b/eval.c @@ -664,7 +664,6 @@ dvar_asgn_internal(id, value, curr) struct RVarmap *vars = ruby_dyna_vars; while (vars) { - if (TYPE(vars) != T_VARMAP) abort(); if (curr && vars->id == 0) { n++; if (n == 2) break; @@ -729,6 +728,7 @@ struct tag { struct SCOPE *scope; int dst; struct tag *prev; + int line; }; static struct tag *prot_tag; @@ -742,6 +742,7 @@ static struct tag *prot_tag; _tag.scope = ruby_scope; \ _tag.tag = ptag; \ _tag.dst = 0; \ + _tag.line = __LINE__; \ prot_tag = &_tag; #define PROT_NONE 0 @@ -798,6 +799,7 @@ static VALUE ruby_wrapper; /* security wrapper */ typedef struct thread * rb_thread_t; static rb_thread_t curr_thread = 0; +static rb_thread_t main_thread; static void scope_dup _((struct SCOPE *)); #define POP_SCOPE() \ @@ -868,8 +870,8 @@ set_backtrace(info, bt) static void error_print() { - VALUE errat = Qnil; - VALUE eclass; + VALUE errat = Qnil; /* OK */ + volatile VALUE eclass; char *einfo; int elen; @@ -3274,9 +3276,10 @@ rb_longjmp(tag, mesg) if (RTEST(ruby_debug) && !NIL_P(ruby_errinfo) && !rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) { - fprintf(stderr, "Exception `%s' at %s:%d\n", + fprintf(stderr, "Exception `%s' at %s:%d - %s\n", rb_class2name(CLASS_OF(ruby_errinfo)), - ruby_sourcefile, ruby_sourceline); + ruby_sourcefile, ruby_sourceline, + STR2CSTR(ruby_errinfo)); } rb_trap_restore_mask(); @@ -4837,7 +4840,7 @@ yield_under_i(self) POP_TAG(); ruby_block = old_block; if (state) JUMP_TAG(state); - + return result; } /* static block, no need to restore */ @@ -4930,7 +4933,7 @@ rb_load(fname, wrap) char *file; volatile ID last_func; volatile VALUE wrapper = 0; - VALUE self = ruby_top_self; + volatile VALUE self = ruby_top_self; TMP_PROTECT; if (wrap) { @@ -6146,7 +6149,7 @@ block_pass(self, node) VALUE self; NODE *node; { - VALUE block = rb_eval(self, node->nd_body); + VALUE block = rb_eval(self, node->nd_body); /* OK */ struct BLOCK * volatile old_block; struct BLOCK _block; struct BLOCK *data; @@ -6623,9 +6626,6 @@ struct thread { #define THREAD_RAISED 0x200 -static rb_thread_t main_thread; -/*static rb_thread_t curr_thread = 0;*/ - #define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next; #define END_FOREACH_FROM(f,x) } while (x != f) @@ -6754,7 +6754,6 @@ rb_thread_save_context(th) rb_thread_t th; { VALUE *pos; - int len; len = stack_length(&pos); @@ -7005,7 +7004,6 @@ find_bad_fds(dst, src, max) fd_set *dst, *src; int max; { - struct stat s; int i, test = Qfalse; for (i=0; i<=max; i++) { @@ -7300,7 +7298,6 @@ rb_thread_select(max, read, write, except, timeout) struct timeval *timeout; { double limit; - struct timeval zero; int n; if (!read && !write && !except) { @@ -7642,6 +7639,9 @@ rb_thread_abort_exc_set(thread, val) #define THREAD_ALLOC(th) do {\ th = ALLOC(struct thread);\ +\ + th->next = 0;\ + th->prev = 0;\ \ th->status = THREAD_RUNNABLE;\ th->result = 0;\ @@ -7696,7 +7696,6 @@ rb_thread_alloc(klass) } else { curr_thread = th->prev = th->next = th; - th->status = THREAD_RUNNABLE; } for (vars = th->dyna_vars; vars; vars = vars->next) { @@ -7758,11 +7757,12 @@ rb_thread_stop_timer() #endif static VALUE -rb_thread_start_0(fn, arg, th) +rb_thread_start_0(fn, arg, th_arg) VALUE (*fn)(); void *arg; - rb_thread_t th; + rb_thread_t th_arg; { + volatile rb_thread_t th = th_arg; volatile VALUE thread = th->thread; enum thread_status status; int state; @@ -7791,7 +7791,7 @@ rb_thread_start_0(fn, arg, th) PUSH_TAG(PROT_THREAD); if ((state = EXEC_TAG()) == 0) { - if (THREAD_SAVE_CONTEXT(th) == 0) { + if ((status = THREAD_SAVE_CONTEXT(th)) == 0) { curr_thread = th; th->result = (*fn)(arg, th); } @@ -7833,7 +7833,8 @@ rb_thread_create(fn, arg) VALUE (*fn)(); void *arg; { - return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread)); + rb_thread_t th = rb_thread_alloc(rb_cThread); + return rb_thread_start_0(fn, arg, th); } int @@ -7864,7 +7865,7 @@ rb_thread_s_new(argc, argv, klass) pos = th->stk_pos; rb_obj_call_init(th->thread, argc, argv); if (th->stk_pos == pos) { - rb_raise(rb_eThreadError, "uninitialized thread - check `initialize' of %s", + rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'", rb_class2name(klass)); } @@ -7875,20 +7876,27 @@ static VALUE rb_thread_initialize(thread, args) VALUE thread, args; { + rb_thread_t th; + + th = rb_thread_check(thread); if (!rb_block_given_p()) { + rb_thread_remove(th); rb_raise(rb_eThreadError, "must be called with a block"); } - return rb_thread_start_0(rb_thread_yield, args, rb_thread_check(thread)); + return rb_thread_start_0(rb_thread_yield, args, th); } static VALUE rb_thread_start(klass, args) VALUE klass, args; { + rb_thread_t th; + VALUE t; + if (!rb_block_given_p()) { rb_raise(rb_eThreadError, "must be called with a block"); } - return rb_thread_start_0(rb_thread_yield, args, rb_thread_alloc(klass)); + return rb_thread_start_0(rb_thread_yield, args, rb_thread_alloc(rb_cThread)); } static VALUE @@ -8092,6 +8100,7 @@ rb_thread_raise_m(argc, argv, thread) rb_secure(4); } rb_thread_raise(argc, argv, th); + return Qnil; /* not reached */ } VALUE @@ -8170,7 +8179,7 @@ rb_thread_inspect(thread) { char *cname = rb_class2name(CLASS_OF(thread)); rb_thread_t th = rb_thread_check(thread); - char *s, *status; + char *status; VALUE str; switch (th->status) { @@ -8205,8 +8214,8 @@ rb_callcc(self) struct RVarmap *vars; THREAD_ALLOC(th); - cont = Data_Wrap_Struct(rb_cCont, thread_mark, - thread_free, th); + th->status = THREAD_RUNNABLE; + cont = Data_Wrap_Struct(rb_cCont, thread_mark, thread_free, th); scope_dup(ruby_scope); for (tag=prot_tag; tag; tag=tag->prev) { @@ -8478,4 +8487,3 @@ return_check() tt = tt->prev; } } - diff --git a/lib/debug.rb b/lib/debug.rb index 97be752797..04e6c730c7 100644 --- a/lib/debug.rb +++ b/lib/debug.rb @@ -5,15 +5,16 @@ if $SAFE > 0 STDERR.print "-r debug.rb is not available in safe mode\n" exit 1 end -SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__ require 'tracer' + class Tracer def Tracer.trace_func(*vars) Single.trace_func(*vars) end end +SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__ class DEBUGGER__ class Mutex @@ -89,6 +90,7 @@ class DEBUGGER__ @frames = [] @finish_pos = 0 @trace = false + @catch = "StandardError" end def stop_next(n=1) @@ -130,16 +132,8 @@ class DEBUGGER__ def var_list(ary, binding) ary.sort! - if false # ary.size < 0 - f = open("|less", "w") - for v in ary - f.printf " %s => %s\n", v, eval(v, binding).inspect - end - f.close - else - for v in ary - stdout.printf " %s => %s\n", v, eval(v, binding).inspect - end + for v in ary + stdout.printf " %s => %s\n", v, eval(v, binding).inspect end end @@ -158,7 +152,7 @@ class DEBUGGER__ when /^\s*c(?:onst(?:ant)?)?\s+/ obj = debug_eval($', binding) unless obj.kind_of? Module - stdout.print "should be Class/Module: ", $', "\n" + stdout.print "Should be Class/Module: ", $', "\n" else var_list(obj.constants, obj.module_eval{binding()}) end @@ -184,7 +178,7 @@ class DEBUGGER__ else obj = debug_eval(input, binding) unless obj.kind_of? Module - stdout.print "should be Class/Module: ", input, "\n" + stdout.print "Should be Class/Module: ", input, "\n" else len = 0 for v in obj.instance_methods.sort @@ -235,12 +229,12 @@ class DEBUGGER__ case input when /^\s*tr(?:ace)?(?:\s+(on|off))?$/ - if !defined?( $1 ) - @trace = !@trace - elsif $1 == 'on' - @trace = true - else - @trace = false + if defined?( $1 ) + if $1 == 'on' + @trace = true + else + @trace = false + end end if @trace stdout.print "Trace on\n" @@ -271,7 +265,7 @@ class DEBUGGER__ when /^\s*b(?:reak)?$/ if break_points.find{|b| b[1] == 0} n = 1 - stdout.print "breakpoints:\n" + stdout.print "Breakpoints:\n" for b in break_points if b[0] and b[1] == 0 stdout.printf " %d %s:%s\n", n, b[2], b[3] @@ -282,7 +276,7 @@ class DEBUGGER__ if break_points.find{|b| b[1] == 1} n = 1 stdout.print "\n" - stdout.print "watchpoints:\n" + stdout.print "Watchpoints:\n" for b in break_points if b[0] and b[1] == 1 stdout.printf " %d %s\n", n, b[2] @@ -291,7 +285,7 @@ class DEBUGGER__ end end if break_points.size == 0 - stdout.print "no breakpoints\n" + stdout.print "No breakpoints\n" else stdout.print "\n" end @@ -299,7 +293,7 @@ class DEBUGGER__ when /^\s*del(?:ete)?(?:\s+(\d+))?$/ pos = $1 unless pos - input = readline("clear all breakpoints? (y/n) ", false) + input = readline("Clear all breakpoints? (y/n) ", false) if input == "y" for b in break_points b[0] = false @@ -326,7 +320,7 @@ class DEBUGGER__ when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/ pos = $1 unless pos - input = readline("clear all expressions? (y/n) ", false) + input = readline("Clear all expressions? (y/n) ", false) if input == "y" for d in display d[0] = false @@ -337,7 +331,7 @@ class DEBUGGER__ if display[pos-1] display[pos-1][0] = false else - stdout.printf "display expression %d is not defined\n", pos + stdout.printf "Display expression %d is not defined\n", pos end end @@ -397,7 +391,7 @@ class DEBUGGER__ frame_pos += lev if frame_pos >= @frames.size frame_pos = @frames.size - 1 - stdout.print "at toplevel\n" + stdout.print "At toplevel\n" end binding, binding_file, binding_line = @frames[frame_pos] stdout.printf "#%d %s:%s\n", frame_pos, binding_file, binding_line @@ -412,7 +406,7 @@ class DEBUGGER__ frame_pos -= lev if frame_pos < 0 frame_pos = 0 - stdout.print "at stack bottom\n" + stdout.print "At stack bottom\n" end binding, binding_file, binding_line = @frames[frame_pos] stdout.printf "#%d %s:%s\n", frame_pos, binding_file, binding_line @@ -422,11 +416,29 @@ class DEBUGGER__ stdout.print "\"finish\" not meaningful in the outermost frame.\n" else @finish_pos = @frames.size - frame_pos - p @finish_pos frame_pos = 0 + MUTEX.unlock return end + when /^\s*cat(?:ch)?(?:\s+(.+))?$/ + if $1 + excn = $1 + if excn == 'off' + @catch = nil + stdout.print "Clear catchpoint.\n" + else + @catch = excn + stdout.printf "Set catchpoint %s.\n", @catch + end + else + if @catch + stdout.printf "Catchpoint %s.\n", @catch + else + stdout.print "No catchpoint.\n" + end + end + when /^\s*q(?:uit)?$/ input = readline("really quit? (y/n) ", false) exit if input == "y" @@ -444,27 +456,29 @@ class DEBUGGER__ end when /^\s*p\s+/ - p debug_eval($', binding) + stdout.printf "%s\n", debug_eval($', binding) - when /^\s*h(?:elp)?/ + when /^\s*h(?:elp)?$/ debug_print_help() else v = debug_eval(input, binding) - p v unless (v == nil) + stdout.printf "%s\n", v unless (v == nil) end end end end def debug_print_help - print < set breakpoint to some position wat[ch] set watchpoint to some expression + cat[ch] set catchpoint to an exception b[reak] list breakpoints + cat[ch] show catchpoint del[ele][ nnn] delete some or all breakpoints disp[lay] add expression into display expression list undisp[lay][ nnn] delete one particular or all display expressions @@ -549,7 +563,7 @@ EOHELP end end else - stdout.printf "no sourcefile available for %s\n", file + stdout.printf "No sourcefile available for %s\n", file end end @@ -580,11 +594,11 @@ EOHELP for b in break_points if b[0] if b[1] == 0 and b[2] == file and b[3] == pos - stdout.printf "breakpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos + stdout.printf "Breakpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos return true elsif b[1] == 1 if debug_silent_eval(b[2], binding) - stdout.printf "watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos + stdout.printf "Watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos return true end end @@ -596,22 +610,25 @@ EOHELP end def excn_handle(file, line, id, binding) - p $! + stdout.printf "Exception `%s': %s\n", $!.type, $! if $!.type <= SystemExit set_trace_func nil exit end + MUTEX.lock fs = @frames.size tb = caller(0)[-fs..-1] - - stdout.printf "%s\n", $! if tb for i in tb stdout.printf "\tfrom %s\n", i end end - debug_command(file, line, id, binding) + if @catch and ($!.type.ancestors.find { |e| e.to_s == @catch }) + debug_command(file, line, id, binding) + else + MUTEX.unlock + end end def trace_func(event, file, line, id, binding, klass) @@ -781,8 +798,8 @@ EOHELP end end - @stdout.printf "Debug.rb\n" - @stdout.printf "Emacs support available.\n\n" + stdout.printf "Debug.rb\n" + stdout.printf "Emacs support available.\n\n" set_trace_func proc{|event, file, line, id, binding,klass,*rest| DEBUGGER__.context.trace_func event, file, line, id, binding,klass } diff --git a/lib/timeout.rb b/lib/timeout.rb index 4e6f546e0c..dd7cb306cf 100644 --- a/lib/timeout.rb +++ b/lib/timeout.rb @@ -39,6 +39,12 @@ def timeout(sec) yield sec return true ensure - Thread.kill y if y.alive? + Thread.kill y if y and y.alive? end end + +if __FILE__ == $0 + timeout(5) { + p 10 + } +end