From: Brian Candler Date: 2003-05-11T00:50:49+09:00 Subject: Re: RCR for child execution On Sat, May 10, 2003 at 10:26:11PM +0900, Simon Strandgaard wrote: > I have some more to add to this issue. > > > I am embedding ruby into c++ and want to seperate Rubys output from C++. > > AFAIK: When ruby spawns a child-process, then the child inherits > filedescriptor 1 & 2 from parent. > > What im asking for is: is it possible for let the children inherit the > value of rb_stdout, rb_stderr instead ??? From the Unix point of view, the child can be passed any open *Unix* filehandles that you like. For doing this sort of stuff from C, I strongly recommend the book "Advanced Programming in the Unix Environment" by the late Richard Stevens (Addison Wesley). It's a classic must-have reference books for anyone writing Unix programs. In short, you open whatever files/pipes you like, then use the function dup2() to assign them to fd 0/fd 1/fd 2. If you look at the source for 'Open3::popen3' you'll see a way that you can do this from Ruby using IO#reopen. Note that rb_stdout and rb_stderr that you mention are just the constants STDOUT and STDERR in ruby: io.c: rb_define_global_const("STDOUT", rb_stdout); io.c: rb_define_global_const("STDERR", rb_stderr); These objects are wrappers, or containers, which contain the relevant fds, or in fact FILE* objects which are a stdio abstraction which in turn contain the fds. Look at prep_stdio in io.c: prep_stdio(f, mode, klass) FILE *f; { ... MakeOpenFile(io, fp); fp->f = f; fp->mode = mode; ... } rb_stdout = orig_stdout = prep_stdio(stdout, FMODE_WRITABLE, rb_cIO); So whenever you do STDOUT.reopen you are really acting on the stdio object "FILE *stdout" which in turn is a wrapper around an open file on fd 1. Now, if you do system("foo") that's the fd your child will share with the parent process as its stdout. If you do any=%x{foo} then Ruby opens a new pipe and hands one end of it as fd 1 to the child process, and reads the local end into a string. However it doesn't touch fd 2, so the child process shares it. The same applies with IO.popen("foo","r") In the case of Open3.popen3 you get three separate pipes set up, and one end of each of those pipes is dup2()'d into fd0, fd1 and fd2 of the child process before exec'ing. Is this any clearer?? Regards, Brian.