From: Reto Schuettel Date: 2006-07-20T00:20:28+09:00 Subject: PTY on Solaris multi-processor systems 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.