From 9d77639f30172b0e3b88ea22df0724df61240161 Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 7 Mar 2003 05:59:42 +0000 Subject: * parse.y (dsym): :"symbol string" style should not contain `\0'. * process.c (proc_detach): new method Proc#detach(pid) which create background watcher thread to issue waitpid. [new] * process.c (rb_detach_process): utility function to detach process from C code. * ext/pty/pty.c (pty_finalize_syswait): terminate watcher thread, and detach child process (by creating new idle waitpid watcher thread). * ext/pty/pty.c (pty_syswait): may lost signal stopped child. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3561 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/pty/README | 40 ++++----------------------- ext/pty/pty.c | 83 +++++++++++++++++++++++++------------------------------ ext/pty/script.rb | 3 +- 3 files changed, 45 insertions(+), 81 deletions(-) (limited to 'ext/pty') diff --git a/ext/pty/README b/ext/pty/README index a09469d39c..42c7d4f891 100644 --- a/ext/pty/README +++ b/ext/pty/README @@ -33,43 +33,15 @@ following module fungtions: the array is passed to the block as block parameters, and the function itself returns nil. - While the process spawned by this function is active, SIGCHLD - is captured to handle the change of the child process. When the - child process is suspended or finished, an exception is raised. - As all SIGCHLD signal is captured and processed by PTY module, - you can't use other function or method which spawns subprosesses - (including signal() and IO.popen()) while the PTY subprocesses - are active. Otherwise, unexpected exception will occur. To avoid - this problem, see protect_signal() below. - - If this function is called with an iterator block, SIGCHLD signal - is captured only within the block. Therefore, it is risky to use - File objects for PTY subprocess outside the iterator block. - + When the child process is suspended or finished, an exception is + raised. If this function is called with an iterator block, + exception is raised only within the block. Child process + monitor is terminated on block exit. protect_signal + reset_signal - This function takes an iterator block. Within the iterator block, - no exception is raised even if any subprocess is terminated. - This function is used to enable functions like system() or IO.popen() - while PTY subprocess is active. For example, - - PTY.spawn("command_foo") do |r,w| - ... - ... - PTY.protect_signal do - system "some other commands" - end - ... - end - - disables to send exception when "some other commands" is - terminated. - - reset_signal - - Disables to handle SIGCHLD while PTY subprocess is active. - + These functions are obsolete in this version of pty. 4. License diff --git a/ext/pty/pty.c b/ext/pty/pty.c index b7c69fe400..f1d4f73a18 100644 --- a/ext/pty/pty.c +++ b/ext/pty/pty.c @@ -133,44 +133,50 @@ struct pty_info { VALUE thread; }; +static void +raise_from_wait(state, info) + struct pty_info *info; + char *state; +{ + extern VALUE rb_last_status; + char buf[1024]; + VALUE exc; + + snprintf(buf, sizeof(buf), "pty - %s: %d", state, info->child_pid); + exc = rb_exc_new2(eChildExited, buf); + rb_iv_set(exc, "status", rb_last_status); + rb_funcall(info->thread, rb_intern("raise"), 1, exc); +} + 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); - st = rb_last_status; - - if (cpid == 0 || cpid == -1) - return Qnil; + for (;;) { + cpid = rb_waitpid(info->child_pid, &status, WUNTRACED); + if (cpid == -1) return Qnil; -#ifdef IF_STOPPED - if (IF_STOPPED(status)) { /* suspend */ - state = "stopped"; - } -#else -#ifdef WIFSTOPPED - if (WIFSTOPPED(status)) { /* suspend */ - state = "stopped"; - } +#if defined(IF_STOPPED) + if (IF_STOPPED(status)) { /* suspend */ + raise_from_wait("stopped", info); + } +#elif defined(WIFSTOPPED) + if (WIFSTOPPED(status)) { /* suspend */ + raise_from_wait("stopped", info); + } #else ---->> Either IF_STOPPED or WIFSTOPPED is needed <<---- -#endif /* WIFSTOPPED */ -#endif /* IF_STOPPED */ - if (WIFEXITED(status)) { - state = "exit"; +#endif /* WIFSTOPPED | IF_STOPPED */ + else if (kill(info->child_pid, 0) == 0) { + raise_from_wait("changed", info); + } + else { + raise_from_wait("exited", info); + return Qnil; + } } - - 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*)); @@ -290,27 +296,14 @@ establishShell(argc, argv, info) } static VALUE -pty_kill_child(info) +pty_finalize_syswait(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); + rb_thread_kill(info->thread); + rb_detach_process(info->child_pid); return Qnil; } - #ifdef HAVE_OPENPTY /* * Use openpty(3) of 4.3BSD Reno and later, @@ -447,7 +440,7 @@ pty_getpty(argc, argv, self) thinfo.child_pid = info.child_pid; if (rb_block_given_p()) { - rb_ensure(rb_yield, res, pty_kill_child, (VALUE)&thinfo); + rb_ensure(rb_yield, res, pty_finalize_syswait, (VALUE)&thinfo); return Qnil; } return res; diff --git a/ext/pty/script.rb b/ext/pty/script.rb index 3084935637..dbb933171f 100644 --- a/ext/pty/script.rb +++ b/ext/pty/script.rb @@ -10,8 +10,7 @@ logfile = File.open(ofile,"a") system "stty -echo raw lnext ^_" -PTY.spawn("/bin/csh") do - |r_pty,w_pty,pid| +PTY.spawn("/bin/csh") do |r_pty,w_pty,pid| Thread.new do while true -- cgit v1.2.3