summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog32
-rw-r--r--eval.c26
-rw-r--r--ext/pty/extconf.rb3
-rw-r--r--ext/pty/pty.c111
-rw-r--r--gc.c10
-rw-r--r--intern.h2
-rw-r--r--lib/delegate.rb2
-rw-r--r--parse.y32
-rw-r--r--process.c12
-rw-r--r--signal.c7
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 <matz@ruby-lang.org>
+
+ * parse.y (str_extend): should check nesting parentheses in #{}.
+
Wed Nov 21 12:22:52 2001 Shugo Maeda <shugo@ruby-lang.org>
* 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 <matz@ruby-lang.org>
+
+ * 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 <mulperi@iki.fi>
+
+ * 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 <ts@moulon.inra.fr>
+
+ * parse.y (call_args2): block_arg may follow the first argument in
+ call_args2.
+
+Tue Nov 20 02:01:15 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (stack_check): should avoid stack length check during
+ raising SystemStackError exception.
+
Tue Nov 20 01:07:13 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* 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 <sys/ioctl.h>
#endif
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+#ifdef HAVE_PTY_H
+#include <pty.h>
+#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#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)