summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--ext/pty/pty.c117
2 files changed, 56 insertions, 71 deletions
diff --git a/ChangeLog b/ChangeLog
index 003e52a00e..53614962aa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
* ext/curses/curses.c (curses_escdelay_set): support ESCDELAY. a
diff --git a/ext/pty/pty.c b/ext/pty/pty.c
index e0d571a581..f0b8e66595 100644
--- a/ext/pty/pty.c
+++ b/ext/pty/pty.c
@@ -127,51 +127,8 @@ echild_status(VALUE self)
struct pty_info {
int fd;
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]);
struct exec_info {
@@ -217,7 +174,6 @@ establishShell(int argc, VALUE *argv, struct pty_info *info,
}
getDevice(&master, &slave, SlaveName);
- info->thread = rb_thread_current();
if ((pid = fork()) < 0) {
close(master);
close(slave);
@@ -288,15 +244,6 @@ establishShell(int argc, VALUE *argv, struct pty_info *info,
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
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 */
static VALUE
pty_getpty(int argc, VALUE *argv, VALUE self)
{
VALUE res;
struct pty_info info;
- struct pty_info thinfo;
rb_io_t *wfptr,*rfptr;
VALUE rport = 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,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()) {
- rb_ensure(rb_yield, res, pty_finalize_syswait, (VALUE)&thinfo);
+ rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info);
return Qnil;
}
return res;
}
-/* ruby function: protect_signal - obsolete */
-static VALUE
-pty_protect(VALUE self)
+static void
+raise_from_check(pid_t pid, int status)
{
- rb_warn("PTY::protect_signal is no longer needed");
- rb_yield(Qnil);
- return self;
+ const char *state;
+ char buf[1024];
+ 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
-pty_reset_signal(VALUE self)
+pty_check(int argc, VALUE *argv, VALUE self)
{
- rb_warn("PTY::reset_signal is no longer needed");
- return self;
+ VALUE pid, exc;
+ 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;
@@ -462,8 +438,7 @@ Init_pty()
cPTY = rb_define_module("PTY");
rb_define_module_function(cPTY,"getpty",pty_getpty,-1);
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);
+ rb_define_singleton_function(cPTY,"check",pty_check,-1);
eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError);
rb_define_method(eChildExited,"status",echild_status,0);