Hi

Yet another problem/bug I'd like to report.

On solaris (Solaris 8 tested) multi-processor systems the pty library
doesn't work properly:
 
| # execute a command which produces some output and sleep for one second 
| # (to avoid triggering the PTY::ChildExited exception)
| so, si, pid = PTY.spawn("hostname; sleep 1") 
| 
| # read some bytes...
| puts so.sysread(1)
| # --> throws EOFError 
| 
| # well.. lets try again, read again (in same process.. )
| puts so.sysread(1)
| # --> able to read the first byte

So, a work-around would be to ignore the first exception, but this can
back-fire if an EOF immediately occurs :/. 

When the process gets bound to a single cpu the above code works as expected. 

| # bind the current process to the first cpu 
| system("pbind -b 0 #{$$}")
| so, si, pid = PTY.spawn("hostname; sleep 1") 
| puts so.sysread(1)
| # --> works

Okay, and there's another error/problem:

This snipped starts and stops many processes. To keep on going I ignore
any PTY::ChildExited Exceptions[1]. As you can see I kill the process
immediately, but usually this would be a normal program termination.

| require 'pty'
| 
| STDOUT.sync = true
| 
| fhs = []
| 
|
| 100.times do |i|
|   begin
|     print "."
|     so, si, pid = PTY.spawn("hostname; sleep 1")
|   
|     sleep 0.1
|     Process.kill("TERM", pid)
|   rescue PTY::ChildExited => e
|     # ignore the exits
|   end
| end

The following thing happens:

.......................pty.rb:10:in `spawn': No such process - can't get Master/Slave device (Errno::ESRCH)
        from pty.rb:10
        from pty.rb:7

After about 20-50 runs ruby complains about not being able to get any
PTY devices. In fact it has eaten up all the remaining pty devices
(solaris seems to limit that, I don't know...) which can even lead to a
system where you can't log in anymore (because the ssh daemon also needs
pty devices). 

Closing the the i/o streams (si & so) manually solves this problem:

| require 'pty'
| 
| STDOUT.sync = true
| 
| fhs = []
| 
| 100.times do |i|
|   si = nil
|   so = nil
|   begin
|     print "."
|     so, si, pid = PTY.spawn("hostname; sleep 1")
|   
|     sleep 0.1
| 
|     Process.kill("TERM", pid)
|   rescue PTY::ChildExited => e
|     # ignore the exits
|   ensure
|     si.close if si; si = nil
|     so.close if so; so = nil
|   end
| end

> $ ruby1.8 pty-close.rb 
> ..................................................................................................
> done

Perhaps this behavior was intended, but at least it should be documented. 


I'm not sure if these errors only occurs on solaris 8, but somehow I doubt
it. I can temporarily provide a Solaris 8 System (SMP) if a developer would
like to work on this problem and doesn't have the hardware.

Regards,
Reto Schuettel

1) These exceptions are so annoying, can't I just ask for the current
status? I.e. RExpect works around this problem by starting another
thread and catching this exception there... but it isn't easy to
implement than when you have to expect an Exception at any time.