* 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
This commit is contained in:
matz 2001-11-21 15:42:12 +00:00
Родитель e15f65b004
Коммит f1fdbf080e
10 изменённых файлов: 181 добавлений и 56 удалений

Просмотреть файл

@ -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

26
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:

Просмотреть файл

@ -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")

Просмотреть файл

@ -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);
}

10
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);
}

Просмотреть файл

@ -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*));

Просмотреть файл

@ -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

32
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;
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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)