Hi,

At Thu, 20 Jul 2006 00:20:28 +0900,
Reto Schuettel wrote in [ruby-core:08282]:
> 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 :/. 

Maybe concerned with the timing.  Why do you use sysread?  Does
read_partial also return nil first?

> 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.
(snip)
> 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). 

It'd be better to retry after GC.


Index: ext/pty/pty.c =================================================================== RCS file: /cvs/ruby/src/ruby/ext/pty/pty.c,v retrieving revision 1.26 diff -p -u -2 -r1.26 pty.c --- ext/pty/pty.c 20 Jun 2006 18:02:14 -0000 1.26 +++ ext/pty/pty.c 20 Jul 2006 00:46:20 -0000 @@ -296,25 +296,24 @@ pty_finalize_syswait(struct pty_info *in } -#ifdef HAVE_OPENPTY +static int +get_device_once(int *master, int *slave, int fail) +{ +#if defined HAVE_OPENPTY /* * Use openpty(3) of 4.3BSD Reno and later, * or the same interface function. */ -static void -getDevice(int *master, int *slave) -{ if (openpty(master, slave, SlaveName, (struct termios *)0, (struct winsize *)0) == -1) { + if (!fail) return -1; rb_raise(rb_eRuntimeError, "openpty() failed"); } -} -#else /* HAVE_OPENPTY */ -#ifdef HAVE__GETPTY -static void -getDevice(int *master, int *slave) -{ + + return 0; +#elif defined HAVE__GETPTY char *name; if (!(name = _getpty(master, O_RDWR, 0622, 0))) { + if (!fail) return -1; rb_raise(rb_eRuntimeError, "_getpty() failed"); } @@ -322,9 +321,7 @@ getDevice(int *master, int *slave) *slave = open(name, O_RDWR); strcpy(SlaveName, name); -} + + return 0; #else /* HAVE__GETPTY */ -static void -getDevice(int *master, int *slave) -{ int i,j; @@ -351,5 +348,5 @@ getDevice(int *master, int *slave) *slave = j; strcpy(SlaveName, pn); - return; + return 0; #if defined I_PUSH && !defined linux } @@ -362,5 +359,6 @@ getDevice(int *master, int *slave) close(i); } - rb_raise(rb_eRuntimeError, "can't get Master/Slave device"); + if (!fail) rb_raise(rb_eRuntimeError, "can't get Master/Slave device"); + return -1; #else char **p; @@ -376,14 +374,23 @@ getDevice(int *master, int *slave) chown(SlaveName, getuid(), getgid()); chmod(SlaveName, 0622); - return; + return 0; } close(i); } } - rb_raise(rb_eRuntimeError, "can't get %s", SlaveName); + if (fail) rb_raise(rb_eRuntimeError, "can't get %s", SlaveName); + return -1; #endif +#endif +} + +static void +getDevice(int *master, int *slave) +{ + if (get_device_once(master, slave, 0)) { + rb_gc(); + get_device_once(master, slave, 1); + } } -#endif /* HAVE__GETPTY */ -#endif /* HAVE_OPENPTY */ static void
-- Nobu Nakada