summaryrefslogtreecommitdiffstats
path: root/ext
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-11-21 18:45:01 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-11-21 18:45:01 +0000
commitb3b2c97e591e16f6cfefd8c613e32315b8b62dc3 (patch)
tree0afa0fb998f6d90b7fb3038b28dcf1b6be425249 /ext
parentdaba387d2d72c49f580d05ee3bdc8d0fd50d73ec (diff)
downloadruby-b3b2c97e591e16f6cfefd8c613e32315b8b62dc3.tar.gz
ruby-b3b2c97e591e16f6cfefd8c613e32315b8b62dc3.tar.xz
ruby-b3b2c97e591e16f6cfefd8c613e32315b8b62dc3.zip
* 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: http://svn.ruby-lang.org/repos/ruby/trunk@20298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext')
-rw-r--r--ext/pty/pty.c117
1 files changed, 46 insertions, 71 deletions
diff --git a/ext/pty/pty.c b/ext/pty/pty.c
index e0d571a58..f0b8e6659 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);