* ext/pty/pty.c (get_device_once): abandon asynchronous exception

that might cause serious problem if a program terminated early.
  asynchronous exception is a very bad thing anyway.  use
  Process.waitpid(pid) or PTY.check(pid) to poll program
  termination. if PTY.check is called with optional second
  argument being true, it raises an exception same as one from
  previous behavior.  [incompatible] fix: [ruby-core:19583]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2008-11-21 18:45:01 +00:00
Родитель 5640227231
Коммит 1e1d2b2639
2 изменённых файлов: 56 добавлений и 71 удалений

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

@ -1,3 +1,13 @@
Sat Nov 22 03:41:22 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* ext/pty/pty.c (get_device_once): abandon asynchronous exception
that might cause serious problem if a program terminated early.
asynchronous exception is a very bad thing anyway. use
Process.waitpid(pid) or PTY.check(pid) to poll program
termination. if PTY.check is called with optional second
argument being true, it raises an exception same as one from
previous behavior. [incompatible] fix: [ruby-core:19583]
Fri Nov 21 22:24:31 2008 Yukihiro Matsumoto <matz@ruby-lang.org> Fri Nov 21 22:24:31 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* ext/curses/curses.c (curses_escdelay_set): support ESCDELAY. a * ext/curses/curses.c (curses_escdelay_set): support ESCDELAY. a

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

@ -127,51 +127,8 @@ echild_status(VALUE self)
struct pty_info { struct pty_info {
int fd; int fd;
rb_pid_t child_pid; rb_pid_t child_pid;
VALUE thread;
}; };
static void
raise_from_wait(const char *state, const struct pty_info *info)
{
char buf[1024];
VALUE exc;
snprintf(buf, sizeof(buf), "pty - %s: %ld", state, (long)info->child_pid);
exc = rb_exc_new2(eChildExited, buf);
rb_iv_set(exc, "status", rb_last_status_get());
rb_funcall(info->thread, rb_intern("raise"), 1, exc);
}
static VALUE
pty_syswait(void *arg)
{
const struct pty_info *const info = arg;
rb_pid_t cpid;
int status;
for (;;) {
cpid = rb_waitpid(info->child_pid, &status, WUNTRACED);
if (cpid == -1) return Qnil;
#if defined(WIFSTOPPED)
#elif defined(IF_STOPPED)
#define WIFSTOPPED(status) IF_STOPPED(status)
#else
---->> Either IF_STOPPED or WIFSTOPPED is needed <<----
#endif /* WIFSTOPPED | IF_STOPPED */
if (WIFSTOPPED(status)) { /* suspend */
raise_from_wait("stopped", info);
}
else if (kill(info->child_pid, 0) == 0) {
raise_from_wait("changed", info);
}
else {
raise_from_wait("exited", info);
return Qnil;
}
}
}
static void getDevice(int*, int*, char [DEVICELEN]); static void getDevice(int*, int*, char [DEVICELEN]);
struct exec_info { struct exec_info {
@ -217,7 +174,6 @@ establishShell(int argc, VALUE *argv, struct pty_info *info,
} }
getDevice(&master, &slave, SlaveName); getDevice(&master, &slave, SlaveName);
info->thread = rb_thread_current();
if ((pid = fork()) < 0) { if ((pid = fork()) < 0) {
close(master); close(master);
close(slave); close(slave);
@ -288,15 +244,6 @@ establishShell(int argc, VALUE *argv, struct pty_info *info,
info->fd = master; info->fd = master;
} }
static VALUE
pty_finalize_syswait(struct pty_info *info)
{
rb_thread_kill(info->thread);
rb_funcall(info->thread, rb_intern("value"), 0);
rb_detach_process(info->child_pid);
return Qnil;
}
static int static int
get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int fail) get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int fail)
{ {
@ -396,13 +343,19 @@ getDevice(int *master, int *slave, char SlaveName[DEVICELEN])
} }
} }
static VALUE
pty_detach_process(struct pty_info *info)
{
rb_detach_process(info->child_pid);
return Qnil;
}
/* ruby function: getpty */ /* ruby function: getpty */
static VALUE static VALUE
pty_getpty(int argc, VALUE *argv, VALUE self) pty_getpty(int argc, VALUE *argv, VALUE self)
{ {
VALUE res; VALUE res;
struct pty_info info; struct pty_info info;
struct pty_info thinfo;
rb_io_t *wfptr,*rfptr; rb_io_t *wfptr,*rfptr;
VALUE rport = rb_obj_alloc(rb_cFile); VALUE rport = rb_obj_alloc(rb_cFile);
VALUE wport = rb_obj_alloc(rb_cFile); VALUE wport = rb_obj_alloc(rb_cFile);
@ -426,32 +379,55 @@ pty_getpty(int argc, VALUE *argv, VALUE self)
rb_ary_store(res,1,(VALUE)wport); rb_ary_store(res,1,(VALUE)wport);
rb_ary_store(res,2,PIDT2NUM(info.child_pid)); rb_ary_store(res,2,PIDT2NUM(info.child_pid));
thinfo.thread = rb_thread_create(pty_syswait, (void*)&info);
thinfo.child_pid = info.child_pid;
rb_thread_schedule();
if (rb_block_given_p()) { if (rb_block_given_p()) {
rb_ensure(rb_yield, res, pty_finalize_syswait, (VALUE)&thinfo); rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info);
return Qnil; return Qnil;
} }
return res; return res;
} }
/* ruby function: protect_signal - obsolete */ static void
static VALUE raise_from_check(pid_t pid, int status)
pty_protect(VALUE self)
{ {
rb_warn("PTY::protect_signal is no longer needed"); const char *state;
rb_yield(Qnil); char buf[1024];
return self; VALUE exc;
#if defined(WIFSTOPPED)
#elif defined(IF_STOPPED)
#define WIFSTOPPED(status) IF_STOPPED(status)
#else
---->> Either IF_STOPPED or WIFSTOPPED is needed <<----
#endif /* WIFSTOPPED | IF_STOPPED */
if (WIFSTOPPED(status)) { /* suspend */
state = "stopped";
}
else if (kill(pid, 0) == 0) {
state = "changed";
}
else {
state = "exited";
}
snprintf(buf, sizeof(buf), "pty - %s: %ld", state, (long)pid);
exc = rb_exc_new2(eChildExited, buf);
rb_iv_set(exc, "status", rb_last_status_get());
rb_exc_raise(exc);
} }
/* ruby function: reset_signal - obsolete */
static VALUE static VALUE
pty_reset_signal(VALUE self) pty_check(int argc, VALUE *argv, VALUE self)
{ {
rb_warn("PTY::reset_signal is no longer needed"); VALUE pid, exc;
return self; pid_t cpid;
int status;
rb_scan_args(argc, argv, "11", &pid, &exc);
cpid = rb_waitpid(NUM2PIDT(pid), &status, WUNTRACED);
if (cpid == -1) return Qnil;
if (!RTEST(exc)) return status;
raise_from_check(pid, status);
return Qnil; /* not reached */
} }
static VALUE cPTY; static VALUE cPTY;
@ -462,8 +438,7 @@ Init_pty()
cPTY = rb_define_module("PTY"); cPTY = rb_define_module("PTY");
rb_define_module_function(cPTY,"getpty",pty_getpty,-1); rb_define_module_function(cPTY,"getpty",pty_getpty,-1);
rb_define_module_function(cPTY,"spawn",pty_getpty,-1); rb_define_module_function(cPTY,"spawn",pty_getpty,-1);
rb_define_module_function(cPTY,"protect_signal",pty_protect,0); rb_define_singleton_function(cPTY,"check",pty_check,-1);
rb_define_module_function(cPTY,"reset_signal",pty_reset_signal,0);
eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError); eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError);
rb_define_method(eChildExited,"status",echild_status,0); rb_define_method(eChildExited,"status",echild_status,0);