From f1fdbf080efdf954a4773baf2dd088eddb7c03ef Mon Sep 17 00:00:00 2001 From: matz Date: Wed, 21 Nov 2001 15:42:12 +0000 Subject: * parse.y (str_extend): should check nesting parentheses in #{}. * process.c (pst_wstopsig): returns nil unless WIFSTOPPED() is non-zero. * process.c (pst_wtermsig): returns nil unless WIFSIGNALED() is non-zero. * process.c (pst_wexitstatus): returns nil unless WIFEXITED() is non-zero. * eval.c (rb_thread_select): tv_sec and tv_usec should not be negative. * signal.c (posix_signal): do not set SA_RESTART for SIGVTALRM. * parse.y (call_args2): block_arg may follow the first argument in call_args2. * eval.c (stack_check): should avoid stack length check during raising SystemStackError exception. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1852 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 32 +++++++++++++++ eval.c | 26 ++++++++++++- ext/pty/extconf.rb | 3 ++ ext/pty/pty.c | 111 ++++++++++++++++++++++++++++++++++++++++------------- gc.c | 10 +---- intern.h | 2 +- lib/delegate.rb | 2 +- parse.y | 32 ++++++++------- process.c | 12 ++++-- signal.c | 7 +++- 10 files changed, 181 insertions(+), 56 deletions(-) diff --git a/ChangeLog b/ChangeLog index b725462f13..1643c6eccb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,40 @@ +Thu Nov 22 00:28:13 2001 Yukihiro Matsumoto + + * parse.y (str_extend): should check nesting parentheses in #{}. + Wed Nov 21 12:22:52 2001 Shugo Maeda * lib/cgi.rb: CGI#header: do not set Apache.request.status for Location: if Apache.request.status is already set. +Wed Nov 21 02:24:18 2001 Yukihiro Matsumoto + + * process.c (pst_wstopsig): returns nil unless WIFSTOPPED() is + non-zero. + + * process.c (pst_wtermsig): returns nil unless WIFSIGNALED() is + non-zero. + + * process.c (pst_wexitstatus): returns nil unless WIFEXITED() is + non-zero. + +Wed Nov 21 00:17:54 2001 Ville Mattila + + * eval.c (rb_thread_select): tv_sec and tv_usec should not be + negative. + + * signal.c (posix_signal): do not set SA_RESTART for SIGVTALRM. + +Tue Nov 20 21:09:22 2001 Guy Decoux + + * parse.y (call_args2): block_arg may follow the first argument in + call_args2. + +Tue Nov 20 02:01:15 2001 Yukihiro Matsumoto + + * eval.c (stack_check): should avoid stack length check during + raising SystemStackError exception. + Tue Nov 20 01:07:13 2001 Yukihiro Matsumoto * parse.y (str_extend): should not terminate string interpolation diff --git a/eval.c b/eval.c index d1b8322495..e54cf21da5 100644 --- a/eval.c +++ b/eval.c @@ -496,6 +496,7 @@ extern NODE *ruby_eval_tree; extern int ruby_nerrs; static VALUE rb_eLocalJumpError; +static VALUE rb_eSysStackError; extern VALUE ruby_top_self; @@ -4135,6 +4136,24 @@ rb_with_disable_interrupt(proc, data) return result; } +static void +stack_check() +{ + static int overflowing = 0; + + if (!overflowing && ruby_stack_check()) { + int state; + overflowing = 1; + PUSH_TAG(PROT_NONE); + if ((state = EXEC_TAG()) == 0) { + rb_raise(rb_eSysStackError, "stack level too deep"); + } + POP_TAG(); + overflowing = 0; + JUMP_TAG(state); + } +} + static int last_call_status; #define CSTAT_PRIV 1 @@ -4159,7 +4178,7 @@ rb_f_missing(argc, argv, obj) rb_raise(rb_eArgError, "no id given"); } - ruby_stack_check(); + stack_check(); id = SYM2ID(argv[0]); @@ -4365,7 +4384,7 @@ rb_call0(klass, recv, id, argc, argv, body, nosuper) if ((++tick & 0xff) == 0) { CHECK_INTS; /* better than nothing */ - ruby_stack_check(); + stack_check(); } PUSH_ITER(itr); PUSH_FRAME(); @@ -6956,6 +6975,7 @@ void Init_Proc() { rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError); + rb_eSysStackError = rb_define_class("SystemStackError", rb_eStandardError); rb_cProc = rb_define_class("Proc", rb_cObject); rb_undef_method(CLASS_OF(rb_cProc), "allocate"); @@ -7881,6 +7901,8 @@ rb_thread_select(max, read, write, except, timeout) tv.tv_sec = (unsigned int)d; tv.tv_usec = (long)((d-(double)tv.tv_sec)*1e6); + if (tv.tv_sec < 0) tv.tv_sec = 0; + if (tv.tv_usec < 0) tv.tv_usec = 0; } continue; default: diff --git a/ext/pty/extconf.rb b/ext/pty/extconf.rb index ba2b44c70b..51a4bc7cd3 100644 --- a/ext/pty/extconf.rb +++ b/ext/pty/extconf.rb @@ -4,6 +4,9 @@ if /mswin32|mingw/ !~ RUBY_PLATFORM have_header("sys/stropts.h") have_func("setresuid") $CFLAGS << "-DHAVE_DEV_PTMX" if /cygwin/ === RUBY_PLATFORM + have_header("libutil.h") + have_header("pty.h") + have_library("util", "openpty") if have_func("openpty") or have_func("_getpty") or have_func("ioctl") diff --git a/ext/pty/pty.c b/ext/pty/pty.c index c3a3a6fa15..1760ebf598 100644 --- a/ext/pty/pty.c +++ b/ext/pty/pty.c @@ -9,6 +9,12 @@ #if !defined(HAVE_OPENPTY) && !defined(HAVE__GETPTY) #include #endif +#ifdef HAVE_LIBUTIL_H +#include +#endif +#ifdef HAVE_PTY_H +#include +#endif #ifdef HAVE_SYS_WAIT_H #include #else @@ -88,6 +94,8 @@ char *MasterDevice = "/dev/pty%s", "q8","q9","qa","qb","qc","qd","qe","qf", "r0","r1","r2","r3","r4","r5","r6","r7", "r8","r9","ra","rb","rc","rd","re","rf", + "s0","s1","s2","s3","s4","s5","s6","s7", + "s8","s9","sa","sb","sc","sd","se","sf", 0, }; #endif /* _IBMESA */ @@ -110,56 +118,75 @@ extern int errno; # endif /* HAVE_SETREUID */ #endif /* NO_SETEUID */ +static VALUE eChildExited; + +static VALUE +echild_status(self) + VALUE self; +{ + return rb_ivar_get(self, rb_intern("status")); +} + struct pty_info { int fd; pid_t child_pid; VALUE thread; }; -static void -pty_raise(thread, cpid, stop) - VALUE thread; - int cpid; - int stop; -{ - char buf[1024]; - - snprintf(buf, sizeof(buf), "pty - %s: %d", stop ? "stopped" : "changed", cpid); - rb_funcall(thread, rb_intern("raise"), 1, rb_str_new2(buf)); -} - static VALUE pty_syswait(info) struct pty_info *info; { + extern VALUE rb_last_status; int cpid, status; + char buf[1024]; + VALUE exc, st; + char *state = "changed"; cpid = rb_waitpid(info->child_pid, &status, WUNTRACED); - printf("cpid: %d (%d)\n", cpid, status); + st = rb_last_status; if (cpid == 0 || cpid == -1) return Qnil; #ifdef IF_STOPPED if (IF_STOPPED(status)) { /* suspend */ - pty_raise(info->thread, cpid, Qtrue); + state = "stopped"; } #else #ifdef WIFSTOPPED if (WIFSTOPPED(status)) { /* suspend */ - pty_raise(info->thread, cpid, Qtrue); + state = "stopped"; } #else ---->> Either IF_STOPPED or WIFSTOPPED is needed <<---- #endif /* WIFSTOPPED */ #endif /* IF_STOPPED */ + if (WIFEXITED(status)) { + state = "exit"; + } - pty_raise(info->thread, cpid, Qfalse); + snprintf(buf, sizeof(buf), "pty - %s: %d", state, cpid); + exc = rb_exc_new2(eChildExited, buf); + rb_iv_set(exc, "status", st); + rb_funcall(info->thread, rb_intern("raise"), 1, exc); return Qnil; } static void getDevice _((int*, int*)); +struct exec_info { + int argc; + VALUE *argv; +}; + +static VALUE +pty_exec(arg) + struct exec_info *arg; +{ + return rb_f_exec(arg->argc, arg->argv); +} + static void establishShell(argc, argv, info) int argc; @@ -169,7 +196,9 @@ establishShell(argc, argv, info) static int i,master,slave,currentPid; char *p,*getenv(); struct passwd *pwent; - VALUE v; + VALUE v; + struct exec_info arg; + int status; if (argc == 0) { char *shellname; @@ -190,14 +219,13 @@ establishShell(argc, argv, info) } getDevice(&master,&slave); + info->thread = rb_thread_current(); currentPid = getpid(); if((i = fork()) < 0) { rb_sys_fail("fork failed"); } if(i == 0) { /* child */ - /* int argc; - char *argv[1024]; */ currentPid = getpid(); /* @@ -248,7 +276,9 @@ establishShell(argc, argv, info) seteuid(getuid()); #endif - rb_f_exec(argc, argv); + arg.argc = argc; + arg.argv = argv; + rb_protect(pty_exec, (VALUE)&arg, &status); sleep(1); _exit(1); } @@ -259,6 +289,28 @@ establishShell(argc, argv, info) info->fd = master; } +static VALUE +pty_kill_child(info) + struct pty_info *info; +{ + if (rb_funcall(info->thread, rb_intern("alive?"), 0, 0) == Qtrue && + kill(info->child_pid, 0) == 0) { + rb_thread_schedule(); + if (kill(info->child_pid, SIGTERM) == 0) { + rb_thread_schedule(); + if (kill(info->child_pid, 0) == 0) { + kill(info->child_pid, SIGINT); + rb_thread_schedule(); + if (kill(info->child_pid, 0) == 0) + kill(info->child_pid, SIGKILL); + } + } + } + rb_funcall(info->thread, rb_intern("join"), 0, 0); + return Qnil; +} + + #ifdef HAVE_OPENPTY /* * Use openpty(3) of 4.3BSD Reno and later, @@ -346,7 +398,7 @@ getDevice(master,slave) close(i); } } - rb_raise(rb_eRuntimeError, "Cannot get %s\n", SlaveDevice); + rb_raise(rb_eRuntimeError, "Cannot get %s", SlaveName); #endif } #endif /* HAVE__GETPTY */ @@ -367,7 +419,7 @@ pty_getpty(argc, argv, self) VALUE self; { VALUE res, th; - struct pty_info info; + struct pty_info info, thinfo; OpenFile *wfptr,*rfptr; VALUE rport = rb_obj_alloc(rb_cFile); VALUE wport = rb_obj_alloc(rb_cFile); @@ -379,22 +431,24 @@ pty_getpty(argc, argv, self) rfptr->mode = rb_io_mode_flags("r"); rfptr->f = fdopen(info.fd, "r"); - rfptr->path = 0; /*strdup(RSTRING(command)->ptr); */ + rfptr->path = strdup(SlaveName); wfptr->mode = rb_io_mode_flags("w"); wfptr->f = fdopen(dup(info.fd), "w"); - wfptr->path = 0; /* strdup(RSTRING(command)->ptr); */ + wfptr->path = strdup(SlaveName); res = rb_ary_new2(3); rb_ary_store(res,0,(VALUE)rport); rb_ary_store(res,1,(VALUE)wport); rb_ary_store(res,2,INT2FIX(info.child_pid)); - info.thread = rb_thread_current(); th = rb_thread_create(pty_syswait, (void*)&info); + thinfo.thread = th; + thinfo.child_pid = info.child_pid; + if (rb_block_given_p()) { - res = rb_yield((VALUE)res); - rb_funcall(th, rb_intern("kill"), 0, 0); + rb_ensure(rb_yield, res, pty_kill_child, (VALUE)&thinfo); + return Qnil; } return res; } @@ -428,4 +482,7 @@ Init_pty() rb_define_module_function(cPTY,"spawn",pty_getpty,-1); rb_define_module_function(cPTY,"protect_signal",pty_protect,0); rb_define_module_function(cPTY,"reset_signal",pty_reset_signal,0); + + eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError); + rb_define_method(eChildExited,"status",echild_status,0); } diff --git a/gc.c b/gc.c index effb38eccd..2ff8c303ca 100644 --- a/gc.c +++ b/gc.c @@ -404,17 +404,13 @@ ruby_stack_length(p) return STACK_LENGTH; } -static VALUE rb_eSysStackError; - -void +int ruby_stack_check() { int ret; CHECK_STACK(ret); - if (ret) { - rb_raise(rb_eSysStackError, "stack level too deep"); - } + return ret; } #define MARK_STACK_MAX 1024 @@ -1522,6 +1518,4 @@ Init_GC() rb_global_variable(&finalizers); rb_gc_unregister_address(&rb_mObSpace); finalizers = rb_ary_new(); - - rb_eSysStackError = rb_define_class("SystemStackError", rb_eStandardError); } diff --git a/intern.h b/intern.h index 170fba3e5a..cdd56ba4ef 100644 --- a/intern.h +++ b/intern.h @@ -189,7 +189,7 @@ void rb_file_const _((const char*, VALUE)); int rb_find_file_ext _((VALUE*, const char* const*)); VALUE rb_find_file _((VALUE)); /* gc.c */ -void ruby_stack_check _((void)); +int ruby_stack_check _((void)); int ruby_stack_length _((VALUE**)); void rb_gc_mark_locations _((VALUE*, VALUE*)); void rb_mark_tbl _((struct st_table*)); diff --git a/lib/delegate.rb b/lib/delegate.rb index ecc23d52ea..8dd3395931 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -76,7 +76,7 @@ SimpleDelegater = SimpleDelegator # def DelegateClass(superclass) klass = Class.new - methods = superclass.instance_methods + methods = superclass.instance_methods(true) methods -= ::Kernel.instance_methods methods |= ["to_s","to_a","inspect","==","=~","==="] klass.module_eval <<-EOS diff --git a/parse.y b/parse.y index 6796d87318..1e36ca7441 100644 --- a/parse.y +++ b/parse.y @@ -1104,6 +1104,10 @@ call_args2 : arg ',' args opt_block_arg { $$ = arg_blk_pass(list_concat(NEW_LIST($1),$3), $4); } + | arg ',' block_arg + { + $$ = arg_blk_pass($1, $3); + } | arg ',' tSTAR arg opt_block_arg { value_expr($1); @@ -2044,7 +2048,7 @@ none : /* none */ static char *tokenbuf = NULL; static int tokidx, toksiz = 0; -static NODE *str_extend(); +static NODE *str_extend _((NODE*,char,char)); #define LEAVE_BS 1 @@ -2513,7 +2517,7 @@ parse_regx(term, paren) switch (c) { case '#': - list = str_extend(list, term); + list = str_extend(list, term, paren); if (list == (NODE*)-1) goto unterminated; continue; @@ -2642,7 +2646,7 @@ parse_string(func, term, paren) } } else if (c == '#') { - list = str_extend(list, term); + list = str_extend(list, term, paren); if (list == (NODE*)-1) goto unterm_str; continue; } @@ -3873,15 +3877,16 @@ yylex() } static NODE* -str_extend(list, term) +str_extend(list, term, paren) NODE *list; - char term; + char term, paren; { int c; int brace = -1; VALUE ss; NODE *node; - int nest; + int brace_nest = 0; + int paren_nest = 0; c = nextc(); switch (c) { @@ -3996,13 +4001,13 @@ str_extend(list, term) case '{': if (c == '{') brace = '}'; - nest = 0; + brace_nest = 0; do { loop_again: c = nextc(); switch (c) { case -1: - if (nest > 0) { + if (brace_nest > 0) { yyerror("bad substitution in string"); newtok(); return list; @@ -4010,8 +4015,8 @@ str_extend(list, term) return (NODE*)-1; case '}': if (c == brace) { - if (nest == 0) break; - nest--; + if (brace_nest == 0) break; + brace_nest--; } tokadd(c); goto loop_again; @@ -4027,9 +4032,10 @@ str_extend(list, term) } break; case '{': - if (brace != -1) nest++; + if (brace != -1) brace_nest++; default: - if (c == term) { + if (c == paren) paren_nest++; + else if (c == term && (!paren || paren_nest-- == 0)) { pushback(c); list_append(list, NEW_STR(rb_str_new2("#"))); rb_warn("bad substitution in string"); @@ -4282,7 +4288,7 @@ gettable(id) if (in_single) return NEW_CVAR2(id); return NEW_CVAR(id); } - rb_bug("invalid id for gettable"); + rb_compile_error("identifier %s is not valid", rb_id2name(id)); return 0; } diff --git a/process.c b/process.c index a72f003064..81685d0c1d 100644 --- a/process.c +++ b/process.c @@ -161,7 +161,9 @@ pst_wstopsig(st) { int status = NUM2INT(st); - return INT2NUM(WSTOPSIG(status)); + if (WIFSTOPPED(status)) + return INT2NUM(WSTOPSIG(status)); + return Qnil; } static VALUE @@ -182,7 +184,9 @@ pst_wtermsig(st) { int status = NUM2INT(st); - return INT2NUM(WTERMSIG(status)); + if (WIFSIGNALED(status)) + return INT2NUM(WTERMSIG(status)); + return Qnil; } static VALUE @@ -203,7 +207,9 @@ pst_wexitstatus(st) { int status = NUM2INT(st); - return INT2NUM(WEXITSTATUS(status)); + if (WIFEXITED(status)) + return INT2NUM(WEXITSTATUS(status)); + return Qnil; } static VALUE diff --git a/signal.c b/signal.c index 200330d006..b3b389e3f4 100644 --- a/signal.c +++ b/signal.c @@ -293,7 +293,12 @@ posix_signal(signum, handler) sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; #if defined(SA_RESTART) - sigact.sa_flags |= SA_RESTART; /* SVR4, 4.3+BSD */ + /* All other signals but VTALRM shall restart restartable syscall + VTALRM will cause EINTR to syscall if interrupted. + */ + if (signum != SIGVTALRM) { + sigact.sa_flags |= SA_RESTART; /* SVR4, 4.3+BSD */ + } #endif #ifdef SA_NOCLDWAIT if (signum == SIGCHLD && handler == SIG_IGN) -- cgit v1.2.3