Note that there are some explanatory texts on larger screens.

plurals
  1. PODisabling stdout buffering of a forked process
    text
    copied!<p>I wrote a code in C/C++ which forks a child process, duplicates the stdin/stdout into a pipe ends and calls execvp.</p> <p>Everything is working fine (i.e. the output from stdin/err/out is captured by the parent process)</p> <p>The problem is that the child stdout is buffered.</p> <p>so if the child code looks like this:</p> <pre><code>printf("Enter any key and hit ENTER:\n"); fgets(line); printf("read: %s\n", line); exit(0); </code></pre> <p>In the parent process I don't see the line 'Enter any key:' - it will be "flushed" only after the program calls exit (which auto flushes the stdout buffer) or an explicit call to 'flush(stdout)' is added</p> <p>I did some research and tried adding a call to disable the stdout buffering by adding a call to:</p> <p>setvbuf(stdout, NULL, _IONBF, 0); just before calling execvp(...) in the parent process</p> <p>so the relevant code looks now like this:</p> <pre><code>int rc = fork(); if ( rc == 0 ) { // Child process if(workingDirectory.IsEmpty() == false) { wxSetWorkingDirectory( workingDirectory ); } int stdin_file = fileno( stdin ); int stdout_file = fileno( stdout ); int stderr_file = fileno( stderr ); // Replace stdin/out with our pipe ends dup2 ( stdin_pipe_read, stdin_file ); close( stdin_pipe_write ); dup2 ( stdout_pipe_write, stdout_file); dup2 ( stdout_pipe_write, stderr_file); close( stdout_pipe_read ); setvbuf(stdout, NULL, _IONBF, 0); // execute the process execvp(argv[0], argv); exit(0); } </code></pre> <p>With no luck.</p> <p>Any ideas?</p> <p>EDIT:</p> <p>here is a sample of the parent code, the only thing needs changing is the path to the child executable:</p> <pre><code>#include &lt;unistd.h&gt; #include &lt;signal.h&gt; #include &lt;sys/types.h&gt; #include &lt;sys/select.h&gt; #include &lt;errno.h&gt; #include &lt;sys/wait.h&gt; #include &lt;string&gt; #include &lt;string.h&gt; #include &lt;cstdio&gt; static int read_handle(-1); static pid_t pid; bool read_from_child(std::string&amp; buff) { fd_set rs; timeval timeout; memset(&amp;rs, 0, sizeof(rs)); FD_SET(read_handle, &amp;rs); timeout.tv_sec = 1; // 1 second timeout.tv_usec = 0; int rc = select(read_handle+1, &amp;rs, NULL, NULL, &amp;timeout); if ( rc == 0 ) { // timeout return true; } else if ( rc &gt; 0 ) { // there is something to read char buffer[1024*64]; // our read buffer memset(buffer, 0, sizeof(buffer)); if(read(read_handle, buffer, sizeof(buffer)) &gt; 0) { buff.clear(); buff.append( buffer ); return true; } return false; } else { /* == 0 */ if ( rc == EINTR || rc == EAGAIN ) { return true; } // Process terminated int status(0); waitpid(pid, &amp;status, 0); return false; } } void execute() { char *argv[] = {"/home/eran/devl/TestMain/Debug/TestMain", NULL}; int argc = 1; int filedes[2]; int filedes2[2]; // create a pipe int d; d = pipe(filedes); d = pipe(filedes2); int stdin_pipe_write = filedes[1]; int stdin_pipe_read = filedes[0]; int stdout_pipe_write = filedes2[1]; int stdout_pipe_read = filedes2[0]; int rc = fork(); if ( rc == 0 ) { // Child process int stdin_file = fileno( stdin ); int stdout_file = fileno( stdout ); int stderr_file = fileno( stderr ); // Replace stdin/out with our pipe ends dup2 ( stdin_pipe_read, stdin_file ); close( stdin_pipe_write ); dup2 ( stdout_pipe_write, stdout_file); dup2 ( stdout_pipe_write, stderr_file); close( stdout_pipe_read ); setvbuf(stdout, NULL, _IONBF, 0); // execute the process execvp(argv[0], argv); } else if ( rc &lt; 0 ) { perror("fork"); return; } else { // Parent std::string buf; read_handle = stdout_pipe_read; while(read_from_child(buf)) { if(buf.empty() == false) { printf("Received: %s\n", buf.c_str()); } buf.clear(); } } } int main(int argc, char **argv) { execute(); return 0; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload