views:

53

answers:

2

So I have a parent and child process, and the parent can read output from the child and send to the input of the child. So far, everything has been working fine with shell scripts, testing commands which input and output data. I just tested with a simple C program and couldn't get it to work. Here's the C program:

#include <stdio.h>

int main( void ) {
  char stuff[80];
  printf("Enter some stuff:\n");
  scanf("%s", stuff);

  return 0;
}

The problem with with the C program is that my select fails to read from the child fd and hence the program cannot finish. Here's the bit that does the select..

//wait till child is ready
fd_set set;
struct timeval timeout;

FD_ZERO( &set ); // initialize fd set
FD_SET( PARENT_READ, &set ); // add child in to set
timeout.tv_sec = 3;
timeout.tv_usec = 0;

int r = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
if( r < 1 ) { // we didn't get any input
    exit(1);
}

Does anyone have any idea why this would happen with the C program and not a shell one?

Thanks!

Edit: I should point out that the child process calls exec on an argument, so I don't have access to it past that point.

+1  A: 

Flush your stdout before blocking from input in the C program.

fflush(stdout);

In shell, this is frequently implicit.

Alternately, you can use setvbuf() to disable buffering (or enable line buffering). This must be called before any data is written:

setvbuf(stdout, NULL, _IONBF, 0)
Charles Duffy
+2  A: 

The problem is that the child process is fully buffering the output because it is writing to a pipe and not a terminal. Use setvbuf to force line buffering or unbuffered mode, or add an explicit fflush to the child after then printf, or use the unbuffer program that comes with Expect to trick the child process's libc into thinking the program is working interactively.

Donal Fellows
Good call re `setvbuf`; hope you don't mind my incorporating the suggestion.
Charles Duffy
@Charles: There was a period about 5 years ago or so when this was a standard question among newcomers to the Tcl community ("why does my subprocess not work?!") and my answer above is the basic distillation of what we told them. (Well, using full Expect is the real solution we preferred back then but that's not going to fly as an answer for this Q.)
Donal Fellows
The child process is using exec, so fflush() isn't really an option. I tried to use setvbuf(stdout,(char*)NULL,_IONBF,0); on the child before exec but that didn't seem to work. Do you have any idea why?
Gary
Those have to be *inside* the child process's implementation, typically at the start of `main`. If that's not possible in practice (e.g., because you don't have access to the source or otherwise can't change it) then you **need** the unbuffer I mentioned which does ungodly things with the /dev/pty system to trick the "real" subprocess.
Donal Fellows
@Gary: BTW, you really don't want to write your own /dev/pty handler code if possible. Use someone else's.
Donal Fellows
i get it, thanks a bunch :)
Gary