Can not catch PTY::ChildExited exception

Hi guys!

I have problem that I can not catch PTY::ChildExited exception. Here is
the code:

require 'pty'

cmd = "/home3/cman/work/product/integrator/test/syb2/OCS-15_0/bin/isql
-Uuser2 -Puser2 -Scman2"

begin

    pipe_read, pipe_write, pid = PTY.spawn(cmd)

rescue PTY::ChildExited => msg
    puts "Caught child exited exception!"
rescue => msg
    puts "Caught exception!"
end

sleep 10

printf "TEST END\n"

When I run it I have the following:

pty_test.rb:7: pty - exited: 1278 (PTY::ChildExited)

I am wondering why exception is not caught? What is more when I remove
sleep operator then there is no exception at all. Script works and
prints TEST END.

My environment:

ruby 1.8.7 (2008-06-20 patchlevel 22) [x86_64-linux]
Linux 2.6.24-23-server #1 SMP Mon Jan 26 01:36:05 UTC 2009 x86_64
GNU/Linux

What I am doing wrong?

Best regards.
Denis

···

--
Posted via http://www.ruby-forum.com/.

Hi,

···

In message "Re: Can not catch PTY::ChildExited exception" on Wed, 9 Sep 2009 15:14:09 +0900, Denis Berezhnoy <denis.berezhnoy@gmail.com> writes:

I have problem that I can not catch PTY::ChildExited exception. Here is
the code:

The exception was raised when the child process terminated
(asynchronously), so you need to wrap not only spawn but everything.

              matz.

Yukihiro Matsumoto wrote:

Hi,

>I have problem that I can not catch PTY::ChildExited exception. Here is
>the code:

The exception was raised when the child process terminated
(asynchronously), so you need to wrap not only spawn but everything.

              matz.

Hello Matsumoto-san,

Thank you very much for clarifications! I tried to wrap around whole
code with begin rescue block and I can catch ChildExited exception. So
now I have code like this:

require 'pty'

cmd = "/home3/cman/work/product/integrator/test/syb2/OCS-15_0/bin/isql
-Uuser2 -Puser2 -Scman2"

begin

pipe_read, pipe_write, pid = PTY.spawn(cmd)

sleep 10

printf "TEST END\n"

rescue PTY::ChildExited => msg
    puts "Caught child exited exception!"
rescue => msg
    puts "Caught exception!"
rescue => e
    puts e.msg
    puts e.type
end

But now the problem is that ChildExited exception can occur at any
moment after spawn and interrupt program in random place. In my test
above I never get TEST END printed.

How can I handle this in right way?

Best regards,
Denis

···

In message "Re: Can not catch PTY::ChildExited exception" > on Wed, 9 Sep 2009 15:14:09 +0900, Denis Berezhnoy > <denis.berezhnoy@gmail.com> writes:

--
Posted via http://www.ruby-forum.com/\.

Hi,

···

In message "Re: Can not catch PTY::ChildExited exception" on Fri, 11 Sep 2009 09:56:15 +0900, Denis Berezhnoy <denis.berezhnoy@gmail.com> writes:

But now the problem is that ChildExited exception can occur at any
moment after spawn and interrupt program in random place. In my test
above I never get TEST END printed.

How can I handle this in right way?

Define the "right way" first.

I admit asynchronous exception is a bad design choice. pty bundled
with 1.9 has changed to use polling via pty.check method.

              matz.

Well, I'm sure I have nowhere as good an idea of PTY.spawn() as Matsumoto does, but let me try to explain what your code is doing, and how to get your desired result.

First, you might want to consider using other methods for what you're doing. You probably don't really need a pseudo terminal, which is what PTY gives you, and you can use more well documented methods. These two links give a good overview of some of the other ways you can start subprocesses in ruby:
http://devver.net/blog/2009/06/a-dozen-or-so-ways-to-start-sub-processes-in-ruby-part-1/
http://devver.net/blog/2009/07/a-dozen-or-so-ways-to-start-sub-processes-in-ruby-part-2/

If you still think you really need to use a pseudo terminal, then read on.

PTY.spawn() doesn't block your ruby program like a call to system() would. It simply starts the process given the command, and lets you continue. In your first email, you mentioned that when you took out the "sleep 10" line in your code, no exception took place at all. The reason for this is that your script ended before the child did, since the ten seconds of sleep were taken out. And so ruby did not have a chance to raise an exception. Similarly, in your latest code example, "TEST END" was never printed because the
begin block had an exception before you even reached the 'printf "TEST END\n"' line. The exception occurred while
it was in "sleep 10". I hope that's clear, it messed me up too in the past.

To get what you want, you might want to use the block form for PTY.spawn() instead. I just find it cleaner, and using the limited scope for the variables pipe_read etc makes sense. The variables are gone when the pseudo terminal is gone.

What I've done is put a loop inside the PTY.spawn() block, which can be used to handle the output from the subprocess, or feed it input. If you don't need to do that, you probably don't need to use PTY anyways, but you can be the judge of that. Now, this loop stops when the subprocess exits, and then the rest of the ruby script continues.

It seems like you also want to run some code in parallel to the subprocess, but not in the loop I mentioned. For this case, the code below also has a thread. Only when the child exits does the thread stop, and "t.join" finally allows the code to continue. Before "t.join" and after the thread block though, you can run code in parallel to the subprocess. And then, "Test End" is printed after the subprocess has exited. Here's the code:

require 'pty'

cmd = "/home3/cman/work/product/integrator/test/syb2/OCS-15_0/bin/isql -Uuser2 -Puser2 -Scman2"

t = Thread.new do
  begin
    PTY.spawn(cmd) do |pipe_read, pipe_write, pid|
      loop do
        # Code here can handle output given by your command, and feed it input, etc
        # But the infinite loop will be broken by the exception caused when the child process exits, and your script continues
        # Or you could just terminate this loop in advance, but remember, you might reach the end of your ruby script
        # before the child exits, in case that's a problem.
      end
    end
  rescue PTY::ChildExited => msg
    puts "The child has exited"
  rescue => msg
    puts "A different exception:\n" + msg
  end
end

puts "Doing stuff in parallel to the subprocess here"
t.join
puts "Test End"

I hope that was useful/clear. It was certainly too long.

- Ehsan

···

Date: Fri, 11 Sep 2009 09:56:15 +0900
From: denis.berezhnoy@gmail.com
Subject: Re: Can not catch PTY::ChildExited exception
To: ruby-talk@ruby-lang.org

Yukihiro Matsumoto wrote:
> Hi,
>
> In message "Re: Can not catch PTY::ChildExited exception" > > on Wed, 9 Sep 2009 15:14:09 +0900, Denis Berezhnoy > > <denis.berezhnoy@gmail.com> writes:
>
> >I have problem that I can not catch PTY::ChildExited exception. Here is
> >the code:
>
> The exception was raised when the child process terminated
> (asynchronously), so you need to wrap not only spawn but everything.
>
> matz.

Hello Matsumoto-san,

Thank you very much for clarifications! I tried to wrap around whole
code with begin rescue block and I can catch ChildExited exception. So
now I have code like this:

require 'pty'

cmd = "/home3/cman/work/product/integrator/test/syb2/OCS-15_0/bin/isql
-Uuser2 -Puser2 -Scman2"

begin

pipe_read, pipe_write, pid = PTY.spawn(cmd)

sleep 10

printf "TEST END\n"

rescue PTY::ChildExited => msg
    puts "Caught child exited exception!"
rescue => msg
    puts "Caught exception!"
rescue => e
    puts e.msg
    puts e.type
end

But now the problem is that ChildExited exception can occur at any
moment after spawn and interrupt program in random place. In my test
above I never get TEST END printed.

How can I handle this in right way?

Best regards,
Denis
--
Posted via http://www.ruby-forum.com/\.

_________________________________________________________________
With Windows Live, you can organize, edit, and share your photos.
http://www.windowslive.com/Desktop/PhotoGallery

Yukihiro Matsumoto wrote:

Hi,

>But now the problem is that ChildExited exception can occur at any
>moment after spawn and interrupt program in random place. In my test
>above I never get TEST END printed.
>
>How can I handle this in right way?

Define the "right way" first.

I admit asynchronous exception is a bad design choice. pty bundled
with 1.9 has changed to use polling via pty.check method.

              matz.

Hi,

Saying about "right way" I meant that may be there is a standard Ruby
mechanism to handle such async exceptions besides begin rescue
operators. I am newbie in Ruby so I am not sure about its capabilities.

But you answered my question. This is a flaw in design of Ruby PTY
component and we can not avoid interrupting code by child exited
exception.

Anyway thanks for clarification. I will look how I can patch PTY in Ruby
to eliminate generating PTY::ChildExited exception at all.

Best regards,
Denis

···

In message "Re: Can not catch PTY::ChildExited exception" > on Fri, 11 Sep 2009 09:56:15 +0900, Denis Berezhnoy > <denis.berezhnoy@gmail.com> writes:

--
Posted via http://www.ruby-forum.com/\.

Ehsanul Hoque wrote:

Well, I'm sure I have nowhere as good an idea of PTY.spawn() as
Matsumoto does, but let me try to explain what your code is doing, and
how to get your desired result.

First, you might want to consider using other methods for what you're
doing. You probably don't really need a pseudo terminal, which is what
PTY gives you, and you can use more well documented methods.

Hi Ehsan,

Thanks for detailed explanation. The reason why I use PTY is because I
need to interact with application that does not flush its output to
pipe. So when I use IO.popen or IO.pipe there is no output.

PTY.spawn() solves this problem so I use it intentionally.

Best regards,
Denis

···

--
Posted via http://www.ruby-forum.com/\.

Denis Berezhnoy wrote:

Ehsanul Hoque wrote:

Well, I'm sure I have nowhere as good an idea of PTY.spawn() as
Matsumoto does, but let me try to explain what your code is doing, and
how to get your desired result.

First, you might want to consider using other methods for what you're
doing. You probably don't really need a pseudo terminal, which is what
PTY gives you, and you can use more well documented methods.

Hi Ehsan,

Thanks for detailed explanation. The reason why I use PTY is because I
need to interact with application that does not flush its output to
pipe. So when I use IO.popen or IO.pipe there is no output.

PTY.spawn() solves this problem so I use it intentionally.

Best regards,
Denis

Hi Ehsan,

One more question. Can I use Process.wait to wait for termination of
the process which was run by PTY.spawn?

Best regards,
Denis

···

--
Posted via http://www.ruby-forum.com/\.

Denis,

That's a good reason, exactly the same reason I needed to find out so much about PTY in fact.

As for Process.wait, as long as you have the pid, it should work. I tried it out in irb now, and it seems to work. But you will get the child exited exception still. I hadn't thought of this in my explanation, it's definitely a better way to wait for the process to finish compared to my "t.join". Here's what I tried in irb:

def test
a,b,pid = PTY.spawn("sleep 5")
Process.wait(pid)
end
test

···

Date: Fri, 11 Sep 2009 17:12:27 +0900
From: denis.berezhnoy@gmail.com
Subject: Re: Can not catch PTY::ChildExited exception
To: ruby-talk@ruby-lang.org

Denis Berezhnoy wrote:
> Ehsanul Hoque wrote:
>> Well, I'm sure I have nowhere as good an idea of PTY.spawn() as
>> Matsumoto does, but let me try to explain what your code is doing, and
>> how to get your desired result.
>>
>> First, you might want to consider using other methods for what you're
>> doing. You probably don't really need a pseudo terminal, which is what
>> PTY gives you, and you can use more well documented methods.
>
> Hi Ehsan,
>
> Thanks for detailed explanation. The reason why I use PTY is because I
> need to interact with application that does not flush its output to
> pipe. So when I use IO.popen or IO.pipe there is no output.
>
> PTY.spawn() solves this problem so I use it intentionally.
>
> Best regards,
> Denis

Hi Ehsan,

One more question. Can I use Process.wait to wait for termination of
the process which was run by PTY.spawn?

Best regards,
Denis
--
Posted via http://www.ruby-forum.com/\.

_________________________________________________________________
Get back to school stuff for them and cashback for you.
http://www.bing.com/cashback?form=MSHYCB&publ=WLHMTAG&crea=TEXT_MSHYCB_BackToSchool_Cashback_BTSCashback_1x1